projects
/
platform
/
kernel
/
linux-rpi.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
can: af_can: fix NULL pointer dereference in can_rx_register()
[platform/kernel/linux-rpi.git]
/
net
/
can
/
bcm.c
diff --git
a/net/can/bcm.c
b/net/can/bcm.c
index
508f67d
..
aab3a18
100644
(file)
--- a/
net/can/bcm.c
+++ b/
net/can/bcm.c
@@
-100,6
+100,7
@@
static inline u64 get_u64(const struct canfd_frame *cp, int offset)
struct bcm_op {
struct list_head list;
struct bcm_op {
struct list_head list;
+ struct rcu_head rcu;
int ifindex;
canid_t can_id;
u32 flags;
int ifindex;
canid_t can_id;
u32 flags;
@@
-273,6
+274,7
@@
static void bcm_can_tx(struct bcm_op *op)
struct sk_buff *skb;
struct net_device *dev;
struct canfd_frame *cf = op->frames + op->cfsiz * op->currframe;
struct sk_buff *skb;
struct net_device *dev;
struct canfd_frame *cf = op->frames + op->cfsiz * op->currframe;
+ int err;
/* no target device? => exit */
if (!op->ifindex)
/* no target device? => exit */
if (!op->ifindex)
@@
-297,11
+299,11
@@
static void bcm_can_tx(struct bcm_op *op)
/* send with loopback */
skb->dev = dev;
can_skb_set_owner(skb, op->sk);
/* send with loopback */
skb->dev = dev;
can_skb_set_owner(skb, op->sk);
- can_send(skb, 1);
+ err = can_send(skb, 1);
+ if (!err)
+ op->frames_abs++;
- /* update statistics */
op->currframe++;
op->currframe++;
- op->frames_abs++;
/* reached last frame? */
if (op->currframe >= op->nframes)
/* reached last frame? */
if (op->currframe >= op->nframes)
@@
-718,10
+720,9
@@
static struct bcm_op *bcm_find_op(struct list_head *ops,
return NULL;
}
return NULL;
}
-static void bcm_
remove_op(struct bcm_op *op
)
+static void bcm_
free_op_rcu(struct rcu_head *rcu_head
)
{
{
- hrtimer_cancel(&op->timer);
- hrtimer_cancel(&op->thrtimer);
+ struct bcm_op *op = container_of(rcu_head, struct bcm_op, rcu);
if ((op->frames) && (op->frames != &op->sframe))
kfree(op->frames);
if ((op->frames) && (op->frames != &op->sframe))
kfree(op->frames);
@@
-732,6
+733,14
@@
static void bcm_remove_op(struct bcm_op *op)
kfree(op);
}
kfree(op);
}
+static void bcm_remove_op(struct bcm_op *op)
+{
+ hrtimer_cancel(&op->timer);
+ hrtimer_cancel(&op->thrtimer);
+
+ call_rcu(&op->rcu, bcm_free_op_rcu);
+}
+
static void bcm_rx_unreg(struct net_device *dev, struct bcm_op *op)
{
if (op->rx_reg_dev == dev) {
static void bcm_rx_unreg(struct net_device *dev, struct bcm_op *op)
{
if (op->rx_reg_dev == dev) {
@@
-757,6
+766,9
@@
static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
if ((op->can_id == mh->can_id) && (op->ifindex == ifindex) &&
(op->flags & CAN_FD_FRAME) == (mh->flags & CAN_FD_FRAME)) {
if ((op->can_id == mh->can_id) && (op->ifindex == ifindex) &&
(op->flags & CAN_FD_FRAME) == (mh->flags & CAN_FD_FRAME)) {
+ /* disable automatic timer on frame reception */
+ op->flags |= RX_NO_AUTOTIMER;
+
/*
* Don't care if we're bound or not (due to netdev
* problems) can_rx_unregister() is always a save
/*
* Don't care if we're bound or not (due to netdev
* problems) can_rx_unregister() is always a save
@@
-785,7
+797,6
@@
static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
bcm_rx_handler, op);
list_del(&op->list);
bcm_rx_handler, op);
list_del(&op->list);
- synchronize_rcu();
bcm_remove_op(op);
return 1; /* done */
}
bcm_remove_op(op);
return 1; /* done */
}