diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-31 11:08:31 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-31 11:08:31 -0500 |
commit | 612b322ade7954a1d984fa410a70d4ae50f75c0d (patch) | |
tree | 1e8d6cf698148c5fa23870d81a51eb5a460662e3 | |
parent | d2c59a22dd7c0a59dfff60a8e9910f76f308b9f2 (diff) | |
parent | 1b7c2dbc07bf0663a41e3dc838992930019f08fd (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6:
[IPV6]: fix flowlabel seqfile handling
[IPV6]: return EINVAL for invalid address with flowlabel lease request
[SCTP]: Remove temporary associations from backlog and hash.
[SCTP]: Correctly set IP id for SCTP traffic
[NetLabel]: protect the CIPSOv4 socket option from setsockopt()
[NETFILTER]: ip_tables: compat code module refcounting fix
[NETFILTER]: nf_conntrack: add missing unlock in get_next_corpse()
[NETFILTER]: ip_tables: compat error way cleanup
[NETFILTER]: Missed and reordered checks in {arp,ip,ip6}_tables
[NETFILTER]: remove masq/NAT from ip6tables Kconfig help
[IPV6]: fix lockup via /proc/net/ip6_flowlabel
[NET]: fix uaccess handling
[SCTP]: Always linearise packet on input
[ETH1394]: Fix unaligned accesses.
[DCCP]: fix printk format warnings
[NET]: Fix segmentation of linear packets
[XFRM] xfrm_user: Fix unaligned accesses.
[APPLETALK]: Fix potential OOPS in atalk_sendmsg().
[NET] sealevel: uses arp_broken_ops
-rw-r--r-- | drivers/ieee1394/eth1394.c | 20 | ||||
-rw-r--r-- | drivers/net/wan/Kconfig | 2 | ||||
-rw-r--r-- | net/appletalk/ddp.c | 2 | ||||
-rw-r--r-- | net/core/skbuff.c | 9 | ||||
-rw-r--r-- | net/dccp/ccids/ccid2.c | 18 | ||||
-rw-r--r-- | net/ipv4/cipso_ipv4.c | 7 | ||||
-rw-r--r-- | net/ipv4/ip_options.c | 2 | ||||
-rw-r--r-- | net/ipv4/netfilter/arp_tables.c | 25 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_tables.c | 67 | ||||
-rw-r--r-- | net/ipv4/raw.c | 17 | ||||
-rw-r--r-- | net/ipv6/ip6_flowlabel.c | 24 | ||||
-rw-r--r-- | net/ipv6/netfilter/Kconfig | 2 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 24 | ||||
-rw-r--r-- | net/ipv6/raw.c | 17 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_core.c | 3 | ||||
-rw-r--r-- | net/netlink/af_netlink.c | 5 | ||||
-rw-r--r-- | net/sctp/associola.c | 15 | ||||
-rw-r--r-- | net/sctp/endpointola.c | 7 | ||||
-rw-r--r-- | net/sctp/input.c | 9 | ||||
-rw-r--r-- | net/sctp/protocol.c | 2 | ||||
-rw-r--r-- | net/sctp/socket.c | 9 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 4 | ||||
-rw-r--r-- | security/selinux/hooks.c | 8 | ||||
-rw-r--r-- | security/selinux/include/selinux_netlabel.h | 10 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 37 |
25 files changed, 229 insertions, 116 deletions
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 8a7b8fab6238..31e5cc49d61a 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c | |||
@@ -64,6 +64,7 @@ | |||
64 | #include <linux/ethtool.h> | 64 | #include <linux/ethtool.h> |
65 | #include <asm/uaccess.h> | 65 | #include <asm/uaccess.h> |
66 | #include <asm/delay.h> | 66 | #include <asm/delay.h> |
67 | #include <asm/unaligned.h> | ||
67 | #include <net/arp.h> | 68 | #include <net/arp.h> |
68 | 69 | ||
69 | #include "config_roms.h" | 70 | #include "config_roms.h" |
@@ -491,7 +492,7 @@ static void ether1394_reset_priv (struct net_device *dev, int set_mtu) | |||
491 | int i; | 492 | int i; |
492 | struct eth1394_priv *priv = netdev_priv(dev); | 493 | struct eth1394_priv *priv = netdev_priv(dev); |
493 | struct hpsb_host *host = priv->host; | 494 | struct hpsb_host *host = priv->host; |
494 | u64 guid = *((u64*)&(host->csr.rom->bus_info_data[3])); | 495 | u64 guid = get_unaligned((u64*)&(host->csr.rom->bus_info_data[3])); |
495 | u16 maxpayload = 1 << (host->csr.max_rec + 1); | 496 | u16 maxpayload = 1 << (host->csr.max_rec + 1); |
496 | int max_speed = IEEE1394_SPEED_MAX; | 497 | int max_speed = IEEE1394_SPEED_MAX; |
497 | 498 | ||
@@ -514,8 +515,8 @@ static void ether1394_reset_priv (struct net_device *dev, int set_mtu) | |||
514 | ETHER1394_GASP_OVERHEAD))); | 515 | ETHER1394_GASP_OVERHEAD))); |
515 | 516 | ||
516 | /* Set our hardware address while we're at it */ | 517 | /* Set our hardware address while we're at it */ |
517 | *(u64*)dev->dev_addr = guid; | 518 | memcpy(dev->dev_addr, &guid, sizeof(u64)); |
518 | *(u64*)dev->broadcast = ~0x0ULL; | 519 | memset(dev->broadcast, 0xff, sizeof(u64)); |
519 | } | 520 | } |
520 | 521 | ||
521 | spin_unlock_irqrestore (&priv->lock, flags); | 522 | spin_unlock_irqrestore (&priv->lock, flags); |
@@ -894,6 +895,7 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb, | |||
894 | u16 maxpayload; | 895 | u16 maxpayload; |
895 | struct eth1394_node_ref *node; | 896 | struct eth1394_node_ref *node; |
896 | struct eth1394_node_info *node_info; | 897 | struct eth1394_node_info *node_info; |
898 | __be64 guid; | ||
897 | 899 | ||
898 | /* Sanity check. MacOSX seems to be sending us 131 in this | 900 | /* Sanity check. MacOSX seems to be sending us 131 in this |
899 | * field (atleast on my Panther G5). Not sure why. */ | 901 | * field (atleast on my Panther G5). Not sure why. */ |
@@ -902,8 +904,9 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb, | |||
902 | 904 | ||
903 | maxpayload = min(eth1394_speedto_maxpayload[sspd], (u16)(1 << (max_rec + 1))); | 905 | maxpayload = min(eth1394_speedto_maxpayload[sspd], (u16)(1 << (max_rec + 1))); |
904 | 906 | ||
907 | guid = get_unaligned(&arp1394->s_uniq_id); | ||
905 | node = eth1394_find_node_guid(&priv->ip_node_list, | 908 | node = eth1394_find_node_guid(&priv->ip_node_list, |
906 | be64_to_cpu(arp1394->s_uniq_id)); | 909 | be64_to_cpu(guid)); |
907 | if (!node) { | 910 | if (!node) { |
908 | return 0; | 911 | return 0; |
909 | } | 912 | } |
@@ -931,10 +934,9 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb, | |||
931 | arp_ptr += arp->ar_pln; /* skip over sender IP addr */ | 934 | arp_ptr += arp->ar_pln; /* skip over sender IP addr */ |
932 | 935 | ||
933 | if (arp->ar_op == htons(ARPOP_REQUEST)) | 936 | if (arp->ar_op == htons(ARPOP_REQUEST)) |
934 | /* just set ARP req target unique ID to 0 */ | 937 | memset(arp_ptr, 0, sizeof(u64)); |
935 | *((u64*)arp_ptr) = 0; | ||
936 | else | 938 | else |
937 | *((u64*)arp_ptr) = *((u64*)dev->dev_addr); | 939 | memcpy(arp_ptr, dev->dev_addr, sizeof(u64)); |
938 | } | 940 | } |
939 | 941 | ||
940 | /* Now add the ethernet header. */ | 942 | /* Now add the ethernet header. */ |
@@ -1675,8 +1677,10 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev) | |||
1675 | if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF]) | 1677 | if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF]) |
1676 | priv->bc_dgl++; | 1678 | priv->bc_dgl++; |
1677 | } else { | 1679 | } else { |
1680 | __be64 guid = get_unaligned((u64 *)eth->h_dest); | ||
1681 | |||
1678 | node = eth1394_find_node_guid(&priv->ip_node_list, | 1682 | node = eth1394_find_node_guid(&priv->ip_node_list, |
1679 | be64_to_cpu(*(u64*)eth->h_dest)); | 1683 | be64_to_cpu(guid)); |
1680 | if (!node) { | 1684 | if (!node) { |
1681 | ret = -EAGAIN; | 1685 | ret = -EAGAIN; |
1682 | goto fail; | 1686 | goto fail; |
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 58b7efbb0750..b5d0d7fb647a 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig | |||
@@ -127,7 +127,7 @@ config LANMEDIA | |||
127 | # There is no way to detect a Sealevel board. Force it modular | 127 | # There is no way to detect a Sealevel board. Force it modular |
128 | config SEALEVEL_4021 | 128 | config SEALEVEL_4021 |
129 | tristate "Sealevel Systems 4021 support" | 129 | tristate "Sealevel Systems 4021 support" |
130 | depends on WAN && ISA && m && ISA_DMA_API | 130 | depends on WAN && ISA && m && ISA_DMA_API && INET |
131 | help | 131 | help |
132 | This is a driver for the Sealevel Systems ACB 56 serial I/O adapter. | 132 | This is a driver for the Sealevel Systems ACB 56 serial I/O adapter. |
133 | 133 | ||
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 708e2e0371af..485e35c3b28b 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c | |||
@@ -1584,7 +1584,6 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr | |||
1584 | 1584 | ||
1585 | if (usat->sat_addr.s_net || usat->sat_addr.s_node == ATADDR_ANYNODE) { | 1585 | if (usat->sat_addr.s_net || usat->sat_addr.s_node == ATADDR_ANYNODE) { |
1586 | rt = atrtr_find(&usat->sat_addr); | 1586 | rt = atrtr_find(&usat->sat_addr); |
1587 | dev = rt->dev; | ||
1588 | } else { | 1587 | } else { |
1589 | struct atalk_addr at_hint; | 1588 | struct atalk_addr at_hint; |
1590 | 1589 | ||
@@ -1592,7 +1591,6 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr | |||
1592 | at_hint.s_net = at->src_net; | 1591 | at_hint.s_net = at->src_net; |
1593 | 1592 | ||
1594 | rt = atrtr_find(&at_hint); | 1593 | rt = atrtr_find(&at_hint); |
1595 | dev = rt->dev; | ||
1596 | } | 1594 | } |
1597 | if (!rt) | 1595 | if (!rt) |
1598 | return -ENETUNREACH; | 1596 | return -ENETUNREACH; |
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 3c23760c5827..f735455dc5d1 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -1946,7 +1946,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features) | |||
1946 | do { | 1946 | do { |
1947 | struct sk_buff *nskb; | 1947 | struct sk_buff *nskb; |
1948 | skb_frag_t *frag; | 1948 | skb_frag_t *frag; |
1949 | int hsize, nsize; | 1949 | int hsize; |
1950 | int k; | 1950 | int k; |
1951 | int size; | 1951 | int size; |
1952 | 1952 | ||
@@ -1957,11 +1957,10 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features) | |||
1957 | hsize = skb_headlen(skb) - offset; | 1957 | hsize = skb_headlen(skb) - offset; |
1958 | if (hsize < 0) | 1958 | if (hsize < 0) |
1959 | hsize = 0; | 1959 | hsize = 0; |
1960 | nsize = hsize + doffset; | 1960 | if (hsize > len || !sg) |
1961 | if (nsize > len + doffset || !sg) | 1961 | hsize = len; |
1962 | nsize = len + doffset; | ||
1963 | 1962 | ||
1964 | nskb = alloc_skb(nsize + headroom, GFP_ATOMIC); | 1963 | nskb = alloc_skb(hsize + doffset + headroom, GFP_ATOMIC); |
1965 | if (unlikely(!nskb)) | 1964 | if (unlikely(!nskb)) |
1966 | goto err; | 1965 | goto err; |
1967 | 1966 | ||
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index 2fbb84bf4e26..162032baeac0 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c | |||
@@ -352,14 +352,14 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, int len) | |||
352 | 352 | ||
353 | #ifdef CONFIG_IP_DCCP_CCID2_DEBUG | 353 | #ifdef CONFIG_IP_DCCP_CCID2_DEBUG |
354 | ccid2_pr_debug("pipe=%d\n", hctx->ccid2hctx_pipe); | 354 | ccid2_pr_debug("pipe=%d\n", hctx->ccid2hctx_pipe); |
355 | ccid2_pr_debug("Sent: seq=%llu\n", seq); | 355 | ccid2_pr_debug("Sent: seq=%llu\n", (unsigned long long)seq); |
356 | do { | 356 | do { |
357 | struct ccid2_seq *seqp = hctx->ccid2hctx_seqt; | 357 | struct ccid2_seq *seqp = hctx->ccid2hctx_seqt; |
358 | 358 | ||
359 | while (seqp != hctx->ccid2hctx_seqh) { | 359 | while (seqp != hctx->ccid2hctx_seqh) { |
360 | ccid2_pr_debug("out seq=%llu acked=%d time=%lu\n", | 360 | ccid2_pr_debug("out seq=%llu acked=%d time=%lu\n", |
361 | seqp->ccid2s_seq, seqp->ccid2s_acked, | 361 | (unsigned long long)seqp->ccid2s_seq, |
362 | seqp->ccid2s_sent); | 362 | seqp->ccid2s_acked, seqp->ccid2s_sent); |
363 | seqp = seqp->ccid2s_next; | 363 | seqp = seqp->ccid2s_next; |
364 | } | 364 | } |
365 | } while (0); | 365 | } while (0); |
@@ -480,7 +480,8 @@ static inline void ccid2_new_ack(struct sock *sk, | |||
480 | /* first measurement */ | 480 | /* first measurement */ |
481 | if (hctx->ccid2hctx_srtt == -1) { | 481 | if (hctx->ccid2hctx_srtt == -1) { |
482 | ccid2_pr_debug("R: %lu Time=%lu seq=%llu\n", | 482 | ccid2_pr_debug("R: %lu Time=%lu seq=%llu\n", |
483 | r, jiffies, seqp->ccid2s_seq); | 483 | r, jiffies, |
484 | (unsigned long long)seqp->ccid2s_seq); | ||
484 | ccid2_change_srtt(hctx, r); | 485 | ccid2_change_srtt(hctx, r); |
485 | hctx->ccid2hctx_rttvar = r >> 1; | 486 | hctx->ccid2hctx_rttvar = r >> 1; |
486 | } else { | 487 | } else { |
@@ -636,8 +637,9 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
636 | u64 ackno_end_rl; | 637 | u64 ackno_end_rl; |
637 | 638 | ||
638 | dccp_set_seqno(&ackno_end_rl, ackno - rl); | 639 | dccp_set_seqno(&ackno_end_rl, ackno - rl); |
639 | ccid2_pr_debug("ackvec start:%llu end:%llu\n", ackno, | 640 | ccid2_pr_debug("ackvec start:%llu end:%llu\n", |
640 | ackno_end_rl); | 641 | (unsigned long long)ackno, |
642 | (unsigned long long)ackno_end_rl); | ||
641 | /* if the seqno we are analyzing is larger than the | 643 | /* if the seqno we are analyzing is larger than the |
642 | * current ackno, then move towards the tail of our | 644 | * current ackno, then move towards the tail of our |
643 | * seqnos. | 645 | * seqnos. |
@@ -672,7 +674,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
672 | 674 | ||
673 | seqp->ccid2s_acked = 1; | 675 | seqp->ccid2s_acked = 1; |
674 | ccid2_pr_debug("Got ack for %llu\n", | 676 | ccid2_pr_debug("Got ack for %llu\n", |
675 | seqp->ccid2s_seq); | 677 | (unsigned long long)seqp->ccid2s_seq); |
676 | ccid2_hc_tx_dec_pipe(sk); | 678 | ccid2_hc_tx_dec_pipe(sk); |
677 | } | 679 | } |
678 | if (seqp == hctx->ccid2hctx_seqt) { | 680 | if (seqp == hctx->ccid2hctx_seqt) { |
@@ -718,7 +720,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
718 | while (1) { | 720 | while (1) { |
719 | if (!seqp->ccid2s_acked) { | 721 | if (!seqp->ccid2s_acked) { |
720 | ccid2_pr_debug("Packet lost: %llu\n", | 722 | ccid2_pr_debug("Packet lost: %llu\n", |
721 | seqp->ccid2s_seq); | 723 | (unsigned long long)seqp->ccid2s_seq); |
722 | /* XXX need to traverse from tail -> head in | 724 | /* XXX need to traverse from tail -> head in |
723 | * order to detect multiple congestion events in | 725 | * order to detect multiple congestion events in |
724 | * one ack vector. | 726 | * one ack vector. |
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index e2077a3aa8c0..6460233407c7 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c | |||
@@ -1307,7 +1307,8 @@ int cipso_v4_socket_setattr(const struct socket *sock, | |||
1307 | 1307 | ||
1308 | /* We can't use ip_options_get() directly because it makes a call to | 1308 | /* We can't use ip_options_get() directly because it makes a call to |
1309 | * ip_options_get_alloc() which allocates memory with GFP_KERNEL and | 1309 | * ip_options_get_alloc() which allocates memory with GFP_KERNEL and |
1310 | * we can't block here. */ | 1310 | * we won't always have CAP_NET_RAW even though we _always_ want to |
1311 | * set the IPOPT_CIPSO option. */ | ||
1311 | opt_len = (buf_len + 3) & ~3; | 1312 | opt_len = (buf_len + 3) & ~3; |
1312 | opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC); | 1313 | opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC); |
1313 | if (opt == NULL) { | 1314 | if (opt == NULL) { |
@@ -1317,11 +1318,9 @@ int cipso_v4_socket_setattr(const struct socket *sock, | |||
1317 | memcpy(opt->__data, buf, buf_len); | 1318 | memcpy(opt->__data, buf, buf_len); |
1318 | opt->optlen = opt_len; | 1319 | opt->optlen = opt_len; |
1319 | opt->is_data = 1; | 1320 | opt->is_data = 1; |
1321 | opt->cipso = sizeof(struct iphdr); | ||
1320 | kfree(buf); | 1322 | kfree(buf); |
1321 | buf = NULL; | 1323 | buf = NULL; |
1322 | ret_val = ip_options_compile(opt, NULL); | ||
1323 | if (ret_val != 0) | ||
1324 | goto socket_setattr_failure; | ||
1325 | 1324 | ||
1326 | sk_inet = inet_sk(sk); | 1325 | sk_inet = inet_sk(sk); |
1327 | if (sk_inet->is_icsk) { | 1326 | if (sk_inet->is_icsk) { |
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 8dabbfc31267..9f02917d6f45 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c | |||
@@ -443,7 +443,7 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb) | |||
443 | opt->router_alert = optptr - iph; | 443 | opt->router_alert = optptr - iph; |
444 | break; | 444 | break; |
445 | case IPOPT_CIPSO: | 445 | case IPOPT_CIPSO: |
446 | if (opt->cipso) { | 446 | if ((!skb && !capable(CAP_NET_RAW)) || opt->cipso) { |
447 | pp_ptr = optptr; | 447 | pp_ptr = optptr; |
448 | goto error; | 448 | goto error; |
449 | } | 449 | } |
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 0849f1cced13..413c2d0a1f3d 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c | |||
@@ -466,7 +466,13 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i | |||
466 | return -EINVAL; | 466 | return -EINVAL; |
467 | } | 467 | } |
468 | 468 | ||
469 | if (e->target_offset + sizeof(struct arpt_entry_target) > e->next_offset) | ||
470 | return -EINVAL; | ||
471 | |||
469 | t = arpt_get_target(e); | 472 | t = arpt_get_target(e); |
473 | if (e->target_offset + t->u.target_size > e->next_offset) | ||
474 | return -EINVAL; | ||
475 | |||
470 | target = try_then_request_module(xt_find_target(NF_ARP, t->u.user.name, | 476 | target = try_then_request_module(xt_find_target(NF_ARP, t->u.user.name, |
471 | t->u.user.revision), | 477 | t->u.user.revision), |
472 | "arpt_%s", t->u.user.name); | 478 | "arpt_%s", t->u.user.name); |
@@ -621,20 +627,18 @@ static int translate_table(const char *name, | |||
621 | } | 627 | } |
622 | } | 628 | } |
623 | 629 | ||
624 | if (!mark_source_chains(newinfo, valid_hooks, entry0)) { | ||
625 | duprintf("Looping hook\n"); | ||
626 | return -ELOOP; | ||
627 | } | ||
628 | |||
629 | /* Finally, each sanity check must pass */ | 630 | /* Finally, each sanity check must pass */ |
630 | i = 0; | 631 | i = 0; |
631 | ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size, | 632 | ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size, |
632 | check_entry, name, size, &i); | 633 | check_entry, name, size, &i); |
633 | 634 | ||
634 | if (ret != 0) { | 635 | if (ret != 0) |
635 | ARPT_ENTRY_ITERATE(entry0, newinfo->size, | 636 | goto cleanup; |
636 | cleanup_entry, &i); | 637 | |
637 | return ret; | 638 | ret = -ELOOP; |
639 | if (!mark_source_chains(newinfo, valid_hooks, entry0)) { | ||
640 | duprintf("Looping hook\n"); | ||
641 | goto cleanup; | ||
638 | } | 642 | } |
639 | 643 | ||
640 | /* And one copy for every other CPU */ | 644 | /* And one copy for every other CPU */ |
@@ -643,6 +647,9 @@ static int translate_table(const char *name, | |||
643 | memcpy(newinfo->entries[i], entry0, newinfo->size); | 647 | memcpy(newinfo->entries[i], entry0, newinfo->size); |
644 | } | 648 | } |
645 | 649 | ||
650 | return 0; | ||
651 | cleanup: | ||
652 | ARPT_ENTRY_ITERATE(entry0, newinfo->size, cleanup_entry, &i); | ||
646 | return ret; | 653 | return ret; |
647 | } | 654 | } |
648 | 655 | ||
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 4b90927619b8..8a455439b128 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
@@ -547,12 +547,18 @@ check_entry(struct ipt_entry *e, const char *name, unsigned int size, | |||
547 | return -EINVAL; | 547 | return -EINVAL; |
548 | } | 548 | } |
549 | 549 | ||
550 | if (e->target_offset + sizeof(struct ipt_entry_target) > e->next_offset) | ||
551 | return -EINVAL; | ||
552 | |||
550 | j = 0; | 553 | j = 0; |
551 | ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j); | 554 | ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j); |
552 | if (ret != 0) | 555 | if (ret != 0) |
553 | goto cleanup_matches; | 556 | goto cleanup_matches; |
554 | 557 | ||
555 | t = ipt_get_target(e); | 558 | t = ipt_get_target(e); |
559 | ret = -EINVAL; | ||
560 | if (e->target_offset + t->u.target_size > e->next_offset) | ||
561 | goto cleanup_matches; | ||
556 | target = try_then_request_module(xt_find_target(AF_INET, | 562 | target = try_then_request_module(xt_find_target(AF_INET, |
557 | t->u.user.name, | 563 | t->u.user.name, |
558 | t->u.user.revision), | 564 | t->u.user.revision), |
@@ -712,19 +718,17 @@ translate_table(const char *name, | |||
712 | } | 718 | } |
713 | } | 719 | } |
714 | 720 | ||
715 | if (!mark_source_chains(newinfo, valid_hooks, entry0)) | ||
716 | return -ELOOP; | ||
717 | |||
718 | /* Finally, each sanity check must pass */ | 721 | /* Finally, each sanity check must pass */ |
719 | i = 0; | 722 | i = 0; |
720 | ret = IPT_ENTRY_ITERATE(entry0, newinfo->size, | 723 | ret = IPT_ENTRY_ITERATE(entry0, newinfo->size, |
721 | check_entry, name, size, &i); | 724 | check_entry, name, size, &i); |
722 | 725 | ||
723 | if (ret != 0) { | 726 | if (ret != 0) |
724 | IPT_ENTRY_ITERATE(entry0, newinfo->size, | 727 | goto cleanup; |
725 | cleanup_entry, &i); | 728 | |
726 | return ret; | 729 | ret = -ELOOP; |
727 | } | 730 | if (!mark_source_chains(newinfo, valid_hooks, entry0)) |
731 | goto cleanup; | ||
728 | 732 | ||
729 | /* And one copy for every other CPU */ | 733 | /* And one copy for every other CPU */ |
730 | for_each_possible_cpu(i) { | 734 | for_each_possible_cpu(i) { |
@@ -732,6 +736,9 @@ translate_table(const char *name, | |||
732 | memcpy(newinfo->entries[i], entry0, newinfo->size); | 736 | memcpy(newinfo->entries[i], entry0, newinfo->size); |
733 | } | 737 | } |
734 | 738 | ||
739 | return 0; | ||
740 | cleanup: | ||
741 | IPT_ENTRY_ITERATE(entry0, newinfo->size, cleanup_entry, &i); | ||
735 | return ret; | 742 | return ret; |
736 | } | 743 | } |
737 | 744 | ||
@@ -1463,6 +1470,10 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e, | |||
1463 | return -EINVAL; | 1470 | return -EINVAL; |
1464 | } | 1471 | } |
1465 | 1472 | ||
1473 | if (e->target_offset + sizeof(struct compat_xt_entry_target) > | ||
1474 | e->next_offset) | ||
1475 | return -EINVAL; | ||
1476 | |||
1466 | off = 0; | 1477 | off = 0; |
1467 | entry_offset = (void *)e - (void *)base; | 1478 | entry_offset = (void *)e - (void *)base; |
1468 | j = 0; | 1479 | j = 0; |
@@ -1472,6 +1483,9 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e, | |||
1472 | goto cleanup_matches; | 1483 | goto cleanup_matches; |
1473 | 1484 | ||
1474 | t = ipt_get_target(e); | 1485 | t = ipt_get_target(e); |
1486 | ret = -EINVAL; | ||
1487 | if (e->target_offset + t->u.target_size > e->next_offset) | ||
1488 | goto cleanup_matches; | ||
1475 | target = try_then_request_module(xt_find_target(AF_INET, | 1489 | target = try_then_request_module(xt_find_target(AF_INET, |
1476 | t->u.user.name, | 1490 | t->u.user.name, |
1477 | t->u.user.revision), | 1491 | t->u.user.revision), |
@@ -1513,7 +1527,7 @@ cleanup_matches: | |||
1513 | 1527 | ||
1514 | static inline int compat_copy_match_from_user(struct ipt_entry_match *m, | 1528 | static inline int compat_copy_match_from_user(struct ipt_entry_match *m, |
1515 | void **dstptr, compat_uint_t *size, const char *name, | 1529 | void **dstptr, compat_uint_t *size, const char *name, |
1516 | const struct ipt_ip *ip, unsigned int hookmask, int *i) | 1530 | const struct ipt_ip *ip, unsigned int hookmask) |
1517 | { | 1531 | { |
1518 | struct ipt_entry_match *dm; | 1532 | struct ipt_entry_match *dm; |
1519 | struct ipt_match *match; | 1533 | struct ipt_match *match; |
@@ -1526,22 +1540,13 @@ static inline int compat_copy_match_from_user(struct ipt_entry_match *m, | |||
1526 | ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm), | 1540 | ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm), |
1527 | name, hookmask, ip->proto, | 1541 | name, hookmask, ip->proto, |
1528 | ip->invflags & IPT_INV_PROTO); | 1542 | ip->invflags & IPT_INV_PROTO); |
1529 | if (ret) | 1543 | if (!ret && m->u.kernel.match->checkentry |
1530 | goto err; | ||
1531 | |||
1532 | if (m->u.kernel.match->checkentry | ||
1533 | && !m->u.kernel.match->checkentry(name, ip, match, dm->data, | 1544 | && !m->u.kernel.match->checkentry(name, ip, match, dm->data, |
1534 | hookmask)) { | 1545 | hookmask)) { |
1535 | duprintf("ip_tables: check failed for `%s'.\n", | 1546 | duprintf("ip_tables: check failed for `%s'.\n", |
1536 | m->u.kernel.match->name); | 1547 | m->u.kernel.match->name); |
1537 | ret = -EINVAL; | 1548 | ret = -EINVAL; |
1538 | goto err; | ||
1539 | } | 1549 | } |
1540 | (*i)++; | ||
1541 | return 0; | ||
1542 | |||
1543 | err: | ||
1544 | module_put(m->u.kernel.match->me); | ||
1545 | return ret; | 1550 | return ret; |
1546 | } | 1551 | } |
1547 | 1552 | ||
@@ -1553,19 +1558,18 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr, | |||
1553 | struct ipt_target *target; | 1558 | struct ipt_target *target; |
1554 | struct ipt_entry *de; | 1559 | struct ipt_entry *de; |
1555 | unsigned int origsize; | 1560 | unsigned int origsize; |
1556 | int ret, h, j; | 1561 | int ret, h; |
1557 | 1562 | ||
1558 | ret = 0; | 1563 | ret = 0; |
1559 | origsize = *size; | 1564 | origsize = *size; |
1560 | de = (struct ipt_entry *)*dstptr; | 1565 | de = (struct ipt_entry *)*dstptr; |
1561 | memcpy(de, e, sizeof(struct ipt_entry)); | 1566 | memcpy(de, e, sizeof(struct ipt_entry)); |
1562 | 1567 | ||
1563 | j = 0; | ||
1564 | *dstptr += sizeof(struct compat_ipt_entry); | 1568 | *dstptr += sizeof(struct compat_ipt_entry); |
1565 | ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size, | 1569 | ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size, |
1566 | name, &de->ip, de->comefrom, &j); | 1570 | name, &de->ip, de->comefrom); |
1567 | if (ret) | 1571 | if (ret) |
1568 | goto cleanup_matches; | 1572 | goto err; |
1569 | de->target_offset = e->target_offset - (origsize - *size); | 1573 | de->target_offset = e->target_offset - (origsize - *size); |
1570 | t = ipt_get_target(e); | 1574 | t = ipt_get_target(e); |
1571 | target = t->u.kernel.target; | 1575 | target = t->u.kernel.target; |
@@ -1599,12 +1603,7 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr, | |||
1599 | goto err; | 1603 | goto err; |
1600 | } | 1604 | } |
1601 | ret = 0; | 1605 | ret = 0; |
1602 | return ret; | ||
1603 | |||
1604 | err: | 1606 | err: |
1605 | module_put(t->u.kernel.target->me); | ||
1606 | cleanup_matches: | ||
1607 | IPT_MATCH_ITERATE(e, cleanup_match, &j); | ||
1608 | return ret; | 1607 | return ret; |
1609 | } | 1608 | } |
1610 | 1609 | ||
@@ -1618,7 +1617,7 @@ translate_compat_table(const char *name, | |||
1618 | unsigned int *hook_entries, | 1617 | unsigned int *hook_entries, |
1619 | unsigned int *underflows) | 1618 | unsigned int *underflows) |
1620 | { | 1619 | { |
1621 | unsigned int i; | 1620 | unsigned int i, j; |
1622 | struct xt_table_info *newinfo, *info; | 1621 | struct xt_table_info *newinfo, *info; |
1623 | void *pos, *entry0, *entry1; | 1622 | void *pos, *entry0, *entry1; |
1624 | unsigned int size; | 1623 | unsigned int size; |
@@ -1636,21 +1635,21 @@ translate_compat_table(const char *name, | |||
1636 | } | 1635 | } |
1637 | 1636 | ||
1638 | duprintf("translate_compat_table: size %u\n", info->size); | 1637 | duprintf("translate_compat_table: size %u\n", info->size); |
1639 | i = 0; | 1638 | j = 0; |
1640 | xt_compat_lock(AF_INET); | 1639 | xt_compat_lock(AF_INET); |
1641 | /* Walk through entries, checking offsets. */ | 1640 | /* Walk through entries, checking offsets. */ |
1642 | ret = IPT_ENTRY_ITERATE(entry0, total_size, | 1641 | ret = IPT_ENTRY_ITERATE(entry0, total_size, |
1643 | check_compat_entry_size_and_hooks, | 1642 | check_compat_entry_size_and_hooks, |
1644 | info, &size, entry0, | 1643 | info, &size, entry0, |
1645 | entry0 + total_size, | 1644 | entry0 + total_size, |
1646 | hook_entries, underflows, &i, name); | 1645 | hook_entries, underflows, &j, name); |
1647 | if (ret != 0) | 1646 | if (ret != 0) |
1648 | goto out_unlock; | 1647 | goto out_unlock; |
1649 | 1648 | ||
1650 | ret = -EINVAL; | 1649 | ret = -EINVAL; |
1651 | if (i != number) { | 1650 | if (j != number) { |
1652 | duprintf("translate_compat_table: %u not %u entries\n", | 1651 | duprintf("translate_compat_table: %u not %u entries\n", |
1653 | i, number); | 1652 | j, number); |
1654 | goto out_unlock; | 1653 | goto out_unlock; |
1655 | } | 1654 | } |
1656 | 1655 | ||
@@ -1709,8 +1708,10 @@ translate_compat_table(const char *name, | |||
1709 | free_newinfo: | 1708 | free_newinfo: |
1710 | xt_free_table_info(newinfo); | 1709 | xt_free_table_info(newinfo); |
1711 | out: | 1710 | out: |
1711 | IPT_ENTRY_ITERATE(entry0, total_size, cleanup_entry, &j); | ||
1712 | return ret; | 1712 | return ret; |
1713 | out_unlock: | 1713 | out_unlock: |
1714 | compat_flush_offsets(); | ||
1714 | xt_compat_unlock(AF_INET); | 1715 | xt_compat_unlock(AF_INET); |
1715 | goto out; | 1716 | goto out; |
1716 | } | 1717 | } |
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index b430cf2a4f66..5c31dead2bdc 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c | |||
@@ -329,7 +329,7 @@ error: | |||
329 | return err; | 329 | return err; |
330 | } | 330 | } |
331 | 331 | ||
332 | static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | 332 | static int raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg) |
333 | { | 333 | { |
334 | struct iovec *iov; | 334 | struct iovec *iov; |
335 | u8 __user *type = NULL; | 335 | u8 __user *type = NULL; |
@@ -338,7 +338,7 @@ static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
338 | unsigned int i; | 338 | unsigned int i; |
339 | 339 | ||
340 | if (!msg->msg_iov) | 340 | if (!msg->msg_iov) |
341 | return; | 341 | return 0; |
342 | 342 | ||
343 | for (i = 0; i < msg->msg_iovlen; i++) { | 343 | for (i = 0; i < msg->msg_iovlen; i++) { |
344 | iov = &msg->msg_iov[i]; | 344 | iov = &msg->msg_iov[i]; |
@@ -360,8 +360,9 @@ static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
360 | code = iov->iov_base; | 360 | code = iov->iov_base; |
361 | 361 | ||
362 | if (type && code) { | 362 | if (type && code) { |
363 | get_user(fl->fl_icmp_type, type); | 363 | if (get_user(fl->fl_icmp_type, type) || |
364 | get_user(fl->fl_icmp_code, code); | 364 | get_user(fl->fl_icmp_code, code)) |
365 | return -EFAULT; | ||
365 | probed = 1; | 366 | probed = 1; |
366 | } | 367 | } |
367 | break; | 368 | break; |
@@ -372,6 +373,7 @@ static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
372 | if (probed) | 373 | if (probed) |
373 | break; | 374 | break; |
374 | } | 375 | } |
376 | return 0; | ||
375 | } | 377 | } |
376 | 378 | ||
377 | static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | 379 | static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |
@@ -480,8 +482,11 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
480 | .proto = inet->hdrincl ? IPPROTO_RAW : | 482 | .proto = inet->hdrincl ? IPPROTO_RAW : |
481 | sk->sk_protocol, | 483 | sk->sk_protocol, |
482 | }; | 484 | }; |
483 | if (!inet->hdrincl) | 485 | if (!inet->hdrincl) { |
484 | raw_probe_proto_opt(&fl, msg); | 486 | err = raw_probe_proto_opt(&fl, msg); |
487 | if (err) | ||
488 | goto done; | ||
489 | } | ||
485 | 490 | ||
486 | security_sk_classify_flow(sk, &fl); | 491 | security_sk_classify_flow(sk, &fl); |
487 | err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT)); | 492 | err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT)); |
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 1d672b0547f2..6d4533b58dca 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
@@ -330,8 +330,10 @@ fl_create(struct in6_flowlabel_req *freq, char __user *optval, int optlen, int * | |||
330 | fl->share = freq->flr_share; | 330 | fl->share = freq->flr_share; |
331 | addr_type = ipv6_addr_type(&freq->flr_dst); | 331 | addr_type = ipv6_addr_type(&freq->flr_dst); |
332 | if ((addr_type&IPV6_ADDR_MAPPED) | 332 | if ((addr_type&IPV6_ADDR_MAPPED) |
333 | || addr_type == IPV6_ADDR_ANY) | 333 | || addr_type == IPV6_ADDR_ANY) { |
334 | err = -EINVAL; | ||
334 | goto done; | 335 | goto done; |
336 | } | ||
335 | ipv6_addr_copy(&fl->dst, &freq->flr_dst); | 337 | ipv6_addr_copy(&fl->dst, &freq->flr_dst); |
336 | atomic_set(&fl->users, 1); | 338 | atomic_set(&fl->users, 1); |
337 | switch (fl->share) { | 339 | switch (fl->share) { |
@@ -587,6 +589,8 @@ static struct ip6_flowlabel *ip6fl_get_next(struct seq_file *seq, struct ip6_flo | |||
587 | while (!fl) { | 589 | while (!fl) { |
588 | if (++state->bucket <= FL_HASH_MASK) | 590 | if (++state->bucket <= FL_HASH_MASK) |
589 | fl = fl_ht[state->bucket]; | 591 | fl = fl_ht[state->bucket]; |
592 | else | ||
593 | break; | ||
590 | } | 594 | } |
591 | return fl; | 595 | return fl; |
592 | } | 596 | } |
@@ -623,9 +627,13 @@ static void ip6fl_seq_stop(struct seq_file *seq, void *v) | |||
623 | read_unlock_bh(&ip6_fl_lock); | 627 | read_unlock_bh(&ip6_fl_lock); |
624 | } | 628 | } |
625 | 629 | ||
626 | static void ip6fl_fl_seq_show(struct seq_file *seq, struct ip6_flowlabel *fl) | 630 | static int ip6fl_seq_show(struct seq_file *seq, void *v) |
627 | { | 631 | { |
628 | while(fl) { | 632 | if (v == SEQ_START_TOKEN) |
633 | seq_printf(seq, "%-5s %-1s %-6s %-6s %-6s %-8s %-32s %s\n", | ||
634 | "Label", "S", "Owner", "Users", "Linger", "Expires", "Dst", "Opt"); | ||
635 | else { | ||
636 | struct ip6_flowlabel *fl = v; | ||
629 | seq_printf(seq, | 637 | seq_printf(seq, |
630 | "%05X %-1d %-6d %-6d %-6ld %-8ld " NIP6_SEQFMT " %-4d\n", | 638 | "%05X %-1d %-6d %-6d %-6ld %-8ld " NIP6_SEQFMT " %-4d\n", |
631 | (unsigned)ntohl(fl->label), | 639 | (unsigned)ntohl(fl->label), |
@@ -636,17 +644,7 @@ static void ip6fl_fl_seq_show(struct seq_file *seq, struct ip6_flowlabel *fl) | |||
636 | (long)(fl->expires - jiffies)/HZ, | 644 | (long)(fl->expires - jiffies)/HZ, |
637 | NIP6(fl->dst), | 645 | NIP6(fl->dst), |
638 | fl->opt ? fl->opt->opt_nflen : 0); | 646 | fl->opt ? fl->opt->opt_nflen : 0); |
639 | fl = fl->next; | ||
640 | } | 647 | } |
641 | } | ||
642 | |||
643 | static int ip6fl_seq_show(struct seq_file *seq, void *v) | ||
644 | { | ||
645 | if (v == SEQ_START_TOKEN) | ||
646 | seq_printf(seq, "%-5s %-1s %-6s %-6s %-6s %-8s %-32s %s\n", | ||
647 | "Label", "S", "Owner", "Users", "Linger", "Expires", "Dst", "Opt"); | ||
648 | else | ||
649 | ip6fl_fl_seq_show(seq, v); | ||
650 | return 0; | 648 | return 0; |
651 | } | 649 | } |
652 | 650 | ||
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 4bc4e5b33794..d7c45a9c15fe 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig | |||
@@ -40,7 +40,7 @@ config IP6_NF_QUEUE | |||
40 | To compile it as a module, choose M here. If unsure, say N. | 40 | To compile it as a module, choose M here. If unsure, say N. |
41 | 41 | ||
42 | config IP6_NF_IPTABLES | 42 | config IP6_NF_IPTABLES |
43 | tristate "IP6 tables support (required for filtering/masq/NAT)" | 43 | tristate "IP6 tables support (required for filtering)" |
44 | depends on NETFILTER_XTABLES | 44 | depends on NETFILTER_XTABLES |
45 | help | 45 | help |
46 | ip6tables is a general, extensible packet identification framework. | 46 | ip6tables is a general, extensible packet identification framework. |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 53bf977cca63..167c2ea88f6b 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -586,12 +586,19 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size, | |||
586 | return -EINVAL; | 586 | return -EINVAL; |
587 | } | 587 | } |
588 | 588 | ||
589 | if (e->target_offset + sizeof(struct ip6t_entry_target) > | ||
590 | e->next_offset) | ||
591 | return -EINVAL; | ||
592 | |||
589 | j = 0; | 593 | j = 0; |
590 | ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j); | 594 | ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j); |
591 | if (ret != 0) | 595 | if (ret != 0) |
592 | goto cleanup_matches; | 596 | goto cleanup_matches; |
593 | 597 | ||
594 | t = ip6t_get_target(e); | 598 | t = ip6t_get_target(e); |
599 | ret = -EINVAL; | ||
600 | if (e->target_offset + t->u.target_size > e->next_offset) | ||
601 | goto cleanup_matches; | ||
595 | target = try_then_request_module(xt_find_target(AF_INET6, | 602 | target = try_then_request_module(xt_find_target(AF_INET6, |
596 | t->u.user.name, | 603 | t->u.user.name, |
597 | t->u.user.revision), | 604 | t->u.user.revision), |
@@ -751,19 +758,17 @@ translate_table(const char *name, | |||
751 | } | 758 | } |
752 | } | 759 | } |
753 | 760 | ||
754 | if (!mark_source_chains(newinfo, valid_hooks, entry0)) | ||
755 | return -ELOOP; | ||
756 | |||
757 | /* Finally, each sanity check must pass */ | 761 | /* Finally, each sanity check must pass */ |
758 | i = 0; | 762 | i = 0; |
759 | ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size, | 763 | ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size, |
760 | check_entry, name, size, &i); | 764 | check_entry, name, size, &i); |
761 | 765 | ||
762 | if (ret != 0) { | 766 | if (ret != 0) |
763 | IP6T_ENTRY_ITERATE(entry0, newinfo->size, | 767 | goto cleanup; |
764 | cleanup_entry, &i); | 768 | |
765 | return ret; | 769 | ret = -ELOOP; |
766 | } | 770 | if (!mark_source_chains(newinfo, valid_hooks, entry0)) |
771 | goto cleanup; | ||
767 | 772 | ||
768 | /* And one copy for every other CPU */ | 773 | /* And one copy for every other CPU */ |
769 | for_each_possible_cpu(i) { | 774 | for_each_possible_cpu(i) { |
@@ -771,6 +776,9 @@ translate_table(const char *name, | |||
771 | memcpy(newinfo->entries[i], entry0, newinfo->size); | 776 | memcpy(newinfo->entries[i], entry0, newinfo->size); |
772 | } | 777 | } |
773 | 778 | ||
779 | return 0; | ||
780 | cleanup: | ||
781 | IP6T_ENTRY_ITERATE(entry0, newinfo->size, cleanup_entry, &i); | ||
774 | return ret; | 782 | return ret; |
775 | } | 783 | } |
776 | 784 | ||
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index d09329ca3267..d6dedc4aec77 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -604,7 +604,7 @@ error: | |||
604 | return err; | 604 | return err; |
605 | } | 605 | } |
606 | 606 | ||
607 | static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | 607 | static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) |
608 | { | 608 | { |
609 | struct iovec *iov; | 609 | struct iovec *iov; |
610 | u8 __user *type = NULL; | 610 | u8 __user *type = NULL; |
@@ -616,7 +616,7 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
616 | int i; | 616 | int i; |
617 | 617 | ||
618 | if (!msg->msg_iov) | 618 | if (!msg->msg_iov) |
619 | return; | 619 | return 0; |
620 | 620 | ||
621 | for (i = 0; i < msg->msg_iovlen; i++) { | 621 | for (i = 0; i < msg->msg_iovlen; i++) { |
622 | iov = &msg->msg_iov[i]; | 622 | iov = &msg->msg_iov[i]; |
@@ -638,8 +638,9 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
638 | code = iov->iov_base; | 638 | code = iov->iov_base; |
639 | 639 | ||
640 | if (type && code) { | 640 | if (type && code) { |
641 | get_user(fl->fl_icmp_type, type); | 641 | if (get_user(fl->fl_icmp_type, type) || |
642 | get_user(fl->fl_icmp_code, code); | 642 | get_user(fl->fl_icmp_code, code)) |
643 | return -EFAULT; | ||
643 | probed = 1; | 644 | probed = 1; |
644 | } | 645 | } |
645 | break; | 646 | break; |
@@ -650,7 +651,8 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
650 | /* check if type field is readable or not. */ | 651 | /* check if type field is readable or not. */ |
651 | if (iov->iov_len > 2 - len) { | 652 | if (iov->iov_len > 2 - len) { |
652 | u8 __user *p = iov->iov_base; | 653 | u8 __user *p = iov->iov_base; |
653 | get_user(fl->fl_mh_type, &p[2 - len]); | 654 | if (get_user(fl->fl_mh_type, &p[2 - len])) |
655 | return -EFAULT; | ||
654 | probed = 1; | 656 | probed = 1; |
655 | } else | 657 | } else |
656 | len += iov->iov_len; | 658 | len += iov->iov_len; |
@@ -664,6 +666,7 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
664 | if (probed) | 666 | if (probed) |
665 | break; | 667 | break; |
666 | } | 668 | } |
669 | return 0; | ||
667 | } | 670 | } |
668 | 671 | ||
669 | static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | 672 | static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, |
@@ -787,7 +790,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
787 | opt = ipv6_fixup_options(&opt_space, opt); | 790 | opt = ipv6_fixup_options(&opt_space, opt); |
788 | 791 | ||
789 | fl.proto = proto; | 792 | fl.proto = proto; |
790 | rawv6_probe_proto_opt(&fl, msg); | 793 | err = rawv6_probe_proto_opt(&fl, msg); |
794 | if (err) | ||
795 | goto out; | ||
791 | 796 | ||
792 | ipv6_addr_copy(&fl.fl6_dst, daddr); | 797 | ipv6_addr_copy(&fl.fl6_dst, daddr); |
793 | if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) | 798 | if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 093b3ddc513c..836541e509fe 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -1520,9 +1520,10 @@ get_next_corpse(int (*iter)(struct nf_conn *i, void *data), | |||
1520 | if (iter(ct, data)) | 1520 | if (iter(ct, data)) |
1521 | goto found; | 1521 | goto found; |
1522 | } | 1522 | } |
1523 | write_unlock_bh(&nf_conntrack_lock); | ||
1523 | return NULL; | 1524 | return NULL; |
1524 | found: | 1525 | found: |
1525 | atomic_inc(&nf_ct_tuplehash_to_ctrack(h)->ct_general.use); | 1526 | atomic_inc(&ct->ct_general.use); |
1526 | write_unlock_bh(&nf_conntrack_lock); | 1527 | write_unlock_bh(&nf_conntrack_lock); |
1527 | return ct; | 1528 | return ct; |
1528 | } | 1529 | } |
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index d56e0d21f919..d527c8977b1f 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -1075,8 +1075,9 @@ static int netlink_getsockopt(struct socket *sock, int level, int optname, | |||
1075 | return -EINVAL; | 1075 | return -EINVAL; |
1076 | len = sizeof(int); | 1076 | len = sizeof(int); |
1077 | val = nlk->flags & NETLINK_RECV_PKTINFO ? 1 : 0; | 1077 | val = nlk->flags & NETLINK_RECV_PKTINFO ? 1 : 0; |
1078 | put_user(len, optlen); | 1078 | if (put_user(len, optlen) || |
1079 | put_user(val, optval); | 1079 | put_user(val, optval)) |
1080 | return -EFAULT; | ||
1080 | err = 0; | 1081 | err = 0; |
1081 | break; | 1082 | break; |
1082 | default: | 1083 | default: |
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 27329ce9c311..ed0445fe85e7 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
@@ -346,11 +346,18 @@ void sctp_association_free(struct sctp_association *asoc) | |||
346 | struct list_head *pos, *temp; | 346 | struct list_head *pos, *temp; |
347 | int i; | 347 | int i; |
348 | 348 | ||
349 | list_del(&asoc->asocs); | 349 | /* Only real associations count against the endpoint, so |
350 | * don't bother for if this is a temporary association. | ||
351 | */ | ||
352 | if (!asoc->temp) { | ||
353 | list_del(&asoc->asocs); | ||
350 | 354 | ||
351 | /* Decrement the backlog value for a TCP-style listening socket. */ | 355 | /* Decrement the backlog value for a TCP-style listening |
352 | if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) | 356 | * socket. |
353 | sk->sk_ack_backlog--; | 357 | */ |
358 | if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) | ||
359 | sk->sk_ack_backlog--; | ||
360 | } | ||
354 | 361 | ||
355 | /* Mark as dead, so other users can know this structure is | 362 | /* Mark as dead, so other users can know this structure is |
356 | * going away. | 363 | * going away. |
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 35c49ff2d062..9b6b394b66f6 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c | |||
@@ -144,6 +144,13 @@ void sctp_endpoint_add_asoc(struct sctp_endpoint *ep, | |||
144 | { | 144 | { |
145 | struct sock *sk = ep->base.sk; | 145 | struct sock *sk = ep->base.sk; |
146 | 146 | ||
147 | /* If this is a temporary association, don't bother | ||
148 | * since we'll be removing it shortly and don't | ||
149 | * want anyone to find it anyway. | ||
150 | */ | ||
151 | if (asoc->temp) | ||
152 | return; | ||
153 | |||
147 | /* Now just add it to our list of asocs */ | 154 | /* Now just add it to our list of asocs */ |
148 | list_add_tail(&asoc->asocs, &ep->asocs); | 155 | list_add_tail(&asoc->asocs, &ep->asocs); |
149 | 156 | ||
diff --git a/net/sctp/input.c b/net/sctp/input.c index 64f630102532..6d82f400d13c 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c | |||
@@ -135,6 +135,9 @@ int sctp_rcv(struct sk_buff *skb) | |||
135 | 135 | ||
136 | SCTP_INC_STATS_BH(SCTP_MIB_INSCTPPACKS); | 136 | SCTP_INC_STATS_BH(SCTP_MIB_INSCTPPACKS); |
137 | 137 | ||
138 | if (skb_linearize(skb)) | ||
139 | goto discard_it; | ||
140 | |||
138 | sh = (struct sctphdr *) skb->h.raw; | 141 | sh = (struct sctphdr *) skb->h.raw; |
139 | 142 | ||
140 | /* Pull up the IP and SCTP headers. */ | 143 | /* Pull up the IP and SCTP headers. */ |
@@ -768,6 +771,9 @@ static void __sctp_hash_established(struct sctp_association *asoc) | |||
768 | /* Add an association to the hash. Local BH-safe. */ | 771 | /* Add an association to the hash. Local BH-safe. */ |
769 | void sctp_hash_established(struct sctp_association *asoc) | 772 | void sctp_hash_established(struct sctp_association *asoc) |
770 | { | 773 | { |
774 | if (asoc->temp) | ||
775 | return; | ||
776 | |||
771 | sctp_local_bh_disable(); | 777 | sctp_local_bh_disable(); |
772 | __sctp_hash_established(asoc); | 778 | __sctp_hash_established(asoc); |
773 | sctp_local_bh_enable(); | 779 | sctp_local_bh_enable(); |
@@ -801,6 +807,9 @@ static void __sctp_unhash_established(struct sctp_association *asoc) | |||
801 | /* Remove association from the hash table. Local BH-safe. */ | 807 | /* Remove association from the hash table. Local BH-safe. */ |
802 | void sctp_unhash_established(struct sctp_association *asoc) | 808 | void sctp_unhash_established(struct sctp_association *asoc) |
803 | { | 809 | { |
810 | if (asoc->temp) | ||
811 | return; | ||
812 | |||
804 | sctp_local_bh_disable(); | 813 | sctp_local_bh_disable(); |
805 | __sctp_unhash_established(asoc); | 814 | __sctp_unhash_established(asoc); |
806 | sctp_local_bh_enable(); | 815 | sctp_local_bh_enable(); |
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index fac7674438a4..5b4f82fd98f8 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c | |||
@@ -591,7 +591,7 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk, | |||
591 | newinet->dport = htons(asoc->peer.port); | 591 | newinet->dport = htons(asoc->peer.port); |
592 | newinet->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr; | 592 | newinet->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr; |
593 | newinet->pmtudisc = inet->pmtudisc; | 593 | newinet->pmtudisc = inet->pmtudisc; |
594 | newinet->id = 0; | 594 | newinet->id = asoc->next_tsn ^ jiffies; |
595 | 595 | ||
596 | newinet->uc_ttl = -1; | 596 | newinet->uc_ttl = -1; |
597 | newinet->mc_loop = 1; | 597 | newinet->mc_loop = 1; |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 9f34dec6ff8e..935bc9187fd8 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -3372,6 +3372,7 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc, | |||
3372 | { | 3372 | { |
3373 | struct sock *sk = asoc->base.sk; | 3373 | struct sock *sk = asoc->base.sk; |
3374 | struct socket *sock; | 3374 | struct socket *sock; |
3375 | struct inet_sock *inetsk; | ||
3375 | int err = 0; | 3376 | int err = 0; |
3376 | 3377 | ||
3377 | /* An association cannot be branched off from an already peeled-off | 3378 | /* An association cannot be branched off from an already peeled-off |
@@ -3389,6 +3390,14 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc, | |||
3389 | * asoc to the newsk. | 3390 | * asoc to the newsk. |
3390 | */ | 3391 | */ |
3391 | sctp_sock_migrate(sk, sock->sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH); | 3392 | sctp_sock_migrate(sk, sock->sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH); |
3393 | |||
3394 | /* Make peeled-off sockets more like 1-1 accepted sockets. | ||
3395 | * Set the daddr and initialize id to something more random | ||
3396 | */ | ||
3397 | inetsk = inet_sk(sock->sk); | ||
3398 | inetsk->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr; | ||
3399 | inetsk->id = asoc->next_tsn ^ jiffies; | ||
3400 | |||
3392 | *sockp = sock; | 3401 | *sockp = sock; |
3393 | 3402 | ||
3394 | return err; | 3403 | return err; |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 2b2e59d8ffbc..b43e7647e125 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -323,7 +323,7 @@ static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info * | |||
323 | x->props.replay_window = p->replay_window; | 323 | x->props.replay_window = p->replay_window; |
324 | x->props.reqid = p->reqid; | 324 | x->props.reqid = p->reqid; |
325 | x->props.family = p->family; | 325 | x->props.family = p->family; |
326 | x->props.saddr = p->saddr; | 326 | memcpy(&x->props.saddr, &p->saddr, sizeof(x->props.saddr)); |
327 | x->props.flags = p->flags; | 327 | x->props.flags = p->flags; |
328 | } | 328 | } |
329 | 329 | ||
@@ -545,7 +545,7 @@ static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) | |||
545 | memcpy(&p->lft, &x->lft, sizeof(p->lft)); | 545 | memcpy(&p->lft, &x->lft, sizeof(p->lft)); |
546 | memcpy(&p->curlft, &x->curlft, sizeof(p->curlft)); | 546 | memcpy(&p->curlft, &x->curlft, sizeof(p->curlft)); |
547 | memcpy(&p->stats, &x->stats, sizeof(p->stats)); | 547 | memcpy(&p->stats, &x->stats, sizeof(p->stats)); |
548 | p->saddr = x->props.saddr; | 548 | memcpy(&p->saddr, &x->props.saddr, sizeof(p->saddr)); |
549 | p->mode = x->props.mode; | 549 | p->mode = x->props.mode; |
550 | p->replay_window = x->props.replay_window; | 550 | p->replay_window = x->props.replay_window; |
551 | p->reqid = x->props.reqid; | 551 | p->reqid = x->props.reqid; |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index e9969a2fc846..8ab5679a37a3 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -3313,7 +3313,13 @@ static int selinux_socket_getpeername(struct socket *sock) | |||
3313 | 3313 | ||
3314 | static int selinux_socket_setsockopt(struct socket *sock,int level,int optname) | 3314 | static int selinux_socket_setsockopt(struct socket *sock,int level,int optname) |
3315 | { | 3315 | { |
3316 | return socket_has_perm(current, sock, SOCKET__SETOPT); | 3316 | int err; |
3317 | |||
3318 | err = socket_has_perm(current, sock, SOCKET__SETOPT); | ||
3319 | if (err) | ||
3320 | return err; | ||
3321 | |||
3322 | return selinux_netlbl_socket_setsockopt(sock, level, optname); | ||
3317 | } | 3323 | } |
3318 | 3324 | ||
3319 | static int selinux_socket_getsockopt(struct socket *sock, int level, | 3325 | static int selinux_socket_getsockopt(struct socket *sock, int level, |
diff --git a/security/selinux/include/selinux_netlabel.h b/security/selinux/include/selinux_netlabel.h index ecab4bddaaf4..9de10cc2cef2 100644 --- a/security/selinux/include/selinux_netlabel.h +++ b/security/selinux/include/selinux_netlabel.h | |||
@@ -53,6 +53,9 @@ void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec, | |||
53 | void selinux_netlbl_sk_clone_security(struct sk_security_struct *ssec, | 53 | void selinux_netlbl_sk_clone_security(struct sk_security_struct *ssec, |
54 | struct sk_security_struct *newssec); | 54 | struct sk_security_struct *newssec); |
55 | int selinux_netlbl_inode_permission(struct inode *inode, int mask); | 55 | int selinux_netlbl_inode_permission(struct inode *inode, int mask); |
56 | int selinux_netlbl_socket_setsockopt(struct socket *sock, | ||
57 | int level, | ||
58 | int optname); | ||
56 | #else | 59 | #else |
57 | static inline void selinux_netlbl_cache_invalidate(void) | 60 | static inline void selinux_netlbl_cache_invalidate(void) |
58 | { | 61 | { |
@@ -114,6 +117,13 @@ static inline int selinux_netlbl_inode_permission(struct inode *inode, | |||
114 | { | 117 | { |
115 | return 0; | 118 | return 0; |
116 | } | 119 | } |
120 | |||
121 | static inline int selinux_netlbl_socket_setsockopt(struct socket *sock, | ||
122 | int level, | ||
123 | int optname) | ||
124 | { | ||
125 | return 0; | ||
126 | } | ||
117 | #endif /* CONFIG_NETLABEL */ | 127 | #endif /* CONFIG_NETLABEL */ |
118 | 128 | ||
119 | #endif | 129 | #endif |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index b1f6fb36c699..bfe122764c98 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -2682,4 +2682,41 @@ u32 selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb) | |||
2682 | 2682 | ||
2683 | return peer_sid; | 2683 | return peer_sid; |
2684 | } | 2684 | } |
2685 | |||
2686 | /** | ||
2687 | * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel | ||
2688 | * @sock: the socket | ||
2689 | * @level: the socket level or protocol | ||
2690 | * @optname: the socket option name | ||
2691 | * | ||
2692 | * Description: | ||
2693 | * Check the setsockopt() call and if the user is trying to replace the IP | ||
2694 | * options on a socket and a NetLabel is in place for the socket deny the | ||
2695 | * access; otherwise allow the access. Returns zero when the access is | ||
2696 | * allowed, -EACCES when denied, and other negative values on error. | ||
2697 | * | ||
2698 | */ | ||
2699 | int selinux_netlbl_socket_setsockopt(struct socket *sock, | ||
2700 | int level, | ||
2701 | int optname) | ||
2702 | { | ||
2703 | int rc = 0; | ||
2704 | struct inode *inode = SOCK_INODE(sock); | ||
2705 | struct sk_security_struct *sksec = sock->sk->sk_security; | ||
2706 | struct inode_security_struct *isec = inode->i_security; | ||
2707 | struct netlbl_lsm_secattr secattr; | ||
2708 | |||
2709 | mutex_lock(&isec->lock); | ||
2710 | if (level == IPPROTO_IP && optname == IP_OPTIONS && | ||
2711 | sksec->nlbl_state == NLBL_LABELED) { | ||
2712 | netlbl_secattr_init(&secattr); | ||
2713 | rc = netlbl_socket_getattr(sock, &secattr); | ||
2714 | if (rc == 0 && (secattr.cache || secattr.mls_lvl_vld)) | ||
2715 | rc = -EACCES; | ||
2716 | netlbl_secattr_destroy(&secattr); | ||
2717 | } | ||
2718 | mutex_unlock(&isec->lock); | ||
2719 | |||
2720 | return rc; | ||
2721 | } | ||
2685 | #endif /* CONFIG_NETLABEL */ | 2722 | #endif /* CONFIG_NETLABEL */ |