diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/packet/af_packet.c | 65 |
1 files changed, 48 insertions, 17 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 8690f171c1ef..ee865d88183b 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -36,6 +36,11 @@ | |||
36 | * Michal Ostrowski : Module initialization cleanup. | 36 | * Michal Ostrowski : Module initialization cleanup. |
37 | * Ulises Alonso : Frame number limit removal and | 37 | * Ulises Alonso : Frame number limit removal and |
38 | * packet_set_ring memory leak. | 38 | * packet_set_ring memory leak. |
39 | * Eric Biederman : Allow for > 8 byte hardware addresses. | ||
40 | * The convention is that longer addresses | ||
41 | * will simply extend the hardware address | ||
42 | * byte arrays at the end of sockaddr_ll | ||
43 | * and packet_mreq. | ||
39 | * | 44 | * |
40 | * This program is free software; you can redistribute it and/or | 45 | * This program is free software; you can redistribute it and/or |
41 | * modify it under the terms of the GNU General Public License | 46 | * modify it under the terms of the GNU General Public License |
@@ -161,7 +166,17 @@ struct packet_mclist | |||
161 | int count; | 166 | int count; |
162 | unsigned short type; | 167 | unsigned short type; |
163 | unsigned short alen; | 168 | unsigned short alen; |
164 | unsigned char addr[8]; | 169 | unsigned char addr[MAX_ADDR_LEN]; |
170 | }; | ||
171 | /* identical to struct packet_mreq except it has | ||
172 | * a longer address field. | ||
173 | */ | ||
174 | struct packet_mreq_max | ||
175 | { | ||
176 | int mr_ifindex; | ||
177 | unsigned short mr_type; | ||
178 | unsigned short mr_alen; | ||
179 | unsigned char mr_address[MAX_ADDR_LEN]; | ||
165 | }; | 180 | }; |
166 | #endif | 181 | #endif |
167 | #ifdef CONFIG_PACKET_MMAP | 182 | #ifdef CONFIG_PACKET_MMAP |
@@ -716,6 +731,8 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
716 | err = -EINVAL; | 731 | err = -EINVAL; |
717 | if (msg->msg_namelen < sizeof(struct sockaddr_ll)) | 732 | if (msg->msg_namelen < sizeof(struct sockaddr_ll)) |
718 | goto out; | 733 | goto out; |
734 | if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll, sll_addr))) | ||
735 | goto out; | ||
719 | ifindex = saddr->sll_ifindex; | 736 | ifindex = saddr->sll_ifindex; |
720 | proto = saddr->sll_protocol; | 737 | proto = saddr->sll_protocol; |
721 | addr = saddr->sll_addr; | 738 | addr = saddr->sll_addr; |
@@ -744,6 +761,12 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
744 | if (dev->hard_header) { | 761 | if (dev->hard_header) { |
745 | int res; | 762 | int res; |
746 | err = -EINVAL; | 763 | err = -EINVAL; |
764 | if (saddr) { | ||
765 | if (saddr->sll_halen != dev->addr_len) | ||
766 | goto out_free; | ||
767 | if (saddr->sll_hatype != dev->type) | ||
768 | goto out_free; | ||
769 | } | ||
747 | res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len); | 770 | res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len); |
748 | if (sock->type != SOCK_DGRAM) { | 771 | if (sock->type != SOCK_DGRAM) { |
749 | skb->tail = skb->data; | 772 | skb->tail = skb->data; |
@@ -1045,6 +1068,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1045 | struct sock *sk = sock->sk; | 1068 | struct sock *sk = sock->sk; |
1046 | struct sk_buff *skb; | 1069 | struct sk_buff *skb; |
1047 | int copied, err; | 1070 | int copied, err; |
1071 | struct sockaddr_ll *sll; | ||
1048 | 1072 | ||
1049 | err = -EINVAL; | 1073 | err = -EINVAL; |
1050 | if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT)) | 1074 | if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT)) |
@@ -1057,16 +1081,6 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1057 | #endif | 1081 | #endif |
1058 | 1082 | ||
1059 | /* | 1083 | /* |
1060 | * If the address length field is there to be filled in, we fill | ||
1061 | * it in now. | ||
1062 | */ | ||
1063 | |||
1064 | if (sock->type == SOCK_PACKET) | ||
1065 | msg->msg_namelen = sizeof(struct sockaddr_pkt); | ||
1066 | else | ||
1067 | msg->msg_namelen = sizeof(struct sockaddr_ll); | ||
1068 | |||
1069 | /* | ||
1070 | * Call the generic datagram receiver. This handles all sorts | 1084 | * Call the generic datagram receiver. This handles all sorts |
1071 | * of horrible races and re-entrancy so we can forget about it | 1085 | * of horrible races and re-entrancy so we can forget about it |
1072 | * in the protocol layers. | 1086 | * in the protocol layers. |
@@ -1087,6 +1101,17 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1087 | goto out; | 1101 | goto out; |
1088 | 1102 | ||
1089 | /* | 1103 | /* |
1104 | * If the address length field is there to be filled in, we fill | ||
1105 | * it in now. | ||
1106 | */ | ||
1107 | |||
1108 | sll = (struct sockaddr_ll*)skb->cb; | ||
1109 | if (sock->type == SOCK_PACKET) | ||
1110 | msg->msg_namelen = sizeof(struct sockaddr_pkt); | ||
1111 | else | ||
1112 | msg->msg_namelen = sll->sll_halen + offsetof(struct sockaddr_ll, sll_addr); | ||
1113 | |||
1114 | /* | ||
1090 | * You lose any data beyond the buffer you gave. If it worries a | 1115 | * You lose any data beyond the buffer you gave. If it worries a |
1091 | * user program they can ask the device for its MTU anyway. | 1116 | * user program they can ask the device for its MTU anyway. |
1092 | */ | 1117 | */ |
@@ -1166,7 +1191,7 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr, | |||
1166 | sll->sll_hatype = 0; /* Bad: we have no ARPHRD_UNSPEC */ | 1191 | sll->sll_hatype = 0; /* Bad: we have no ARPHRD_UNSPEC */ |
1167 | sll->sll_halen = 0; | 1192 | sll->sll_halen = 0; |
1168 | } | 1193 | } |
1169 | *uaddr_len = sizeof(*sll); | 1194 | *uaddr_len = offsetof(struct sockaddr_ll, sll_addr) + sll->sll_halen; |
1170 | 1195 | ||
1171 | return 0; | 1196 | return 0; |
1172 | } | 1197 | } |
@@ -1199,7 +1224,7 @@ static void packet_dev_mclist(struct net_device *dev, struct packet_mclist *i, i | |||
1199 | } | 1224 | } |
1200 | } | 1225 | } |
1201 | 1226 | ||
1202 | static int packet_mc_add(struct sock *sk, struct packet_mreq *mreq) | 1227 | static int packet_mc_add(struct sock *sk, struct packet_mreq_max *mreq) |
1203 | { | 1228 | { |
1204 | struct packet_sock *po = pkt_sk(sk); | 1229 | struct packet_sock *po = pkt_sk(sk); |
1205 | struct packet_mclist *ml, *i; | 1230 | struct packet_mclist *ml, *i; |
@@ -1249,7 +1274,7 @@ done: | |||
1249 | return err; | 1274 | return err; |
1250 | } | 1275 | } |
1251 | 1276 | ||
1252 | static int packet_mc_drop(struct sock *sk, struct packet_mreq *mreq) | 1277 | static int packet_mc_drop(struct sock *sk, struct packet_mreq_max *mreq) |
1253 | { | 1278 | { |
1254 | struct packet_mclist *ml, **mlp; | 1279 | struct packet_mclist *ml, **mlp; |
1255 | 1280 | ||
@@ -1315,11 +1340,17 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv | |||
1315 | case PACKET_ADD_MEMBERSHIP: | 1340 | case PACKET_ADD_MEMBERSHIP: |
1316 | case PACKET_DROP_MEMBERSHIP: | 1341 | case PACKET_DROP_MEMBERSHIP: |
1317 | { | 1342 | { |
1318 | struct packet_mreq mreq; | 1343 | struct packet_mreq_max mreq; |
1319 | if (optlen<sizeof(mreq)) | 1344 | int len = optlen; |
1345 | memset(&mreq, 0, sizeof(mreq)); | ||
1346 | if (len < sizeof(struct packet_mreq)) | ||
1320 | return -EINVAL; | 1347 | return -EINVAL; |
1321 | if (copy_from_user(&mreq,optval,sizeof(mreq))) | 1348 | if (len > sizeof(mreq)) |
1349 | len = sizeof(mreq); | ||
1350 | if (copy_from_user(&mreq,optval,len)) | ||
1322 | return -EFAULT; | 1351 | return -EFAULT; |
1352 | if (len < (mreq.mr_alen + offsetof(struct packet_mreq, mr_address))) | ||
1353 | return -EINVAL; | ||
1323 | if (optname == PACKET_ADD_MEMBERSHIP) | 1354 | if (optname == PACKET_ADD_MEMBERSHIP) |
1324 | ret = packet_mc_add(sk, &mreq); | 1355 | ret = packet_mc_add(sk, &mreq); |
1325 | else | 1356 | else |