mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 05:02:12 +00:00
f1712c7371
Zhang Yanmin reported crashes [1] and provided a patch adding a synchronize_rcu() call in can_rx_unregister() The main problem seems that the sockets themselves are not RCU protected. If CAN uses RCU for delivery, then sockets should be freed only after one RCU grace period. Recent kernels could use sock_set_flag(sk, SOCK_RCU_FREE), but let's ease stable backports with the following fix instead. [1] BUG: unable to handle kernel NULL pointer dereference at (null) IP: [<ffffffff81495e25>] selinux_socket_sock_rcv_skb+0x65/0x2a0 Call Trace: <IRQ> [<ffffffff81485d8c>] security_sock_rcv_skb+0x4c/0x60 [<ffffffff81d55771>] sk_filter+0x41/0x210 [<ffffffff81d12913>] sock_queue_rcv_skb+0x53/0x3a0 [<ffffffff81f0a2b3>] raw_rcv+0x2a3/0x3c0 [<ffffffff81f06eab>] can_rcv_filter+0x12b/0x370 [<ffffffff81f07af9>] can_receive+0xd9/0x120 [<ffffffff81f07beb>] can_rcv+0xab/0x100 [<ffffffff81d362ac>] __netif_receive_skb_core+0xd8c/0x11f0 [<ffffffff81d36734>] __netif_receive_skb+0x24/0xb0 [<ffffffff81d37f67>] process_backlog+0x127/0x280 [<ffffffff81d36f7b>] net_rx_action+0x33b/0x4f0 [<ffffffff810c88d4>] __do_softirq+0x184/0x440 [<ffffffff81f9e86c>] do_softirq_own_stack+0x1c/0x30 <EOI> [<ffffffff810c76fb>] do_softirq.part.18+0x3b/0x40 [<ffffffff810c8bed>] do_softirq+0x1d/0x20 [<ffffffff81d30085>] netif_rx_ni+0xe5/0x110 [<ffffffff8199cc87>] slcan_receive_buf+0x507/0x520 [<ffffffff8167ef7c>] flush_to_ldisc+0x21c/0x230 [<ffffffff810e3baf>] process_one_work+0x24f/0x670 [<ffffffff810e44ed>] worker_thread+0x9d/0x6f0 [<ffffffff810e4450>] ? rescuer_thread+0x480/0x480 [<ffffffff810ebafc>] kthread+0x12c/0x150 [<ffffffff81f9ccef>] ret_from_fork+0x3f/0x70 Reported-by: Zhang Yanmin <yanmin.zhang@intel.com> Signed-off-by: Eric Dumazet <edumazet@google.com> Acked-by: Oliver Hartkopp <socketcan@hartkopp.net> Signed-off-by: David S. Miller <davem@davemloft.net>
128 lines
4.2 KiB
C
128 lines
4.2 KiB
C
/*
|
|
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of Volkswagen nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* Alternatively, provided that this notice is retained in full, this
|
|
* software may be distributed under the terms of the GNU General
|
|
* Public License ("GPL") version 2, in which case the provisions of the
|
|
* GPL apply INSTEAD OF those given above.
|
|
*
|
|
* The provided data structures and external interfaces from this code
|
|
* are not restricted to be used by modules with a GPL compatible license.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
* DAMAGE.
|
|
*
|
|
*/
|
|
|
|
#ifndef AF_CAN_H
|
|
#define AF_CAN_H
|
|
|
|
#include <linux/skbuff.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/list.h>
|
|
#include <linux/rcupdate.h>
|
|
#include <linux/can.h>
|
|
|
|
/* af_can rx dispatcher structures */
|
|
|
|
struct receiver {
|
|
struct hlist_node list;
|
|
canid_t can_id;
|
|
canid_t mask;
|
|
unsigned long matches;
|
|
void (*func)(struct sk_buff *, void *);
|
|
void *data;
|
|
char *ident;
|
|
struct sock *sk;
|
|
struct rcu_head rcu;
|
|
};
|
|
|
|
#define CAN_SFF_RCV_ARRAY_SZ (1 << CAN_SFF_ID_BITS)
|
|
#define CAN_EFF_RCV_HASH_BITS 10
|
|
#define CAN_EFF_RCV_ARRAY_SZ (1 << CAN_EFF_RCV_HASH_BITS)
|
|
|
|
enum { RX_ERR, RX_ALL, RX_FIL, RX_INV, RX_MAX };
|
|
|
|
/* per device receive filters linked at dev->ml_priv */
|
|
struct dev_rcv_lists {
|
|
struct hlist_head rx[RX_MAX];
|
|
struct hlist_head rx_sff[CAN_SFF_RCV_ARRAY_SZ];
|
|
struct hlist_head rx_eff[CAN_EFF_RCV_ARRAY_SZ];
|
|
int remove_on_zero_entries;
|
|
int entries;
|
|
};
|
|
|
|
/* statistic structures */
|
|
|
|
/* can be reset e.g. by can_init_stats() */
|
|
struct s_stats {
|
|
unsigned long jiffies_init;
|
|
|
|
unsigned long rx_frames;
|
|
unsigned long tx_frames;
|
|
unsigned long matches;
|
|
|
|
unsigned long total_rx_rate;
|
|
unsigned long total_tx_rate;
|
|
unsigned long total_rx_match_ratio;
|
|
|
|
unsigned long current_rx_rate;
|
|
unsigned long current_tx_rate;
|
|
unsigned long current_rx_match_ratio;
|
|
|
|
unsigned long max_rx_rate;
|
|
unsigned long max_tx_rate;
|
|
unsigned long max_rx_match_ratio;
|
|
|
|
unsigned long rx_frames_delta;
|
|
unsigned long tx_frames_delta;
|
|
unsigned long matches_delta;
|
|
};
|
|
|
|
/* persistent statistics */
|
|
struct s_pstats {
|
|
unsigned long stats_reset;
|
|
unsigned long user_reset;
|
|
unsigned long rcv_entries;
|
|
unsigned long rcv_entries_max;
|
|
};
|
|
|
|
/* receive filters subscribed for 'all' CAN devices */
|
|
extern struct dev_rcv_lists can_rx_alldev_list;
|
|
|
|
/* function prototypes for the CAN networklayer procfs (proc.c) */
|
|
void can_init_proc(void);
|
|
void can_remove_proc(void);
|
|
void can_stat_update(unsigned long data);
|
|
|
|
/* structures and variables from af_can.c needed in proc.c for reading */
|
|
extern struct timer_list can_stattimer; /* timer for statistics update */
|
|
extern struct s_stats can_stats; /* packet statistics */
|
|
extern struct s_pstats can_pstats; /* receive list statistics */
|
|
extern struct hlist_head can_rx_dev_list; /* rx dispatcher structures */
|
|
|
|
#endif /* AF_CAN_H */
|