Skip to content

Commit

Permalink
can: add sanity checks
Browse files Browse the repository at this point in the history
Even though the CAN netlayer only deals with CAN netdevices, the 
netlayer interface to the userspace and to the device layer should 
perform some sanity checks.

This patch adds several sanity checks that mainly prevent userspace apps 
to send broken content into the system that may be misinterpreted by 
some other userspace application.

Signed-off-by: Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
Signed-off-by: Urs Thuermann <urs.thuermann@volkswagen.de>
Acked-by: Andre Naujoks <nautsch@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Oliver Hartkopp authored and David S. Miller committed Jul 6, 2008
1 parent c5a78ac commit 7f2d38e
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 4 deletions.
10 changes: 10 additions & 0 deletions net/can/af_can.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,12 +205,19 @@ static int can_create(struct net *net, struct socket *sock, int protocol)
* -ENOBUFS on full driver queue (see net_xmit_errno())
* -ENOMEM when local loopback failed at calling skb_clone()
* -EPERM when trying to send on a non-CAN interface
* -EINVAL when the skb->data does not contain a valid CAN frame
*/
int can_send(struct sk_buff *skb, int loop)
{
struct sk_buff *newskb = NULL;
struct can_frame *cf = (struct can_frame *)skb->data;
int err;

if (skb->len != sizeof(struct can_frame) || cf->can_dlc > 8) {
kfree_skb(skb);
return -EINVAL;
}

if (skb->dev->type != ARPHRD_CAN) {
kfree_skb(skb);
return -EPERM;
Expand Down Expand Up @@ -605,13 +612,16 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
struct dev_rcv_lists *d;
struct can_frame *cf = (struct can_frame *)skb->data;
int matches;

if (dev->type != ARPHRD_CAN || dev_net(dev) != &init_net) {
kfree_skb(skb);
return 0;
}

BUG_ON(skb->len != sizeof(struct can_frame) || cf->can_dlc > 8);

/* update statistics */
can_stats.rx_frames++;
can_stats.rx_frames_delta++;
Expand Down
23 changes: 19 additions & 4 deletions net/can/bcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head,

if (head->nframes) {
/* can_frames starting here */
firstframe = (struct can_frame *) skb_tail_pointer(skb);
firstframe = (struct can_frame *)skb_tail_pointer(skb);

memcpy(skb_put(skb, datalen), frames, datalen);

Expand Down Expand Up @@ -826,6 +826,10 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
for (i = 0; i < msg_head->nframes; i++) {
err = memcpy_fromiovec((u8 *)&op->frames[i],
msg->msg_iov, CFSIZ);

if (op->frames[i].can_dlc > 8)
err = -EINVAL;

if (err < 0)
return err;

Expand Down Expand Up @@ -858,6 +862,10 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
for (i = 0; i < msg_head->nframes; i++) {
err = memcpy_fromiovec((u8 *)&op->frames[i],
msg->msg_iov, CFSIZ);

if (op->frames[i].can_dlc > 8)
err = -EINVAL;

if (err < 0) {
if (op->frames != &op->sframe)
kfree(op->frames);
Expand Down Expand Up @@ -1164,9 +1172,12 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk)

skb->dev = dev;
skb->sk = sk;
can_send(skb, 1); /* send with loopback */
err = can_send(skb, 1); /* send with loopback */
dev_put(dev);

if (err)
return err;

return CFSIZ + MHSIZ;
}

Expand All @@ -1185,6 +1196,10 @@ static int bcm_sendmsg(struct kiocb *iocb, struct socket *sock,
if (!bo->bound)
return -ENOTCONN;

/* check for valid message length from userspace */
if (size < MHSIZ || (size - MHSIZ) % CFSIZ)
return -EINVAL;

/* check for alternative ifindex for this bcm_op */

if (!ifindex && msg->msg_name) {
Expand Down Expand Up @@ -1259,8 +1274,8 @@ static int bcm_sendmsg(struct kiocb *iocb, struct socket *sock,
break;

case TX_SEND:
/* we need at least one can_frame */
if (msg_head.nframes < 1)
/* we need exactly one can_frame behind the msg head */
if ((msg_head.nframes != 1) || (size != CFSIZ + MHSIZ))
ret = -EINVAL;
else
ret = bcm_tx_send(msg, ifindex, sk);
Expand Down
3 changes: 3 additions & 0 deletions net/can/raw.c
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,9 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
} else
ifindex = ro->ifindex;

if (size != sizeof(struct can_frame))
return -EINVAL;

dev = dev_get_by_index(&init_net, ifindex);
if (!dev)
return -ENXIO;
Expand Down

0 comments on commit 7f2d38e

Please sign in to comment.