diff options
| -rw-r--r-- | net/can/af_can.c | 10 | ||||
| -rw-r--r-- | net/can/bcm.c | 23 | ||||
| -rw-r--r-- | net/can/raw.c | 3 | 
3 files changed, 32 insertions, 4 deletions
diff --git a/net/can/af_can.c b/net/can/af_can.c index 7e8ca2836452..484bbf6dd032 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c  | |||
| @@ -205,12 +205,19 @@ static int can_create(struct net *net, struct socket *sock, int protocol) | |||
| 205 | * -ENOBUFS on full driver queue (see net_xmit_errno()) | 205 | * -ENOBUFS on full driver queue (see net_xmit_errno()) | 
| 206 | * -ENOMEM when local loopback failed at calling skb_clone() | 206 | * -ENOMEM when local loopback failed at calling skb_clone() | 
| 207 | * -EPERM when trying to send on a non-CAN interface | 207 | * -EPERM when trying to send on a non-CAN interface | 
| 208 | * -EINVAL when the skb->data does not contain a valid CAN frame | ||
| 208 | */ | 209 | */ | 
| 209 | int can_send(struct sk_buff *skb, int loop) | 210 | int can_send(struct sk_buff *skb, int loop) | 
| 210 | { | 211 | { | 
| 211 | struct sk_buff *newskb = NULL; | 212 | struct sk_buff *newskb = NULL; | 
| 213 | struct can_frame *cf = (struct can_frame *)skb->data; | ||
| 212 | int err; | 214 | int err; | 
| 213 | 215 | ||
| 216 | if (skb->len != sizeof(struct can_frame) || cf->can_dlc > 8) { | ||
| 217 | kfree_skb(skb); | ||
| 218 | return -EINVAL; | ||
| 219 | } | ||
| 220 | |||
| 214 | if (skb->dev->type != ARPHRD_CAN) { | 221 | if (skb->dev->type != ARPHRD_CAN) { | 
| 215 | kfree_skb(skb); | 222 | kfree_skb(skb); | 
| 216 | return -EPERM; | 223 | return -EPERM; | 
| @@ -605,6 +612,7 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev, | |||
| 605 | struct packet_type *pt, struct net_device *orig_dev) | 612 | struct packet_type *pt, struct net_device *orig_dev) | 
| 606 | { | 613 | { | 
| 607 | struct dev_rcv_lists *d; | 614 | struct dev_rcv_lists *d; | 
| 615 | struct can_frame *cf = (struct can_frame *)skb->data; | ||
| 608 | int matches; | 616 | int matches; | 
| 609 | 617 | ||
| 610 | if (dev->type != ARPHRD_CAN || dev_net(dev) != &init_net) { | 618 | if (dev->type != ARPHRD_CAN || dev_net(dev) != &init_net) { | 
| @@ -612,6 +620,8 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev, | |||
| 612 | return 0; | 620 | return 0; | 
| 613 | } | 621 | } | 
| 614 | 622 | ||
| 623 | BUG_ON(skb->len != sizeof(struct can_frame) || cf->can_dlc > 8); | ||
| 624 | |||
| 615 | /* update statistics */ | 625 | /* update statistics */ | 
| 616 | can_stats.rx_frames++; | 626 | can_stats.rx_frames++; | 
| 617 | can_stats.rx_frames_delta++; | 627 | can_stats.rx_frames_delta++; | 
diff --git a/net/can/bcm.c b/net/can/bcm.c index d9a3a9d13bed..72c2ce904f83 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c  | |||
| @@ -298,7 +298,7 @@ static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head, | |||
| 298 | 298 | ||
| 299 | if (head->nframes) { | 299 | if (head->nframes) { | 
| 300 | /* can_frames starting here */ | 300 | /* can_frames starting here */ | 
| 301 | firstframe = (struct can_frame *) skb_tail_pointer(skb); | 301 | firstframe = (struct can_frame *)skb_tail_pointer(skb); | 
| 302 | 302 | ||
| 303 | memcpy(skb_put(skb, datalen), frames, datalen); | 303 | memcpy(skb_put(skb, datalen), frames, datalen); | 
| 304 | 304 | ||
| @@ -826,6 +826,10 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, | |||
| 826 | for (i = 0; i < msg_head->nframes; i++) { | 826 | for (i = 0; i < msg_head->nframes; i++) { | 
| 827 | err = memcpy_fromiovec((u8 *)&op->frames[i], | 827 | err = memcpy_fromiovec((u8 *)&op->frames[i], | 
| 828 | msg->msg_iov, CFSIZ); | 828 | msg->msg_iov, CFSIZ); | 
| 829 | |||
| 830 | if (op->frames[i].can_dlc > 8) | ||
| 831 | err = -EINVAL; | ||
| 832 | |||
| 829 | if (err < 0) | 833 | if (err < 0) | 
| 830 | return err; | 834 | return err; | 
| 831 | 835 | ||
| @@ -858,6 +862,10 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, | |||
| 858 | for (i = 0; i < msg_head->nframes; i++) { | 862 | for (i = 0; i < msg_head->nframes; i++) { | 
| 859 | err = memcpy_fromiovec((u8 *)&op->frames[i], | 863 | err = memcpy_fromiovec((u8 *)&op->frames[i], | 
| 860 | msg->msg_iov, CFSIZ); | 864 | msg->msg_iov, CFSIZ); | 
| 865 | |||
| 866 | if (op->frames[i].can_dlc > 8) | ||
| 867 | err = -EINVAL; | ||
| 868 | |||
| 861 | if (err < 0) { | 869 | if (err < 0) { | 
| 862 | if (op->frames != &op->sframe) | 870 | if (op->frames != &op->sframe) | 
| 863 | kfree(op->frames); | 871 | kfree(op->frames); | 
| @@ -1164,9 +1172,12 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk) | |||
| 1164 | 1172 | ||
| 1165 | skb->dev = dev; | 1173 | skb->dev = dev; | 
| 1166 | skb->sk = sk; | 1174 | skb->sk = sk; | 
| 1167 | can_send(skb, 1); /* send with loopback */ | 1175 | err = can_send(skb, 1); /* send with loopback */ | 
| 1168 | dev_put(dev); | 1176 | dev_put(dev); | 
| 1169 | 1177 | ||
| 1178 | if (err) | ||
| 1179 | return err; | ||
| 1180 | |||
| 1170 | return CFSIZ + MHSIZ; | 1181 | return CFSIZ + MHSIZ; | 
| 1171 | } | 1182 | } | 
| 1172 | 1183 | ||
| @@ -1185,6 +1196,10 @@ static int bcm_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 1185 | if (!bo->bound) | 1196 | if (!bo->bound) | 
| 1186 | return -ENOTCONN; | 1197 | return -ENOTCONN; | 
| 1187 | 1198 | ||
| 1199 | /* check for valid message length from userspace */ | ||
| 1200 | if (size < MHSIZ || (size - MHSIZ) % CFSIZ) | ||
| 1201 | return -EINVAL; | ||
| 1202 | |||
| 1188 | /* check for alternative ifindex for this bcm_op */ | 1203 | /* check for alternative ifindex for this bcm_op */ | 
| 1189 | 1204 | ||
| 1190 | if (!ifindex && msg->msg_name) { | 1205 | if (!ifindex && msg->msg_name) { | 
| @@ -1259,8 +1274,8 @@ static int bcm_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 1259 | break; | 1274 | break; | 
| 1260 | 1275 | ||
| 1261 | case TX_SEND: | 1276 | case TX_SEND: | 
| 1262 | /* we need at least one can_frame */ | 1277 | /* we need exactly one can_frame behind the msg head */ | 
| 1263 | if (msg_head.nframes < 1) | 1278 | if ((msg_head.nframes != 1) || (size != CFSIZ + MHSIZ)) | 
| 1264 | ret = -EINVAL; | 1279 | ret = -EINVAL; | 
| 1265 | else | 1280 | else | 
| 1266 | ret = bcm_tx_send(msg, ifindex, sk); | 1281 | ret = bcm_tx_send(msg, ifindex, sk); | 
diff --git a/net/can/raw.c b/net/can/raw.c index 69877b8e7e9c..3e46ee36a1aa 100644 --- a/net/can/raw.c +++ b/net/can/raw.c  | |||
| @@ -632,6 +632,9 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 632 | } else | 632 | } else | 
| 633 | ifindex = ro->ifindex; | 633 | ifindex = ro->ifindex; | 
| 634 | 634 | ||
| 635 | if (size != sizeof(struct can_frame)) | ||
| 636 | return -EINVAL; | ||
| 637 | |||
| 635 | dev = dev_get_by_index(&init_net, ifindex); | 638 | dev = dev_get_by_index(&init_net, ifindex); | 
| 636 | if (!dev) | 639 | if (!dev) | 
| 637 | return -ENXIO; | 640 | return -ENXIO; | 
