GIT c6817e4c32d8c4118405d2dec30ac1c264349085 git+ssh://master.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6.git commit Author: James Morris Date: Mon Oct 30 18:56:06 2006 -0800 [IPV6]: return EINVAL for invalid address with flowlabel lease request Currently, when an application requests a lease for a flowlabel via the IPV6_FLOWLABEL_MGR socket option, no error is returned if an invalid type of destination address is supplied as part of the request, leading to a silent failure. This patch ensures that EINVAL is returned to the application in this case. Signed-off-by: James Morris Signed-off-by: David S. Miller commit de76e695a5ce19c121ba7e246b45f258be678a75 Author: Vlad Yasevich Date: Mon Oct 30 18:55:11 2006 -0800 [SCTP]: Remove temporary associations from backlog and hash. Every time SCTP creates a temporary association, the stack hashes it, puts it on a list of endpoint associations and increments the backlog. However, the lifetime of a temporary association is the processing time of a current packet and it's destroyed after that. In fact, we don't really want anyone else finding this association. There is no reason to do this extra work. Signed-off-by: Vlad Yasevich Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller commit 4f4443088b763ca4ac7521e9b4a881b52c294dec Author: Vlad Yasevich Date: Mon Oct 30 18:54:32 2006 -0800 [SCTP]: Correctly set IP id for SCTP traffic Make SCTP 1-1 style and peeled-off associations behave like TCP when setting IP id. In both cases, we set the inet_sk(sk)->daddr and initialize inet_sk(sk)->id to a random value. Signed-off-by: Vlad Yasevich Signed-off-by: Sridhar Samudrala Signed-off-by: David S. Miller commit f8687afefcc821fc47c75775eec87731fe3de360 Author: Paul Moore Date: Mon Oct 30 15:22:15 2006 -0800 [NetLabel]: protect the CIPSOv4 socket option from setsockopt() This patch makes two changes to protect applications from either removing or tampering with the CIPSOv4 IP option on a socket. The first is the requirement that applications have the CAP_NET_RAW capability to set an IPOPT_CIPSO option on a socket; this prevents untrusted applications from setting their own CIPSOv4 security attributes on the packets they send. The second change is to SELinux and it prevents applications from setting any IPv4 options when there is an IPOPT_CIPSO option already present on the socket; this prevents applications from removing CIPSOv4 security attributes from the packets they send. Signed-off-by: Paul Moore Signed-off-by: James Morris Signed-off-by: David S. Miller commit 920b868ae1dfdac77c5e8c97e7067b23680f043e Author: Dmitry Mishin Date: Mon Oct 30 15:14:27 2006 -0800 [NETFILTER]: ip_tables: compat code module refcounting fix This patch fixes bug in iptables modules refcounting on compat error way. As we are getting modules in check_compat_entry_size_and_hooks(), in case of later error, we should put them all in translate_compat_table(), not in the compat_copy_entry_from_user() or compat_copy_match_from_user(), as it is now. Signed-off-by: Dmitry Mishin Acked-by: Vasily Averin Acked-by: Kirill Korotaev Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit c073e3fa8b7f9841aa6451885f135656d455f511 Author: Martin Josefsson Date: Mon Oct 30 15:13:58 2006 -0800 [NETFILTER]: nf_conntrack: add missing unlock in get_next_corpse() Add missing unlock in get_next_corpse() in nf_conntrack. It was missed during the removal of listhelp.h . Also remove an unneeded use of nf_ct_tuplehash_to_ctrack() in the same function. Should be applied before 2.6.19 is released. Signed-off-by: Martin Josefsson Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit ef4512e76679b4f4997f60f93f8a576a0d20c26b Author: Vasily Averin Date: Mon Oct 30 15:13:28 2006 -0800 [NETFILTER]: ip_tables: compat error way cleanup This patch adds forgotten compat_flush_offset() call to error way of translate_compat_table(). May lead to table corruption on the next compat_do_replace(). Signed-off-by: Vasily Averin Acked-by: Dmitry Mishin Acked-by: Kirill Korotaev Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit 590bdf7fd2292b47c428111cb1360e312eff207e Author: Dmitry Mishin Date: Mon Oct 30 15:12:55 2006 -0800 [NETFILTER]: Missed and reordered checks in {arp,ip,ip6}_tables There is a number of issues in parsing user-provided table in translate_table(). Malicious user with CAP_NET_ADMIN may crash system by passing special-crafted table to the *_tables. The first issue is that mark_source_chains() function is called before entry content checks. In case of standard target, mark_source_chains() function uses t->verdict field in order to determine new position. But the check, that this field leads no further, than the table end, is in check_entry(), which is called later, than mark_source_chains(). The second issue, that there is no check that target_offset points inside entry. If so, *_ITERATE_MATCH macro will follow further, than the entry ends. As a result, we'll have oops or memory disclosure. And the third issue, that there is no check that the target is completely inside entry. Results are the same, as in previous issue. Signed-off-by: Dmitry Mishin Acked-by: Kirill Korotaev Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit 844dc7c88046ecd2e52596730d7cc400d6c3ad67 Author: Patrick McHardy Date: Mon Oct 30 15:12:16 2006 -0800 [NETFILTER]: remove masq/NAT from ip6tables Kconfig help Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller commit bcd620757d3a4ae78ef0ca41adb5d9e400ed92b6 Author: James Morris Date: Mon Oct 30 15:08:42 2006 -0800 [IPV6]: fix lockup via /proc/net/ip6_flowlabel There's a bug in the seqfile handling for /proc/net/ip6_flowlabel, where, after finding a flowlabel, the code will loop forever not finding any further flowlabels, first traversing the rest of the hash bucket then just looping. This patch fixes the problem by breaking after the hash bucket has been traversed. Note that this bug can cause lockups and oopses, and is trivially invoked by an unpriveleged user. Signed-off-by: James Morris Signed-off-by: David S. Miller commit a27b58fed90cc5654e2daf1d292cc5bc61be4dd7 Author: Heiko Carstens Date: Mon Oct 30 15:06:12 2006 -0800 [NET]: fix uaccess handling Signed-off-by: Heiko Carstens Signed-off-by: David S. Miller commit 28cd7752734563d5b0967b96a6bade7a1dc89c7f Author: Herbert Xu Date: Sun Oct 29 23:46:42 2006 -0800 [SCTP]: Always linearise packet on input I was looking at a RHEL5 bug report involving Xen and SCTP (https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=212550). It turns out that SCTP wasn't written to handle skb fragments at all. The absence of any calls to skb_may_pull is testament to that. It just so happens that Xen creates fragmented packets more often than other scenarios (header & data split when going from domU to dom0). That's what caused this bug to show up. Until someone has the time sits down and audits the entire net/sctp directory, here is a conservative and safe solution that simply linearises all packets on input. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller commit c20e3945c761502b9d5d73ef0ff5f1a84b3a717e Author: David S. Miller Date: Sun Oct 29 16:14:55 2006 -0800 [ETH1394]: Fix unaligned accesses. Several u64 objects are derefernced in situations where the pointer is not guarenteed to be aligned correctly. Use get_unaligned() as needed. Thanks to Will Simoneau for lots of testing and debugging help. Signed-off-by: David S. Miller Acked-by: Stefan Richter commit 234af4840135342ab295b4e1219fd35c27fdd439 Author: Randy Dunlap Date: Sun Oct 29 16:03:30 2006 -0800 [DCCP]: fix printk format warnings Fix printk format warnings: build2.out:net/dccp/ccids/ccid2.c:355: warning: long long unsigned int format, u64 arg (arg 3) build2.out:net/dccp/ccids/ccid2.c:360: warning: long long unsigned int format, u64 arg (arg 3) build2.out:net/dccp/ccids/ccid2.c:482: warning: long long unsigned int format, u64 arg (arg 5) build2.out:net/dccp/ccids/ccid2.c:639: warning: long long unsigned int format, u64 arg (arg 3) build2.out:net/dccp/ccids/ccid2.c:639: warning: long long unsigned int format, u64 arg (arg 4) build2.out:net/dccp/ccids/ccid2.c:674: warning: long long unsigned int format, u64 arg (arg 3) build2.out:net/dccp/ccids/ccid2.c:720: warning: long long unsigned int format, u64 arg (arg 3) Signed-off-by: Randy Dunlap Signed-off-by: David S. Miller commit c8884edd078748905552d667857259e5358e1232 Author: Herbert Xu Date: Sun Oct 29 15:59:41 2006 -0800 [NET]: Fix segmentation of linear packets skb_segment fails to segment linear packets correctly because it tries to write all linear parts of the original skb into each segment. This will always panic as each segment only contains enough space for one MSS. This was not detected earlier because linear packets should be rare for GSO. In fact it still remains to be seen what exactly created the linear packets that triggered this bug. Basically the only time this should happen is if someone enables GSO emulation on an interface that does not support SG. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller commit 54489c14c058822f7019648b3718bd3820dee802 Author: David S. Miller Date: Fri Oct 27 15:29:47 2006 -0700 [XFRM] xfrm_user: Fix unaligned accesses. Use memcpy() to move xfrm_address_t objects in and out of netlink messages. The vast majority of xfrm_user was doing this properly, except for copy_from_user_state() and copy_to_user_state(). Signed-off-by: David S. Miller commit 201a95afaa324b23188eeec268f6bb0b4b70b710 Author: David S. Miller Date: Fri Oct 27 15:26:21 2006 -0700 [APPLETALK]: Fix potential OOPS in atalk_sendmsg(). atrtr_find() can return NULL, so do not blindly dereference rt->dev before we check for rt being NULL. Signed-off-by: David S. Miller commit d458fd82c9bb536e4a582955e88554a02a92bf78 Author: Randy Dunlap Date: Thu Oct 26 17:15:20 2006 -0700 [NET] sealevel: uses arp_broken_ops On Wed, 25 Oct 2006 18:03:13 +0200 Toralf Förster wrote: > WARNING: "arp_broken_ops" [drivers/net/wan/sealevel.ko] undefined! > make[1]: *** [__modpost] Error 1 > make: *** [modules] Error 2 > > Here's the config: ... > # CONFIG_INET is not set > CONFIG_SEALEVEL_4021=m Sealevel uses arp_broken_ops so it needs to depend on INET. Signed-off-by: Randy Dunlap Signed-off-by: David S. Miller drivers/ieee1394/eth1394.c | 20 +++++--- drivers/net/wan/Kconfig | 2 - net/appletalk/ddp.c | 2 - net/core/skbuff.c | 9 ++-- net/dccp/ccids/ccid2.c | 18 ++++--- net/ipv4/cipso_ipv4.c | 7 +-- net/ipv4/ip_options.c | 2 - net/ipv4/netfilter/arp_tables.c | 25 ++++++---- net/ipv4/netfilter/ip_tables.c | 67 ++++++++++++++------------- net/ipv4/raw.c | 17 ++++--- net/ipv6/ip6_flowlabel.c | 6 ++ net/ipv6/netfilter/Kconfig | 2 - net/ipv6/netfilter/ip6_tables.c | 24 ++++++---- net/ipv6/raw.c | 17 ++++--- net/netfilter/nf_conntrack_core.c | 3 + net/netlink/af_netlink.c | 5 +- net/sctp/associola.c | 15 ++++-- net/sctp/endpointola.c | 7 +++ net/sctp/input.c | 9 ++++ net/sctp/protocol.c | 2 - net/sctp/socket.c | 9 ++++ net/xfrm/xfrm_user.c | 4 +- security/selinux/hooks.c | 8 +++ security/selinux/include/selinux_netlabel.h | 10 ++++ security/selinux/ss/services.c | 37 +++++++++++++++ 25 files changed, 223 insertions(+), 104 deletions(-) diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 8a7b8fa..31e5cc4 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -64,6 +64,7 @@ #include #include #include #include +#include #include #include "config_roms.h" @@ -491,7 +492,7 @@ static void ether1394_reset_priv (struct int i; struct eth1394_priv *priv = netdev_priv(dev); struct hpsb_host *host = priv->host; - u64 guid = *((u64*)&(host->csr.rom->bus_info_data[3])); + u64 guid = get_unaligned((u64*)&(host->csr.rom->bus_info_data[3])); u16 maxpayload = 1 << (host->csr.max_rec + 1); int max_speed = IEEE1394_SPEED_MAX; @@ -514,8 +515,8 @@ static void ether1394_reset_priv (struct ETHER1394_GASP_OVERHEAD))); /* Set our hardware address while we're at it */ - *(u64*)dev->dev_addr = guid; - *(u64*)dev->broadcast = ~0x0ULL; + memcpy(dev->dev_addr, &guid, sizeof(u64)); + memset(dev->broadcast, 0xff, sizeof(u64)); } spin_unlock_irqrestore (&priv->lock, flags); @@ -894,6 +895,7 @@ static inline u16 ether1394_parse_encap( u16 maxpayload; struct eth1394_node_ref *node; struct eth1394_node_info *node_info; + __be64 guid; /* Sanity check. MacOSX seems to be sending us 131 in this * field (atleast on my Panther G5). Not sure why. */ @@ -902,8 +904,9 @@ static inline u16 ether1394_parse_encap( maxpayload = min(eth1394_speedto_maxpayload[sspd], (u16)(1 << (max_rec + 1))); + guid = get_unaligned(&arp1394->s_uniq_id); node = eth1394_find_node_guid(&priv->ip_node_list, - be64_to_cpu(arp1394->s_uniq_id)); + be64_to_cpu(guid)); if (!node) { return 0; } @@ -931,10 +934,9 @@ static inline u16 ether1394_parse_encap( arp_ptr += arp->ar_pln; /* skip over sender IP addr */ if (arp->ar_op == htons(ARPOP_REQUEST)) - /* just set ARP req target unique ID to 0 */ - *((u64*)arp_ptr) = 0; + memset(arp_ptr, 0, sizeof(u64)); else - *((u64*)arp_ptr) = *((u64*)dev->dev_addr); + memcpy(arp_ptr, dev->dev_addr, sizeof(u64)); } /* Now add the ethernet header. */ @@ -1675,8 +1677,10 @@ #endif if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF]) priv->bc_dgl++; } else { + __be64 guid = get_unaligned((u64 *)eth->h_dest); + node = eth1394_find_node_guid(&priv->ip_node_list, - be64_to_cpu(*(u64*)eth->h_dest)); + be64_to_cpu(guid)); if (!node) { ret = -EAGAIN; goto fail; diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 58b7efb..b5d0d7f 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -127,7 +127,7 @@ config LANMEDIA # There is no way to detect a Sealevel board. Force it modular config SEALEVEL_4021 tristate "Sealevel Systems 4021 support" - depends on WAN && ISA && m && ISA_DMA_API + depends on WAN && ISA && m && ISA_DMA_API && INET help This is a driver for the Sealevel Systems ACB 56 serial I/O adapter. diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 708e2e0..485e35c 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1584,7 +1584,6 @@ #endif if (usat->sat_addr.s_net || usat->sat_addr.s_node == ATADDR_ANYNODE) { rt = atrtr_find(&usat->sat_addr); - dev = rt->dev; } else { struct atalk_addr at_hint; @@ -1592,7 +1591,6 @@ #endif at_hint.s_net = at->src_net; rt = atrtr_find(&at_hint); - dev = rt->dev; } if (!rt) return -ENETUNREACH; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 3c23760..f735455 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1946,7 +1946,7 @@ struct sk_buff *skb_segment(struct sk_bu do { struct sk_buff *nskb; skb_frag_t *frag; - int hsize, nsize; + int hsize; int k; int size; @@ -1957,11 +1957,10 @@ struct sk_buff *skb_segment(struct sk_bu hsize = skb_headlen(skb) - offset; if (hsize < 0) hsize = 0; - nsize = hsize + doffset; - if (nsize > len + doffset || !sg) - nsize = len + doffset; + if (hsize > len || !sg) + hsize = len; - nskb = alloc_skb(nsize + headroom, GFP_ATOMIC); + nskb = alloc_skb(hsize + doffset + headroom, GFP_ATOMIC); if (unlikely(!nskb)) goto err; diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index 2fbb84b..162032b 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c @@ -352,14 +352,14 @@ static void ccid2_hc_tx_packet_sent(stru #ifdef CONFIG_IP_DCCP_CCID2_DEBUG ccid2_pr_debug("pipe=%d\n", hctx->ccid2hctx_pipe); - ccid2_pr_debug("Sent: seq=%llu\n", seq); + ccid2_pr_debug("Sent: seq=%llu\n", (unsigned long long)seq); do { struct ccid2_seq *seqp = hctx->ccid2hctx_seqt; while (seqp != hctx->ccid2hctx_seqh) { ccid2_pr_debug("out seq=%llu acked=%d time=%lu\n", - seqp->ccid2s_seq, seqp->ccid2s_acked, - seqp->ccid2s_sent); + (unsigned long long)seqp->ccid2s_seq, + seqp->ccid2s_acked, seqp->ccid2s_sent); seqp = seqp->ccid2s_next; } } while (0); @@ -480,7 +480,8 @@ static inline void ccid2_new_ack(struct /* first measurement */ if (hctx->ccid2hctx_srtt == -1) { ccid2_pr_debug("R: %lu Time=%lu seq=%llu\n", - r, jiffies, seqp->ccid2s_seq); + r, jiffies, + (unsigned long long)seqp->ccid2s_seq); ccid2_change_srtt(hctx, r); hctx->ccid2hctx_rttvar = r >> 1; } else { @@ -636,8 +637,9 @@ static void ccid2_hc_tx_packet_recv(stru u64 ackno_end_rl; dccp_set_seqno(&ackno_end_rl, ackno - rl); - ccid2_pr_debug("ackvec start:%llu end:%llu\n", ackno, - ackno_end_rl); + ccid2_pr_debug("ackvec start:%llu end:%llu\n", + (unsigned long long)ackno, + (unsigned long long)ackno_end_rl); /* if the seqno we are analyzing is larger than the * current ackno, then move towards the tail of our * seqnos. @@ -672,7 +674,7 @@ static void ccid2_hc_tx_packet_recv(stru seqp->ccid2s_acked = 1; ccid2_pr_debug("Got ack for %llu\n", - seqp->ccid2s_seq); + (unsigned long long)seqp->ccid2s_seq); ccid2_hc_tx_dec_pipe(sk); } if (seqp == hctx->ccid2hctx_seqt) { @@ -718,7 +720,7 @@ static void ccid2_hc_tx_packet_recv(stru while (1) { if (!seqp->ccid2s_acked) { ccid2_pr_debug("Packet lost: %llu\n", - seqp->ccid2s_seq); + (unsigned long long)seqp->ccid2s_seq); /* XXX need to traverse from tail -> head in * order to detect multiple congestion events in * one ack vector. diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index e2077a3..6460233 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -1307,7 +1307,8 @@ int cipso_v4_socket_setattr(const struct /* We can't use ip_options_get() directly because it makes a call to * ip_options_get_alloc() which allocates memory with GFP_KERNEL and - * we can't block here. */ + * we won't always have CAP_NET_RAW even though we _always_ want to + * set the IPOPT_CIPSO option. */ opt_len = (buf_len + 3) & ~3; opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC); if (opt == NULL) { @@ -1317,11 +1318,9 @@ int cipso_v4_socket_setattr(const struct memcpy(opt->__data, buf, buf_len); opt->optlen = opt_len; opt->is_data = 1; + opt->cipso = sizeof(struct iphdr); kfree(buf); buf = NULL; - ret_val = ip_options_compile(opt, NULL); - if (ret_val != 0) - goto socket_setattr_failure; sk_inet = inet_sk(sk); if (sk_inet->is_icsk) { diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 8dabbfc..9f02917 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->router_alert = optptr - iph; break; case IPOPT_CIPSO: - if (opt->cipso) { + if ((!skb && !capable(CAP_NET_RAW)) || opt->cipso) { pp_ptr = optptr; goto error; } diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 0849f1c..413c2d0 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 arp return -EINVAL; } + if (e->target_offset + sizeof(struct arpt_entry_target) > e->next_offset) + return -EINVAL; + t = arpt_get_target(e); + if (e->target_offset + t->u.target_size > e->next_offset) + return -EINVAL; + target = try_then_request_module(xt_find_target(NF_ARP, t->u.user.name, t->u.user.revision), "arpt_%s", t->u.user.name); @@ -621,20 +627,18 @@ static int translate_table(const char *n } } - if (!mark_source_chains(newinfo, valid_hooks, entry0)) { - duprintf("Looping hook\n"); - return -ELOOP; - } - /* Finally, each sanity check must pass */ i = 0; ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size, check_entry, name, size, &i); - if (ret != 0) { - ARPT_ENTRY_ITERATE(entry0, newinfo->size, - cleanup_entry, &i); - return ret; + if (ret != 0) + goto cleanup; + + ret = -ELOOP; + if (!mark_source_chains(newinfo, valid_hooks, entry0)) { + duprintf("Looping hook\n"); + goto cleanup; } /* And one copy for every other CPU */ @@ -643,6 +647,9 @@ static int translate_table(const char *n memcpy(newinfo->entries[i], entry0, newinfo->size); } + return 0; +cleanup: + ARPT_ENTRY_ITERATE(entry0, newinfo->size, cleanup_entry, &i); return ret; } diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 4b90927..8a45543 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 c return -EINVAL; } + if (e->target_offset + sizeof(struct ipt_entry_target) > e->next_offset) + return -EINVAL; + j = 0; ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j); if (ret != 0) goto cleanup_matches; t = ipt_get_target(e); + ret = -EINVAL; + if (e->target_offset + t->u.target_size > e->next_offset) + goto cleanup_matches; target = try_then_request_module(xt_find_target(AF_INET, t->u.user.name, t->u.user.revision), @@ -712,19 +718,17 @@ translate_table(const char *name, } } - if (!mark_source_chains(newinfo, valid_hooks, entry0)) - return -ELOOP; - /* Finally, each sanity check must pass */ i = 0; ret = IPT_ENTRY_ITERATE(entry0, newinfo->size, check_entry, name, size, &i); - if (ret != 0) { - IPT_ENTRY_ITERATE(entry0, newinfo->size, - cleanup_entry, &i); - return ret; - } + if (ret != 0) + goto cleanup; + + ret = -ELOOP; + if (!mark_source_chains(newinfo, valid_hooks, entry0)) + goto cleanup; /* And one copy for every other CPU */ for_each_possible_cpu(i) { @@ -732,6 +736,9 @@ translate_table(const char *name, memcpy(newinfo->entries[i], entry0, newinfo->size); } + return 0; +cleanup: + IPT_ENTRY_ITERATE(entry0, newinfo->size, cleanup_entry, &i); return ret; } @@ -1463,6 +1470,10 @@ check_compat_entry_size_and_hooks(struct return -EINVAL; } + if (e->target_offset + sizeof(struct compat_xt_entry_target) > + e->next_offset) + return -EINVAL; + off = 0; entry_offset = (void *)e - (void *)base; j = 0; @@ -1472,6 +1483,9 @@ check_compat_entry_size_and_hooks(struct goto cleanup_matches; t = ipt_get_target(e); + ret = -EINVAL; + if (e->target_offset + t->u.target_size > e->next_offset) + goto cleanup_matches; target = try_then_request_module(xt_find_target(AF_INET, t->u.user.name, t->u.user.revision), @@ -1513,7 +1527,7 @@ cleanup_matches: static inline int compat_copy_match_from_user(struct ipt_entry_match *m, void **dstptr, compat_uint_t *size, const char *name, - const struct ipt_ip *ip, unsigned int hookmask, int *i) + const struct ipt_ip *ip, unsigned int hookmask) { struct ipt_entry_match *dm; struct ipt_match *match; @@ -1526,22 +1540,13 @@ static inline int compat_copy_match_from ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm), name, hookmask, ip->proto, ip->invflags & IPT_INV_PROTO); - if (ret) - goto err; - - if (m->u.kernel.match->checkentry + if (!ret && m->u.kernel.match->checkentry && !m->u.kernel.match->checkentry(name, ip, match, dm->data, hookmask)) { duprintf("ip_tables: check failed for `%s'.\n", m->u.kernel.match->name); ret = -EINVAL; - goto err; } - (*i)++; - return 0; - -err: - module_put(m->u.kernel.match->me); return ret; } @@ -1553,19 +1558,18 @@ static int compat_copy_entry_from_user(s struct ipt_target *target; struct ipt_entry *de; unsigned int origsize; - int ret, h, j; + int ret, h; ret = 0; origsize = *size; de = (struct ipt_entry *)*dstptr; memcpy(de, e, sizeof(struct ipt_entry)); - j = 0; *dstptr += sizeof(struct compat_ipt_entry); ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size, - name, &de->ip, de->comefrom, &j); + name, &de->ip, de->comefrom); if (ret) - goto cleanup_matches; + goto err; de->target_offset = e->target_offset - (origsize - *size); t = ipt_get_target(e); target = t->u.kernel.target; @@ -1599,12 +1603,7 @@ static int compat_copy_entry_from_user(s goto err; } ret = 0; - return ret; - err: - module_put(t->u.kernel.target->me); -cleanup_matches: - IPT_MATCH_ITERATE(e, cleanup_match, &j); return ret; } @@ -1618,7 +1617,7 @@ translate_compat_table(const char *name, unsigned int *hook_entries, unsigned int *underflows) { - unsigned int i; + unsigned int i, j; struct xt_table_info *newinfo, *info; void *pos, *entry0, *entry1; unsigned int size; @@ -1636,21 +1635,21 @@ translate_compat_table(const char *name, } duprintf("translate_compat_table: size %u\n", info->size); - i = 0; + j = 0; xt_compat_lock(AF_INET); /* Walk through entries, checking offsets. */ ret = IPT_ENTRY_ITERATE(entry0, total_size, check_compat_entry_size_and_hooks, info, &size, entry0, entry0 + total_size, - hook_entries, underflows, &i, name); + hook_entries, underflows, &j, name); if (ret != 0) goto out_unlock; ret = -EINVAL; - if (i != number) { + if (j != number) { duprintf("translate_compat_table: %u not %u entries\n", - i, number); + j, number); goto out_unlock; } @@ -1709,8 +1708,10 @@ translate_compat_table(const char *name, free_newinfo: xt_free_table_info(newinfo); out: + IPT_ENTRY_ITERATE(entry0, total_size, cleanup_entry, &j); return ret; out_unlock: + compat_flush_offsets(); xt_compat_unlock(AF_INET); goto out; } diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index b430cf2..5c31dea 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -329,7 +329,7 @@ error: return err; } -static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg) +static int raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg) { struct iovec *iov; u8 __user *type = NULL; @@ -338,7 +338,7 @@ static void raw_probe_proto_opt(struct f unsigned int i; if (!msg->msg_iov) - return; + return 0; for (i = 0; i < msg->msg_iovlen; i++) { iov = &msg->msg_iov[i]; @@ -360,8 +360,9 @@ static void raw_probe_proto_opt(struct f code = iov->iov_base; if (type && code) { - get_user(fl->fl_icmp_type, type); - get_user(fl->fl_icmp_code, code); + if (get_user(fl->fl_icmp_type, type) || + get_user(fl->fl_icmp_code, code)) + return -EFAULT; probed = 1; } break; @@ -372,6 +373,7 @@ static void raw_probe_proto_opt(struct f if (probed) break; } + return 0; } static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, @@ -480,8 +482,11 @@ static int raw_sendmsg(struct kiocb *ioc .proto = inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, }; - if (!inet->hdrincl) - raw_probe_proto_opt(&fl, msg); + if (!inet->hdrincl) { + err = raw_probe_proto_opt(&fl, msg); + if (err) + goto done; + } security_sk_classify_flow(sk, &fl); 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 1d672b0..2b45f2d 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -330,8 +330,10 @@ fl_create(struct in6_flowlabel_req *freq fl->share = freq->flr_share; addr_type = ipv6_addr_type(&freq->flr_dst); if ((addr_type&IPV6_ADDR_MAPPED) - || addr_type == IPV6_ADDR_ANY) + || addr_type == IPV6_ADDR_ANY) { + err = -EINVAL; goto done; + } ipv6_addr_copy(&fl->dst, &freq->flr_dst); atomic_set(&fl->users, 1); switch (fl->share) { @@ -587,6 +589,8 @@ static struct ip6_flowlabel *ip6fl_get_n while (!fl) { if (++state->bucket <= FL_HASH_MASK) fl = fl_ht[state->bucket]; + else + break; } return fl; } diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 4bc4e5b..d7c45a9 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig @@ -40,7 +40,7 @@ config IP6_NF_QUEUE To compile it as a module, choose M here. If unsure, say N. config IP6_NF_IPTABLES - tristate "IP6 tables support (required for filtering/masq/NAT)" + tristate "IP6 tables support (required for filtering)" depends on NETFILTER_XTABLES help 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 53bf977..167c2ea 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 return -EINVAL; } + if (e->target_offset + sizeof(struct ip6t_entry_target) > + e->next_offset) + return -EINVAL; + j = 0; ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j); if (ret != 0) goto cleanup_matches; t = ip6t_get_target(e); + ret = -EINVAL; + if (e->target_offset + t->u.target_size > e->next_offset) + goto cleanup_matches; target = try_then_request_module(xt_find_target(AF_INET6, t->u.user.name, t->u.user.revision), @@ -751,19 +758,17 @@ translate_table(const char *name, } } - if (!mark_source_chains(newinfo, valid_hooks, entry0)) - return -ELOOP; - /* Finally, each sanity check must pass */ i = 0; ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size, check_entry, name, size, &i); - if (ret != 0) { - IP6T_ENTRY_ITERATE(entry0, newinfo->size, - cleanup_entry, &i); - return ret; - } + if (ret != 0) + goto cleanup; + + ret = -ELOOP; + if (!mark_source_chains(newinfo, valid_hooks, entry0)) + goto cleanup; /* And one copy for every other CPU */ for_each_possible_cpu(i) { @@ -771,6 +776,9 @@ translate_table(const char *name, memcpy(newinfo->entries[i], entry0, newinfo->size); } + return 0; +cleanup: + IP6T_ENTRY_ITERATE(entry0, newinfo->size, cleanup_entry, &i); return ret; } diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index d09329c..d6dedc4 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -604,7 +604,7 @@ error: return err; } -static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) +static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) { struct iovec *iov; u8 __user *type = NULL; @@ -616,7 +616,7 @@ #endif int i; if (!msg->msg_iov) - return; + return 0; for (i = 0; i < msg->msg_iovlen; i++) { iov = &msg->msg_iov[i]; @@ -638,8 +638,9 @@ #endif code = iov->iov_base; if (type && code) { - get_user(fl->fl_icmp_type, type); - get_user(fl->fl_icmp_code, code); + if (get_user(fl->fl_icmp_type, type) || + get_user(fl->fl_icmp_code, code)) + return -EFAULT; probed = 1; } break; @@ -650,7 +651,8 @@ #ifdef CONFIG_IPV6_MIP6 /* check if type field is readable or not. */ if (iov->iov_len > 2 - len) { u8 __user *p = iov->iov_base; - get_user(fl->fl_mh_type, &p[2 - len]); + if (get_user(fl->fl_mh_type, &p[2 - len])) + return -EFAULT; probed = 1; } else len += iov->iov_len; @@ -664,6 +666,7 @@ #endif if (probed) break; } + return 0; } static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, @@ -787,7 +790,9 @@ static int rawv6_sendmsg(struct kiocb *i opt = ipv6_fixup_options(&opt_space, opt); fl.proto = proto; - rawv6_probe_proto_opt(&fl, msg); + err = rawv6_probe_proto_opt(&fl, msg); + if (err) + goto out; ipv6_addr_copy(&fl.fl6_dst, daddr); 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 093b3dd..836541e 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_co if (iter(ct, data)) goto found; } + write_unlock_bh(&nf_conntrack_lock); return NULL; found: - atomic_inc(&nf_ct_tuplehash_to_ctrack(h)->ct_general.use); + atomic_inc(&ct->ct_general.use); write_unlock_bh(&nf_conntrack_lock); return ct; } diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index d56e0d2..d527c89 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1075,8 +1075,9 @@ static int netlink_getsockopt(struct soc return -EINVAL; len = sizeof(int); val = nlk->flags & NETLINK_RECV_PKTINFO ? 1 : 0; - put_user(len, optlen); - put_user(val, optval); + if (put_user(len, optlen) || + put_user(val, optval)) + return -EFAULT; err = 0; break; default: diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 27329ce..ed0445f 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -346,11 +346,18 @@ void sctp_association_free(struct sctp_a struct list_head *pos, *temp; int i; - list_del(&asoc->asocs); + /* Only real associations count against the endpoint, so + * don't bother for if this is a temporary association. + */ + if (!asoc->temp) { + list_del(&asoc->asocs); - /* Decrement the backlog value for a TCP-style listening socket. */ - if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) - sk->sk_ack_backlog--; + /* Decrement the backlog value for a TCP-style listening + * socket. + */ + if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) + sk->sk_ack_backlog--; + } /* Mark as dead, so other users can know this structure is * going away. diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 35c49ff..9b6b394 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -144,6 +144,13 @@ void sctp_endpoint_add_asoc(struct sctp_ { struct sock *sk = ep->base.sk; + /* If this is a temporary association, don't bother + * since we'll be removing it shortly and don't + * want anyone to find it anyway. + */ + if (asoc->temp) + return; + /* Now just add it to our list of asocs */ list_add_tail(&asoc->asocs, &ep->asocs); diff --git a/net/sctp/input.c b/net/sctp/input.c index 64f6301..6d82f40 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -135,6 +135,9 @@ int sctp_rcv(struct sk_buff *skb) SCTP_INC_STATS_BH(SCTP_MIB_INSCTPPACKS); + if (skb_linearize(skb)) + goto discard_it; + sh = (struct sctphdr *) skb->h.raw; /* Pull up the IP and SCTP headers. */ @@ -768,6 +771,9 @@ static void __sctp_hash_established(stru /* Add an association to the hash. Local BH-safe. */ void sctp_hash_established(struct sctp_association *asoc) { + if (asoc->temp) + return; + sctp_local_bh_disable(); __sctp_hash_established(asoc); sctp_local_bh_enable(); @@ -801,6 +807,9 @@ static void __sctp_unhash_established(st /* Remove association from the hash table. Local BH-safe. */ void sctp_unhash_established(struct sctp_association *asoc) { + if (asoc->temp) + return; + sctp_local_bh_disable(); __sctp_unhash_established(asoc); sctp_local_bh_enable(); diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index fac7674..5b4f82f 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -591,7 +591,7 @@ static struct sock *sctp_v4_create_accep newinet->dport = htons(asoc->peer.port); newinet->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr; newinet->pmtudisc = inet->pmtudisc; - newinet->id = 0; + newinet->id = asoc->next_tsn ^ jiffies; newinet->uc_ttl = -1; newinet->mc_loop = 1; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 9f34dec..935bc91 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -3372,6 +3372,7 @@ SCTP_STATIC int sctp_do_peeloff(struct s { struct sock *sk = asoc->base.sk; struct socket *sock; + struct inet_sock *inetsk; int err = 0; /* An association cannot be branched off from an already peeled-off @@ -3389,6 +3390,14 @@ SCTP_STATIC int sctp_do_peeloff(struct s * asoc to the newsk. */ sctp_sock_migrate(sk, sock->sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH); + + /* Make peeled-off sockets more like 1-1 accepted sockets. + * Set the daddr and initialize id to something more random + */ + inetsk = inet_sk(sock->sk); + inetsk->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr; + inetsk->id = asoc->next_tsn ^ jiffies; + *sockp = sock; return err; diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 2b2e59d..b43e764 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -323,7 +323,7 @@ static void copy_from_user_state(struct x->props.replay_window = p->replay_window; x->props.reqid = p->reqid; x->props.family = p->family; - x->props.saddr = p->saddr; + memcpy(&x->props.saddr, &p->saddr, sizeof(x->props.saddr)); x->props.flags = p->flags; } @@ -545,7 +545,7 @@ static void copy_to_user_state(struct xf memcpy(&p->lft, &x->lft, sizeof(p->lft)); memcpy(&p->curlft, &x->curlft, sizeof(p->curlft)); memcpy(&p->stats, &x->stats, sizeof(p->stats)); - p->saddr = x->props.saddr; + memcpy(&p->saddr, &x->props.saddr, sizeof(p->saddr)); p->mode = x->props.mode; p->replay_window = x->props.replay_window; p->reqid = x->props.reqid; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index e9969a2..8ab5679 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3313,7 +3313,13 @@ static int selinux_socket_getpeername(st static int selinux_socket_setsockopt(struct socket *sock,int level,int optname) { - return socket_has_perm(current, sock, SOCKET__SETOPT); + int err; + + err = socket_has_perm(current, sock, SOCKET__SETOPT); + if (err) + return err; + + return selinux_netlbl_socket_setsockopt(sock, level, optname); } 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 ecab4bd..9de10cc 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(str void selinux_netlbl_sk_clone_security(struct sk_security_struct *ssec, struct sk_security_struct *newssec); int selinux_netlbl_inode_permission(struct inode *inode, int mask); +int selinux_netlbl_socket_setsockopt(struct socket *sock, + int level, + int optname); #else static inline void selinux_netlbl_cache_invalidate(void) { @@ -114,6 +117,13 @@ static inline int selinux_netlbl_inode_p { return 0; } + +static inline int selinux_netlbl_socket_setsockopt(struct socket *sock, + int level, + int optname) +{ + return 0; +} #endif /* CONFIG_NETLABEL */ #endif diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index b1f6fb3..bfe1227 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -2682,4 +2682,41 @@ u32 selinux_netlbl_socket_getpeersec_dgr return peer_sid; } + +/** + * selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel + * @sock: the socket + * @level: the socket level or protocol + * @optname: the socket option name + * + * Description: + * Check the setsockopt() call and if the user is trying to replace the IP + * options on a socket and a NetLabel is in place for the socket deny the + * access; otherwise allow the access. Returns zero when the access is + * allowed, -EACCES when denied, and other negative values on error. + * + */ +int selinux_netlbl_socket_setsockopt(struct socket *sock, + int level, + int optname) +{ + int rc = 0; + struct inode *inode = SOCK_INODE(sock); + struct sk_security_struct *sksec = sock->sk->sk_security; + struct inode_security_struct *isec = inode->i_security; + struct netlbl_lsm_secattr secattr; + + mutex_lock(&isec->lock); + if (level == IPPROTO_IP && optname == IP_OPTIONS && + sksec->nlbl_state == NLBL_LABELED) { + netlbl_secattr_init(&secattr); + rc = netlbl_socket_getattr(sock, &secattr); + if (rc == 0 && (secattr.cache || secattr.mls_lvl_vld)) + rc = -EACCES; + netlbl_secattr_destroy(&secattr); + } + mutex_unlock(&isec->lock); + + return rc; +} #endif /* CONFIG_NETLABEL */