diff options
-rw-r--r-- | include/linux/if_tunnel.h | 2 | ||||
-rw-r--r-- | net/ipv6/sit.c | 44 |
2 files changed, 25 insertions, 21 deletions
diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h index f1fbe9c930d7..d4efe4014705 100644 --- a/include/linux/if_tunnel.h +++ b/include/linux/if_tunnel.h | |||
@@ -41,7 +41,7 @@ struct ip_tunnel_prl { | |||
41 | __u16 __reserved; | 41 | __u16 __reserved; |
42 | __u32 datalen; | 42 | __u32 datalen; |
43 | __u32 __reserved2; | 43 | __u32 __reserved2; |
44 | void __user *data; | 44 | /* data follows */ |
45 | }; | 45 | }; |
46 | 46 | ||
47 | /* PRL flags */ | 47 | /* PRL flags */ |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 3de6ffdaedf2..32e871a6c25a 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -222,15 +222,18 @@ __ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr) | |||
222 | 222 | ||
223 | } | 223 | } |
224 | 224 | ||
225 | static int ipip6_tunnel_get_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) | 225 | static int ipip6_tunnel_get_prl(struct ip_tunnel *t, |
226 | struct ip_tunnel_prl __user *a) | ||
226 | { | 227 | { |
227 | struct ip_tunnel_prl *kp; | 228 | struct ip_tunnel_prl kprl, *kp; |
228 | struct ip_tunnel_prl_entry *prl; | 229 | struct ip_tunnel_prl_entry *prl; |
229 | unsigned int cmax, c = 0, ca, len; | 230 | unsigned int cmax, c = 0, ca, len; |
230 | int ret = 0; | 231 | int ret = 0; |
231 | 232 | ||
232 | cmax = a->datalen / sizeof(*a); | 233 | if (copy_from_user(&kprl, a, sizeof(kprl))) |
233 | if (cmax > 1 && a->addr != htonl(INADDR_ANY)) | 234 | return -EFAULT; |
235 | cmax = kprl.datalen / sizeof(kprl); | ||
236 | if (cmax > 1 && kprl.addr != htonl(INADDR_ANY)) | ||
234 | cmax = 1; | 237 | cmax = 1; |
235 | 238 | ||
236 | /* For simple GET or for root users, | 239 | /* For simple GET or for root users, |
@@ -261,26 +264,25 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) | |||
261 | for (prl = t->prl; prl; prl = prl->next) { | 264 | for (prl = t->prl; prl; prl = prl->next) { |
262 | if (c > cmax) | 265 | if (c > cmax) |
263 | break; | 266 | break; |
264 | if (a->addr != htonl(INADDR_ANY) && prl->addr != a->addr) | 267 | if (kprl.addr != htonl(INADDR_ANY) && prl->addr != kprl.addr) |
265 | continue; | 268 | continue; |
266 | kp[c].addr = prl->addr; | 269 | kp[c].addr = prl->addr; |
267 | kp[c].flags = prl->flags; | 270 | kp[c].flags = prl->flags; |
268 | c++; | 271 | c++; |
269 | if (a->addr != htonl(INADDR_ANY)) | 272 | if (kprl.addr != htonl(INADDR_ANY)) |
270 | break; | 273 | break; |
271 | } | 274 | } |
272 | out: | 275 | out: |
273 | read_unlock(&ipip6_lock); | 276 | read_unlock(&ipip6_lock); |
274 | 277 | ||
275 | len = sizeof(*kp) * c; | 278 | len = sizeof(*kp) * c; |
276 | ret = len ? copy_to_user(a->data, kp, len) : 0; | 279 | ret = 0; |
280 | if ((len && copy_to_user(a + 1, kp, len)) || put_user(len, &a->datalen)) | ||
281 | ret = -EFAULT; | ||
277 | 282 | ||
278 | kfree(kp); | 283 | kfree(kp); |
279 | if (ret) | ||
280 | return -EFAULT; | ||
281 | 284 | ||
282 | a->datalen = len; | 285 | return ret; |
283 | return 0; | ||
284 | } | 286 | } |
285 | 287 | ||
286 | static int | 288 | static int |
@@ -873,11 +875,20 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | |||
873 | break; | 875 | break; |
874 | 876 | ||
875 | case SIOCGETPRL: | 877 | case SIOCGETPRL: |
878 | err = -EINVAL; | ||
879 | if (dev == sitn->fb_tunnel_dev) | ||
880 | goto done; | ||
881 | err = -ENOENT; | ||
882 | if (!(t = netdev_priv(dev))) | ||
883 | goto done; | ||
884 | err = ipip6_tunnel_get_prl(t, ifr->ifr_ifru.ifru_data); | ||
885 | break; | ||
886 | |||
876 | case SIOCADDPRL: | 887 | case SIOCADDPRL: |
877 | case SIOCDELPRL: | 888 | case SIOCDELPRL: |
878 | case SIOCCHGPRL: | 889 | case SIOCCHGPRL: |
879 | err = -EPERM; | 890 | err = -EPERM; |
880 | if (cmd != SIOCGETPRL && !capable(CAP_NET_ADMIN)) | 891 | if (!capable(CAP_NET_ADMIN)) |
881 | goto done; | 892 | goto done; |
882 | err = -EINVAL; | 893 | err = -EINVAL; |
883 | if (dev == sitn->fb_tunnel_dev) | 894 | if (dev == sitn->fb_tunnel_dev) |
@@ -890,12 +901,6 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | |||
890 | goto done; | 901 | goto done; |
891 | 902 | ||
892 | switch (cmd) { | 903 | switch (cmd) { |
893 | case SIOCGETPRL: | ||
894 | err = ipip6_tunnel_get_prl(t, &prl); | ||
895 | if (!err && copy_to_user(ifr->ifr_ifru.ifru_data, | ||
896 | &prl, sizeof(prl))) | ||
897 | err = -EFAULT; | ||
898 | break; | ||
899 | case SIOCDELPRL: | 904 | case SIOCDELPRL: |
900 | err = ipip6_tunnel_del_prl(t, &prl); | 905 | err = ipip6_tunnel_del_prl(t, &prl); |
901 | break; | 906 | break; |
@@ -904,8 +909,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | |||
904 | err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL); | 909 | err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL); |
905 | break; | 910 | break; |
906 | } | 911 | } |
907 | if (cmd != SIOCGETPRL) | 912 | netdev_state_change(dev); |
908 | netdev_state_change(dev); | ||
909 | break; | 913 | break; |
910 | 914 | ||
911 | default: | 915 | default: |