diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-31 08:08:31 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-31 08:08:31 -0800 |
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 8a7b8fab623..31e5cc49d61 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -64,6 +64,7 @@ #include <linux/ethtool.h> #include <asm/uaccess.h> #include <asm/delay.h> +#include <asm/unaligned.h> #include <net/arp.h> #include "config_roms.h" @@ -491,7 +492,7 @@ static void ether1394_reset_priv (struct net_device *dev, int set_mtu) 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 net_device *dev, int set_mtu) 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(struct sk_buff *skb, 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(struct sk_buff *skb, 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(struct sk_buff *skb, 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 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev) 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 58b7efbb075..b5d0d7fb647 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 708e2e0371a..485e35c3b28 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 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 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr 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 3c23760c582..f735455dc5d 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) 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_buff *skb, int features) 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 2fbb84bf4e2..162032baeac 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) #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 sock *sk, /* 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(struct sock *sk, struct sk_buff *skb) 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(struct sock *sk, struct sk_buff *skb) 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(struct sock *sk, struct sk_buff *skb) 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 e2077a3aa8c..6460233407c 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, /* 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 socket *sock, 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 8dabbfc3126..9f02917d6f4 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) 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 0849f1cced1..413c2d0a1f3 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 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 *name, } } - 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 *name, 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 4b90927619b..8a455439b12 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, 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 ipt_entry *e, 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 ipt_entry *e, 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_user(struct ipt_entry_match *m, 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(struct ipt_entry *e, void **dstptr, 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(struct ipt_entry *e, void **dstptr, 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 b430cf2a4f6..5c31dead2bd 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 flowi *fl, struct msghdr *msg) 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 flowi *fl, struct msghdr *msg) 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 flowi *fl, struct msghdr *msg) 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 *iocb, struct sock *sk, struct msghdr *msg, .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 1d672b0547f..6d4533b58dc 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 * 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_next(struct seq_file *seq, struct ip6_flo while (!fl) { if (++state->bucket <= FL_HASH_MASK) fl = fl_ht[state->bucket]; + else + break; } return fl; } @@ -623,9 +627,13 @@ static void ip6fl_seq_stop(struct seq_file *seq, void *v) read_unlock_bh(&ip6_fl_lock); } -static void ip6fl_fl_seq_show(struct seq_file *seq, struct ip6_flowlabel *fl) +static int ip6fl_seq_show(struct seq_file *seq, void *v) { - while(fl) { + if (v == SEQ_START_TOKEN) + seq_printf(seq, "%-5s %-1s %-6s %-6s %-6s %-8s %-32s %s\n", + "Label", "S", "Owner", "Users", "Linger", "Expires", "Dst", "Opt"); + else { + struct ip6_flowlabel *fl = v; seq_printf(seq, "%05X %-1d %-6d %-6d %-6ld %-8ld " NIP6_SEQFMT " %-4d\n", (unsigned)ntohl(fl->label), @@ -636,17 +644,7 @@ static void ip6fl_fl_seq_show(struct seq_file *seq, struct ip6_flowlabel *fl) (long)(fl->expires - jiffies)/HZ, NIP6(fl->dst), fl->opt ? fl->opt->opt_nflen : 0); - fl = fl->next; } -} - -static int ip6fl_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) - seq_printf(seq, "%-5s %-1s %-6s %-6s %-6s %-8s %-32s %s\n", - "Label", "S", "Owner", "Users", "Linger", "Expires", "Dst", "Opt"); - else - ip6fl_fl_seq_show(seq, v); return 0; } diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 4bc4e5b3379..d7c45a9c15f 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 53bf977cca6..167c2ea88f6 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, 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 d09329ca326..d6dedc4aec7 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 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) 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 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) 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 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) /* 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 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) 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 *iocb, struct sock *sk, 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 093b3ddc513..836541e509f 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), 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 d56e0d21f91..d527c8977b1 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, 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 27329ce9c31..ed0445fe85e 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -346,11 +346,18 @@ void sctp_association_free(struct sctp_association *asoc) 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 35c49ff2d06..9b6b394b66f 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -144,6 +144,13 @@ void sctp_endpoint_add_asoc(struct sctp_endpoint *ep, { 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 64f63010253..6d82f400d13 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(struct sctp_association *asoc) /* 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(struct sctp_association *asoc) /* 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 fac7674438a..5b4f82fd98f 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, 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 9f34dec6ff8..935bc9187fd 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, { 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 sctp_association *asoc, * 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 2b2e59d8ffb..b43e7647e12 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 * 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 xfrm_state *x, struct xfrm_usersa_info *p) 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 e9969a2fc84..8ab5679a37a 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3313,7 +3313,13 @@ static int selinux_socket_getpeername(struct socket *sock) 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 ecab4bddaaf..9de10cc2cef 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, 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_permission(struct inode *inode, { 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 b1f6fb36c69..bfe122764c9 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) 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 */ |