aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/sit.c44
1 files changed, 24 insertions, 20 deletions
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
225static int ipip6_tunnel_get_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) 225static 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 }
272out: 275out:
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
286static int 288static 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: