aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/ip6_input.c9
-rw-r--r--net/ipv6/ipv6_sockglue.c11
-rw-r--r--net/ipv6/sit.c44
3 files changed, 40 insertions, 24 deletions
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 4e5c8615832c..17eb48b8e329 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -102,6 +102,15 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
102 if (hdr->version != 6) 102 if (hdr->version != 6)
103 goto err; 103 goto err;
104 104
105 /*
106 * RFC4291 2.5.3
107 * A packet received on an interface with a destination address
108 * of loopback must be dropped.
109 */
110 if (!(dev->flags & IFF_LOOPBACK) &&
111 ipv6_addr_loopback(&hdr->daddr))
112 goto err;
113
105 skb->transport_header = skb->network_header + sizeof(*hdr); 114 skb->transport_header = skb->network_header + sizeof(*hdr);
106 IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr); 115 IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
107 116
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index c042ce19bd14..86e28a75267f 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -345,18 +345,21 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
345 case IPV6_DSTOPTS: 345 case IPV6_DSTOPTS:
346 { 346 {
347 struct ipv6_txoptions *opt; 347 struct ipv6_txoptions *opt;
348
349 /* remove any sticky options header with a zero option
350 * length, per RFC3542.
351 */
348 if (optlen == 0) 352 if (optlen == 0)
349 optval = NULL; 353 optval = NULL;
354 else if (optlen < sizeof(struct ipv6_opt_hdr) ||
355 optlen & 0x7 || optlen > 8 * 255)
356 goto e_inval;
350 357
351 /* hop-by-hop / destination options are privileged option */ 358 /* hop-by-hop / destination options are privileged option */
352 retv = -EPERM; 359 retv = -EPERM;
353 if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW)) 360 if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW))
354 break; 361 break;
355 362
356 if (optlen < sizeof(struct ipv6_opt_hdr) ||
357 optlen & 0x7 || optlen > 8 * 255)
358 goto e_inval;
359
360 opt = ipv6_renew_options(sk, np->opt, optname, 363 opt = ipv6_renew_options(sk, np->opt, optname,
361 (struct ipv6_opt_hdr __user *)optval, 364 (struct ipv6_opt_hdr __user *)optval,
362 optlen); 365 optlen);
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: