diff options
Diffstat (limited to 'net/ipv4/raw.c')
-rw-r--r-- | net/ipv4/raw.c | 120 |
1 files changed, 75 insertions, 45 deletions
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 009a7b2aa1ef..c9893d43242e 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c | |||
@@ -76,6 +76,7 @@ | |||
76 | #include <linux/seq_file.h> | 76 | #include <linux/seq_file.h> |
77 | #include <linux/netfilter.h> | 77 | #include <linux/netfilter.h> |
78 | #include <linux/netfilter_ipv4.h> | 78 | #include <linux/netfilter_ipv4.h> |
79 | #include <linux/compat.h> | ||
79 | 80 | ||
80 | static struct raw_hashinfo raw_v4_hashinfo = { | 81 | static struct raw_hashinfo raw_v4_hashinfo = { |
81 | .lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock), | 82 | .lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock), |
@@ -153,7 +154,7 @@ static __inline__ int icmp_filter(struct sock *sk, struct sk_buff *skb) | |||
153 | * RFC 1122: SHOULD pass TOS value up to the transport layer. | 154 | * RFC 1122: SHOULD pass TOS value up to the transport layer. |
154 | * -> It does. And not only TOS, but all IP header. | 155 | * -> It does. And not only TOS, but all IP header. |
155 | */ | 156 | */ |
156 | static int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash) | 157 | static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash) |
157 | { | 158 | { |
158 | struct sock *sk; | 159 | struct sock *sk; |
159 | struct hlist_head *head; | 160 | struct hlist_head *head; |
@@ -246,7 +247,7 @@ static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info) | |||
246 | } | 247 | } |
247 | 248 | ||
248 | if (inet->recverr) { | 249 | if (inet->recverr) { |
249 | struct iphdr *iph = (struct iphdr *)skb->data; | 250 | const struct iphdr *iph = (const struct iphdr *)skb->data; |
250 | u8 *payload = skb->data + (iph->ihl << 2); | 251 | u8 *payload = skb->data + (iph->ihl << 2); |
251 | 252 | ||
252 | if (inet->hdrincl) | 253 | if (inet->hdrincl) |
@@ -264,7 +265,7 @@ void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info) | |||
264 | { | 265 | { |
265 | int hash; | 266 | int hash; |
266 | struct sock *raw_sk; | 267 | struct sock *raw_sk; |
267 | struct iphdr *iph; | 268 | const struct iphdr *iph; |
268 | struct net *net; | 269 | struct net *net; |
269 | 270 | ||
270 | hash = protocol & (RAW_HTABLE_SIZE - 1); | 271 | hash = protocol & (RAW_HTABLE_SIZE - 1); |
@@ -272,7 +273,7 @@ void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info) | |||
272 | read_lock(&raw_v4_hashinfo.lock); | 273 | read_lock(&raw_v4_hashinfo.lock); |
273 | raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]); | 274 | raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]); |
274 | if (raw_sk != NULL) { | 275 | if (raw_sk != NULL) { |
275 | iph = (struct iphdr *)skb->data; | 276 | iph = (const struct iphdr *)skb->data; |
276 | net = dev_net(skb->dev); | 277 | net = dev_net(skb->dev); |
277 | 278 | ||
278 | while ((raw_sk = __raw_v4_lookup(net, raw_sk, protocol, | 279 | while ((raw_sk = __raw_v4_lookup(net, raw_sk, protocol, |
@@ -280,7 +281,7 @@ void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info) | |||
280 | skb->dev->ifindex)) != NULL) { | 281 | skb->dev->ifindex)) != NULL) { |
281 | raw_err(raw_sk, skb, info); | 282 | raw_err(raw_sk, skb, info); |
282 | raw_sk = sk_next(raw_sk); | 283 | raw_sk = sk_next(raw_sk); |
283 | iph = (struct iphdr *)skb->data; | 284 | iph = (const struct iphdr *)skb->data; |
284 | } | 285 | } |
285 | } | 286 | } |
286 | read_unlock(&raw_v4_hashinfo.lock); | 287 | read_unlock(&raw_v4_hashinfo.lock); |
@@ -313,9 +314,10 @@ int raw_rcv(struct sock *sk, struct sk_buff *skb) | |||
313 | return 0; | 314 | return 0; |
314 | } | 315 | } |
315 | 316 | ||
316 | static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, | 317 | static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, |
317 | struct rtable **rtp, | 318 | void *from, size_t length, |
318 | unsigned int flags) | 319 | struct rtable **rtp, |
320 | unsigned int flags) | ||
319 | { | 321 | { |
320 | struct inet_sock *inet = inet_sk(sk); | 322 | struct inet_sock *inet = inet_sk(sk); |
321 | struct net *net = sock_net(sk); | 323 | struct net *net = sock_net(sk); |
@@ -326,7 +328,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, | |||
326 | struct rtable *rt = *rtp; | 328 | struct rtable *rt = *rtp; |
327 | 329 | ||
328 | if (length > rt->dst.dev->mtu) { | 330 | if (length > rt->dst.dev->mtu) { |
329 | ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->inet_dport, | 331 | ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport, |
330 | rt->dst.dev->mtu); | 332 | rt->dst.dev->mtu); |
331 | return -EMSGSIZE; | 333 | return -EMSGSIZE; |
332 | } | 334 | } |
@@ -371,7 +373,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, | |||
371 | 373 | ||
372 | if (iphlen >= sizeof(*iph)) { | 374 | if (iphlen >= sizeof(*iph)) { |
373 | if (!iph->saddr) | 375 | if (!iph->saddr) |
374 | iph->saddr = rt->rt_src; | 376 | iph->saddr = fl4->saddr; |
375 | iph->check = 0; | 377 | iph->check = 0; |
376 | iph->tot_len = htons(length); | 378 | iph->tot_len = htons(length); |
377 | if (!iph->id) | 379 | if (!iph->id) |
@@ -401,7 +403,7 @@ error: | |||
401 | return err; | 403 | return err; |
402 | } | 404 | } |
403 | 405 | ||
404 | static int raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | 406 | static int raw_probe_proto_opt(struct flowi4 *fl4, struct msghdr *msg) |
405 | { | 407 | { |
406 | struct iovec *iov; | 408 | struct iovec *iov; |
407 | u8 __user *type = NULL; | 409 | u8 __user *type = NULL; |
@@ -417,7 +419,7 @@ static int raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
417 | if (!iov) | 419 | if (!iov) |
418 | continue; | 420 | continue; |
419 | 421 | ||
420 | switch (fl->proto) { | 422 | switch (fl4->flowi4_proto) { |
421 | case IPPROTO_ICMP: | 423 | case IPPROTO_ICMP: |
422 | /* check if one-byte field is readable or not. */ | 424 | /* check if one-byte field is readable or not. */ |
423 | if (iov->iov_base && iov->iov_len < 1) | 425 | if (iov->iov_base && iov->iov_len < 1) |
@@ -432,8 +434,8 @@ static int raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
432 | code = iov->iov_base; | 434 | code = iov->iov_base; |
433 | 435 | ||
434 | if (type && code) { | 436 | if (type && code) { |
435 | if (get_user(fl->fl_icmp_type, type) || | 437 | if (get_user(fl4->fl4_icmp_type, type) || |
436 | get_user(fl->fl_icmp_code, code)) | 438 | get_user(fl4->fl4_icmp_code, code)) |
437 | return -EFAULT; | 439 | return -EFAULT; |
438 | probed = 1; | 440 | probed = 1; |
439 | } | 441 | } |
@@ -454,11 +456,13 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
454 | struct inet_sock *inet = inet_sk(sk); | 456 | struct inet_sock *inet = inet_sk(sk); |
455 | struct ipcm_cookie ipc; | 457 | struct ipcm_cookie ipc; |
456 | struct rtable *rt = NULL; | 458 | struct rtable *rt = NULL; |
459 | struct flowi4 fl4; | ||
457 | int free = 0; | 460 | int free = 0; |
458 | __be32 daddr; | 461 | __be32 daddr; |
459 | __be32 saddr; | 462 | __be32 saddr; |
460 | u8 tos; | 463 | u8 tos; |
461 | int err; | 464 | int err; |
465 | struct ip_options_data opt_copy; | ||
462 | 466 | ||
463 | err = -EMSGSIZE; | 467 | err = -EMSGSIZE; |
464 | if (len > 0xFFFF) | 468 | if (len > 0xFFFF) |
@@ -505,7 +509,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
505 | 509 | ||
506 | ipc.addr = inet->inet_saddr; | 510 | ipc.addr = inet->inet_saddr; |
507 | ipc.opt = NULL; | 511 | ipc.opt = NULL; |
508 | ipc.shtx.flags = 0; | 512 | ipc.tx_flags = 0; |
509 | ipc.oif = sk->sk_bound_dev_if; | 513 | ipc.oif = sk->sk_bound_dev_if; |
510 | 514 | ||
511 | if (msg->msg_controllen) { | 515 | if (msg->msg_controllen) { |
@@ -519,8 +523,18 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
519 | saddr = ipc.addr; | 523 | saddr = ipc.addr; |
520 | ipc.addr = daddr; | 524 | ipc.addr = daddr; |
521 | 525 | ||
522 | if (!ipc.opt) | 526 | if (!ipc.opt) { |
523 | ipc.opt = inet->opt; | 527 | struct ip_options_rcu *inet_opt; |
528 | |||
529 | rcu_read_lock(); | ||
530 | inet_opt = rcu_dereference(inet->inet_opt); | ||
531 | if (inet_opt) { | ||
532 | memcpy(&opt_copy, inet_opt, | ||
533 | sizeof(*inet_opt) + inet_opt->opt.optlen); | ||
534 | ipc.opt = &opt_copy.opt; | ||
535 | } | ||
536 | rcu_read_unlock(); | ||
537 | } | ||
524 | 538 | ||
525 | if (ipc.opt) { | 539 | if (ipc.opt) { |
526 | err = -EINVAL; | 540 | err = -EINVAL; |
@@ -529,10 +543,10 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
529 | */ | 543 | */ |
530 | if (inet->hdrincl) | 544 | if (inet->hdrincl) |
531 | goto done; | 545 | goto done; |
532 | if (ipc.opt->srr) { | 546 | if (ipc.opt->opt.srr) { |
533 | if (!daddr) | 547 | if (!daddr) |
534 | goto done; | 548 | goto done; |
535 | daddr = ipc.opt->faddr; | 549 | daddr = ipc.opt->opt.faddr; |
536 | } | 550 | } |
537 | } | 551 | } |
538 | tos = RT_CONN_FLAGS(sk); | 552 | tos = RT_CONN_FLAGS(sk); |
@@ -546,27 +560,24 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
546 | saddr = inet->mc_addr; | 560 | saddr = inet->mc_addr; |
547 | } | 561 | } |
548 | 562 | ||
549 | { | 563 | flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, |
550 | struct flowi fl = { .oif = ipc.oif, | 564 | RT_SCOPE_UNIVERSE, |
551 | .mark = sk->sk_mark, | 565 | inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, |
552 | .nl_u = { .ip4_u = | 566 | FLOWI_FLAG_CAN_SLEEP, daddr, saddr, 0, 0); |
553 | { .daddr = daddr, | ||
554 | .saddr = saddr, | ||
555 | .tos = tos } }, | ||
556 | .proto = inet->hdrincl ? IPPROTO_RAW : | ||
557 | sk->sk_protocol, | ||
558 | }; | ||
559 | if (!inet->hdrincl) { | ||
560 | err = raw_probe_proto_opt(&fl, msg); | ||
561 | if (err) | ||
562 | goto done; | ||
563 | } | ||
564 | 567 | ||
565 | security_sk_classify_flow(sk, &fl); | 568 | if (!inet->hdrincl) { |
566 | err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 1); | 569 | err = raw_probe_proto_opt(&fl4, msg); |
570 | if (err) | ||
571 | goto done; | ||
567 | } | 572 | } |
568 | if (err) | 573 | |
574 | security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); | ||
575 | rt = ip_route_output_flow(sock_net(sk), &fl4, sk); | ||
576 | if (IS_ERR(rt)) { | ||
577 | err = PTR_ERR(rt); | ||
578 | rt = NULL; | ||
569 | goto done; | 579 | goto done; |
580 | } | ||
570 | 581 | ||
571 | err = -EACCES; | 582 | err = -EACCES; |
572 | if (rt->rt_flags & RTCF_BROADCAST && !sock_flag(sk, SOCK_BROADCAST)) | 583 | if (rt->rt_flags & RTCF_BROADCAST && !sock_flag(sk, SOCK_BROADCAST)) |
@@ -577,19 +588,20 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
577 | back_from_confirm: | 588 | back_from_confirm: |
578 | 589 | ||
579 | if (inet->hdrincl) | 590 | if (inet->hdrincl) |
580 | err = raw_send_hdrinc(sk, msg->msg_iov, len, | 591 | err = raw_send_hdrinc(sk, &fl4, msg->msg_iov, len, |
581 | &rt, msg->msg_flags); | 592 | &rt, msg->msg_flags); |
582 | 593 | ||
583 | else { | 594 | else { |
584 | if (!ipc.addr) | 595 | if (!ipc.addr) |
585 | ipc.addr = rt->rt_dst; | 596 | ipc.addr = fl4.daddr; |
586 | lock_sock(sk); | 597 | lock_sock(sk); |
587 | err = ip_append_data(sk, ip_generic_getfrag, msg->msg_iov, len, 0, | 598 | err = ip_append_data(sk, &fl4, ip_generic_getfrag, |
588 | &ipc, &rt, msg->msg_flags); | 599 | msg->msg_iov, len, 0, |
600 | &ipc, &rt, msg->msg_flags); | ||
589 | if (err) | 601 | if (err) |
590 | ip_flush_pending_frames(sk); | 602 | ip_flush_pending_frames(sk); |
591 | else if (!(msg->msg_flags & MSG_MORE)) { | 603 | else if (!(msg->msg_flags & MSG_MORE)) { |
592 | err = ip_push_pending_frames(sk); | 604 | err = ip_push_pending_frames(sk, &fl4); |
593 | if (err == -ENOBUFS && !inet->recverr) | 605 | if (err == -ENOBUFS && !inet->recverr) |
594 | err = 0; | 606 | err = 0; |
595 | } | 607 | } |
@@ -616,7 +628,7 @@ do_confirm: | |||
616 | static void raw_close(struct sock *sk, long timeout) | 628 | static void raw_close(struct sock *sk, long timeout) |
617 | { | 629 | { |
618 | /* | 630 | /* |
619 | * Raw sockets may have direct kernel refereneces. Kill them. | 631 | * Raw sockets may have direct kernel references. Kill them. |
620 | */ | 632 | */ |
621 | ip_ra_control(sk, 0, NULL); | 633 | ip_ra_control(sk, 0, NULL); |
622 | 634 | ||
@@ -839,6 +851,23 @@ static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
839 | } | 851 | } |
840 | } | 852 | } |
841 | 853 | ||
854 | #ifdef CONFIG_COMPAT | ||
855 | static int compat_raw_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg) | ||
856 | { | ||
857 | switch (cmd) { | ||
858 | case SIOCOUTQ: | ||
859 | case SIOCINQ: | ||
860 | return -ENOIOCTLCMD; | ||
861 | default: | ||
862 | #ifdef CONFIG_IP_MROUTE | ||
863 | return ipmr_compat_ioctl(sk, cmd, compat_ptr(arg)); | ||
864 | #else | ||
865 | return -ENOIOCTLCMD; | ||
866 | #endif | ||
867 | } | ||
868 | } | ||
869 | #endif | ||
870 | |||
842 | struct proto raw_prot = { | 871 | struct proto raw_prot = { |
843 | .name = "RAW", | 872 | .name = "RAW", |
844 | .owner = THIS_MODULE, | 873 | .owner = THIS_MODULE, |
@@ -861,6 +890,7 @@ struct proto raw_prot = { | |||
861 | #ifdef CONFIG_COMPAT | 890 | #ifdef CONFIG_COMPAT |
862 | .compat_setsockopt = compat_raw_setsockopt, | 891 | .compat_setsockopt = compat_raw_setsockopt, |
863 | .compat_getsockopt = compat_raw_getsockopt, | 892 | .compat_getsockopt = compat_raw_getsockopt, |
893 | .compat_ioctl = compat_raw_ioctl, | ||
864 | #endif | 894 | #endif |
865 | }; | 895 | }; |
866 | 896 | ||
@@ -949,7 +979,7 @@ static void raw_sock_seq_show(struct seq_file *seq, struct sock *sp, int i) | |||
949 | srcp = inet->inet_num; | 979 | srcp = inet->inet_num; |
950 | 980 | ||
951 | seq_printf(seq, "%4d: %08X:%04X %08X:%04X" | 981 | seq_printf(seq, "%4d: %08X:%04X %08X:%04X" |
952 | " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n", | 982 | " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d\n", |
953 | i, src, srcp, dest, destp, sp->sk_state, | 983 | i, src, srcp, dest, destp, sp->sk_state, |
954 | sk_wmem_alloc_get(sp), | 984 | sk_wmem_alloc_get(sp), |
955 | sk_rmem_alloc_get(sp), | 985 | sk_rmem_alloc_get(sp), |