Commit 612b322a authored by Linus Torvalds's avatar Linus Torvalds

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
parents d2c59a22 1b7c2dbc
...@@ -64,6 +64,7 @@ ...@@ -64,6 +64,7 @@
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/delay.h> #include <asm/delay.h>
#include <asm/unaligned.h>
#include <net/arp.h> #include <net/arp.h>
#include "config_roms.h" #include "config_roms.h"
...@@ -491,7 +492,7 @@ static void ether1394_reset_priv (struct net_device *dev, int set_mtu) ...@@ -491,7 +492,7 @@ static void ether1394_reset_priv (struct net_device *dev, int set_mtu)
int i; int i;
struct eth1394_priv *priv = netdev_priv(dev); struct eth1394_priv *priv = netdev_priv(dev);
struct hpsb_host *host = priv->host; 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); u16 maxpayload = 1 << (host->csr.max_rec + 1);
int max_speed = IEEE1394_SPEED_MAX; int max_speed = IEEE1394_SPEED_MAX;
...@@ -514,8 +515,8 @@ static void ether1394_reset_priv (struct net_device *dev, int set_mtu) ...@@ -514,8 +515,8 @@ static void ether1394_reset_priv (struct net_device *dev, int set_mtu)
ETHER1394_GASP_OVERHEAD))); ETHER1394_GASP_OVERHEAD)));
/* Set our hardware address while we're at it */ /* Set our hardware address while we're at it */
*(u64*)dev->dev_addr = guid; memcpy(dev->dev_addr, &guid, sizeof(u64));
*(u64*)dev->broadcast = ~0x0ULL; memset(dev->broadcast, 0xff, sizeof(u64));
} }
spin_unlock_irqrestore (&priv->lock, flags); spin_unlock_irqrestore (&priv->lock, flags);
...@@ -894,6 +895,7 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb, ...@@ -894,6 +895,7 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb,
u16 maxpayload; u16 maxpayload;
struct eth1394_node_ref *node; struct eth1394_node_ref *node;
struct eth1394_node_info *node_info; struct eth1394_node_info *node_info;
__be64 guid;
/* Sanity check. MacOSX seems to be sending us 131 in this /* Sanity check. MacOSX seems to be sending us 131 in this
* field (atleast on my Panther G5). Not sure why. */ * field (atleast on my Panther G5). Not sure why. */
...@@ -902,8 +904,9 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb, ...@@ -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))); 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, node = eth1394_find_node_guid(&priv->ip_node_list,
be64_to_cpu(arp1394->s_uniq_id)); be64_to_cpu(guid));
if (!node) { if (!node) {
return 0; return 0;
} }
...@@ -931,10 +934,9 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb, ...@@ -931,10 +934,9 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb,
arp_ptr += arp->ar_pln; /* skip over sender IP addr */ arp_ptr += arp->ar_pln; /* skip over sender IP addr */
if (arp->ar_op == htons(ARPOP_REQUEST)) if (arp->ar_op == htons(ARPOP_REQUEST))
/* just set ARP req target unique ID to 0 */ memset(arp_ptr, 0, sizeof(u64));
*((u64*)arp_ptr) = 0;
else else
*((u64*)arp_ptr) = *((u64*)dev->dev_addr); memcpy(arp_ptr, dev->dev_addr, sizeof(u64));
} }
/* Now add the ethernet header. */ /* Now add the ethernet header. */
...@@ -1675,8 +1677,10 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev) ...@@ -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]) if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF])
priv->bc_dgl++; priv->bc_dgl++;
} else { } else {
__be64 guid = get_unaligned((u64 *)eth->h_dest);
node = eth1394_find_node_guid(&priv->ip_node_list, node = eth1394_find_node_guid(&priv->ip_node_list,
be64_to_cpu(*(u64*)eth->h_dest)); be64_to_cpu(guid));
if (!node) { if (!node) {
ret = -EAGAIN; ret = -EAGAIN;
goto fail; goto fail;
......
...@@ -127,7 +127,7 @@ config LANMEDIA ...@@ -127,7 +127,7 @@ config LANMEDIA
# There is no way to detect a Sealevel board. Force it modular # There is no way to detect a Sealevel board. Force it modular
config SEALEVEL_4021 config SEALEVEL_4021
tristate "Sealevel Systems 4021 support" tristate "Sealevel Systems 4021 support"
depends on WAN && ISA && m && ISA_DMA_API depends on WAN && ISA && m && ISA_DMA_API && INET
help help
This is a driver for the Sealevel Systems ACB 56 serial I/O adapter. This is a driver for the Sealevel Systems ACB 56 serial I/O adapter.
......
...@@ -1584,7 +1584,6 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr ...@@ -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) { if (usat->sat_addr.s_net || usat->sat_addr.s_node == ATADDR_ANYNODE) {
rt = atrtr_find(&usat->sat_addr); rt = atrtr_find(&usat->sat_addr);
dev = rt->dev;
} else { } else {
struct atalk_addr at_hint; struct atalk_addr at_hint;
...@@ -1592,7 +1591,6 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr ...@@ -1592,7 +1591,6 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
at_hint.s_net = at->src_net; at_hint.s_net = at->src_net;
rt = atrtr_find(&at_hint); rt = atrtr_find(&at_hint);
dev = rt->dev;
} }
if (!rt) if (!rt)
return -ENETUNREACH; return -ENETUNREACH;
......
...@@ -1946,7 +1946,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features) ...@@ -1946,7 +1946,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features)
do { do {
struct sk_buff *nskb; struct sk_buff *nskb;
skb_frag_t *frag; skb_frag_t *frag;
int hsize, nsize; int hsize;
int k; int k;
int size; int size;
...@@ -1957,11 +1957,10 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features) ...@@ -1957,11 +1957,10 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features)
hsize = skb_headlen(skb) - offset; hsize = skb_headlen(skb) - offset;
if (hsize < 0) if (hsize < 0)
hsize = 0; hsize = 0;
nsize = hsize + doffset; if (hsize > len || !sg)
if (nsize > len + doffset || !sg) hsize = len;
nsize = len + doffset;
nskb = alloc_skb(nsize + headroom, GFP_ATOMIC); nskb = alloc_skb(hsize + doffset + headroom, GFP_ATOMIC);
if (unlikely(!nskb)) if (unlikely(!nskb))
goto err; goto err;
......
...@@ -352,14 +352,14 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, int len) ...@@ -352,14 +352,14 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, int len)
#ifdef CONFIG_IP_DCCP_CCID2_DEBUG #ifdef CONFIG_IP_DCCP_CCID2_DEBUG
ccid2_pr_debug("pipe=%d\n", hctx->ccid2hctx_pipe); 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 { do {
struct ccid2_seq *seqp = hctx->ccid2hctx_seqt; struct ccid2_seq *seqp = hctx->ccid2hctx_seqt;
while (seqp != hctx->ccid2hctx_seqh) { while (seqp != hctx->ccid2hctx_seqh) {
ccid2_pr_debug("out seq=%llu acked=%d time=%lu\n", ccid2_pr_debug("out seq=%llu acked=%d time=%lu\n",
seqp->ccid2s_seq, seqp->ccid2s_acked, (unsigned long long)seqp->ccid2s_seq,
seqp->ccid2s_sent); seqp->ccid2s_acked, seqp->ccid2s_sent);
seqp = seqp->ccid2s_next; seqp = seqp->ccid2s_next;
} }
} while (0); } while (0);
...@@ -480,7 +480,8 @@ static inline void ccid2_new_ack(struct sock *sk, ...@@ -480,7 +480,8 @@ static inline void ccid2_new_ack(struct sock *sk,
/* first measurement */ /* first measurement */
if (hctx->ccid2hctx_srtt == -1) { if (hctx->ccid2hctx_srtt == -1) {
ccid2_pr_debug("R: %lu Time=%lu seq=%llu\n", 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); ccid2_change_srtt(hctx, r);
hctx->ccid2hctx_rttvar = r >> 1; hctx->ccid2hctx_rttvar = r >> 1;
} else { } else {
...@@ -636,8 +637,9 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) ...@@ -636,8 +637,9 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
u64 ackno_end_rl; u64 ackno_end_rl;
dccp_set_seqno(&ackno_end_rl, ackno - rl); dccp_set_seqno(&ackno_end_rl, ackno - rl);
ccid2_pr_debug("ackvec start:%llu end:%llu\n", ackno, ccid2_pr_debug("ackvec start:%llu end:%llu\n",
ackno_end_rl); (unsigned long long)ackno,
(unsigned long long)ackno_end_rl);
/* if the seqno we are analyzing is larger than the /* if the seqno we are analyzing is larger than the
* current ackno, then move towards the tail of our * current ackno, then move towards the tail of our
* seqnos. * seqnos.
...@@ -672,7 +674,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) ...@@ -672,7 +674,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
seqp->ccid2s_acked = 1; seqp->ccid2s_acked = 1;
ccid2_pr_debug("Got ack for %llu\n", ccid2_pr_debug("Got ack for %llu\n",
seqp->ccid2s_seq); (unsigned long long)seqp->ccid2s_seq);
ccid2_hc_tx_dec_pipe(sk); ccid2_hc_tx_dec_pipe(sk);
} }
if (seqp == hctx->ccid2hctx_seqt) { if (seqp == hctx->ccid2hctx_seqt) {
...@@ -718,7 +720,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) ...@@ -718,7 +720,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
while (1) { while (1) {
if (!seqp->ccid2s_acked) { if (!seqp->ccid2s_acked) {
ccid2_pr_debug("Packet lost: %llu\n", ccid2_pr_debug("Packet lost: %llu\n",
seqp->ccid2s_seq); (unsigned long long)seqp->ccid2s_seq);
/* XXX need to traverse from tail -> head in /* XXX need to traverse from tail -> head in
* order to detect multiple congestion events in * order to detect multiple congestion events in
* one ack vector. * one ack vector.
......
...@@ -1307,7 +1307,8 @@ int cipso_v4_socket_setattr(const struct socket *sock, ...@@ -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 /* 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 * 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_len = (buf_len + 3) & ~3;
opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC); opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC);
if (opt == NULL) { if (opt == NULL) {
...@@ -1317,11 +1318,9 @@ int cipso_v4_socket_setattr(const struct socket *sock, ...@@ -1317,11 +1318,9 @@ int cipso_v4_socket_setattr(const struct socket *sock,
memcpy(opt->__data, buf, buf_len); memcpy(opt->__data, buf, buf_len);
opt->optlen = opt_len; opt->optlen = opt_len;
opt->is_data = 1; opt->is_data = 1;
opt->cipso = sizeof(struct iphdr);
kfree(buf); kfree(buf);
buf = NULL; buf = NULL;
ret_val = ip_options_compile(opt, NULL);
if (ret_val != 0)
goto socket_setattr_failure;
sk_inet = inet_sk(sk); sk_inet = inet_sk(sk);
if (sk_inet->is_icsk) { if (sk_inet->is_icsk) {
......
...@@ -443,7 +443,7 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb) ...@@ -443,7 +443,7 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb)
opt->router_alert = optptr - iph; opt->router_alert = optptr - iph;
break; break;
case IPOPT_CIPSO: case IPOPT_CIPSO:
if (opt->cipso) { if ((!skb && !capable(CAP_NET_RAW)) || opt->cipso) {
pp_ptr = optptr; pp_ptr = optptr;
goto error; goto error;
} }
......
...@@ -466,7 +466,13 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i ...@@ -466,7 +466,13 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i
return -EINVAL; return -EINVAL;
} }
if (e->target_offset + sizeof(struct arpt_entry_target) > e->next_offset)
return -EINVAL;
t = arpt_get_target(e); 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, target = try_then_request_module(xt_find_target(NF_ARP, t->u.user.name,
t->u.user.revision), t->u.user.revision),
"arpt_%s", t->u.user.name); "arpt_%s", t->u.user.name);
...@@ -621,20 +627,18 @@ static int translate_table(const char *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 */ /* Finally, each sanity check must pass */
i = 0; i = 0;
ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size, ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size,
check_entry, name, size, &i); check_entry, name, size, &i);
if (ret != 0) { if (ret != 0)
ARPT_ENTRY_ITERATE(entry0, newinfo->size, goto cleanup;
cleanup_entry, &i);
return ret; ret = -ELOOP;
if (!mark_source_chains(newinfo, valid_hooks, entry0)) {
duprintf("Looping hook\n");
goto cleanup;
} }
/* And one copy for every other CPU */ /* And one copy for every other CPU */
...@@ -643,6 +647,9 @@ static int translate_table(const char *name, ...@@ -643,6 +647,9 @@ static int translate_table(const char *name,
memcpy(newinfo->entries[i], entry0, newinfo->size); memcpy(newinfo->entries[i], entry0, newinfo->size);
} }
return 0;
cleanup:
ARPT_ENTRY_ITERATE(entry0, newinfo->size, cleanup_entry, &i);
return ret; return ret;
} }
......
...@@ -547,12 +547,18 @@ check_entry(struct ipt_entry *e, const char *name, unsigned int size, ...@@ -547,12 +547,18 @@ check_entry(struct ipt_entry *e, const char *name, unsigned int size,
return -EINVAL; return -EINVAL;
} }
if (e->target_offset + sizeof(struct ipt_entry_target) > e->next_offset)
return -EINVAL;
j = 0; j = 0;
ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j); ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j);
if (ret != 0) if (ret != 0)
goto cleanup_matches; goto cleanup_matches;
t = ipt_get_target(e); 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, target = try_then_request_module(xt_find_target(AF_INET,
t->u.user.name, t->u.user.name,
t->u.user.revision), t->u.user.revision),
...@@ -712,19 +718,17 @@ translate_table(const char *name, ...@@ -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 */ /* Finally, each sanity check must pass */
i = 0; i = 0;
ret = IPT_ENTRY_ITERATE(entry0, newinfo->size, ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
check_entry, name, size, &i); check_entry, name, size, &i);
if (ret != 0) { if (ret != 0)
IPT_ENTRY_ITERATE(entry0, newinfo->size, goto cleanup;
cleanup_entry, &i);
return ret; ret = -ELOOP;
} if (!mark_source_chains(newinfo, valid_hooks, entry0))
goto cleanup;
/* And one copy for every other CPU */ /* And one copy for every other CPU */
for_each_possible_cpu(i) { for_each_possible_cpu(i) {
...@@ -732,6 +736,9 @@ translate_table(const char *name, ...@@ -732,6 +736,9 @@ translate_table(const char *name,
memcpy(newinfo->entries[i], entry0, newinfo->size); memcpy(newinfo->entries[i], entry0, newinfo->size);
} }
return 0;
cleanup:
IPT_ENTRY_ITERATE(entry0, newinfo->size, cleanup_entry, &i);
return ret; return ret;
} }
...@@ -1463,6 +1470,10 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e, ...@@ -1463,6 +1470,10 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
return -EINVAL; return -EINVAL;
} }
if (e->target_offset + sizeof(struct compat_xt_entry_target) >
e->next_offset)
return -EINVAL;
off = 0; off = 0;
entry_offset = (void *)e - (void *)base; entry_offset = (void *)e - (void *)base;
j = 0; j = 0;
...@@ -1472,6 +1483,9 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e, ...@@ -1472,6 +1483,9 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
goto cleanup_matches; goto cleanup_matches;
t = ipt_get_target(e); 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, target = try_then_request_module(xt_find_target(AF_INET,
t->u.user.name, t->u.user.name,
t->u.user.revision), t->u.user.revision),
...@@ -1513,7 +1527,7 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e, ...@@ -1513,7 +1527,7 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
static inline int compat_copy_match_from_user(struct ipt_entry_match *m, static inline int compat_copy_match_from_user(struct ipt_entry_match *m,
void **dstptr, compat_uint_t *size, const char *name, 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_entry_match *dm;
struct ipt_match *match; struct ipt_match *match;
...@@ -1526,22 +1540,13 @@ static inline int compat_copy_match_from_user(struct ipt_entry_match *m, ...@@ -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), ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm),
name, hookmask, ip->proto, name, hookmask, ip->proto,
ip->invflags & IPT_INV_PROTO); ip->invflags & IPT_INV_PROTO);
if (ret) if (!ret && m->u.kernel.match->checkentry
goto err;
if (m->u.kernel.match->checkentry
&& !m->u.kernel.match->checkentry(name, ip, match, dm->data, && !m->u.kernel.match->checkentry(name, ip, match, dm->data,
hookmask)) { hookmask)) {
duprintf("ip_tables: check failed for `%s'.\n", duprintf("ip_tables: check failed for `%s'.\n",
m->u.kernel.match->name); m->u.kernel.match->name);
ret = -EINVAL; ret = -EINVAL;
goto err;
} }
(*i)++;
return 0;
err:
module_put(m->u.kernel.match->me);
return ret; return ret;
} }
...@@ -1553,19 +1558,18 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr, ...@@ -1553,19 +1558,18 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
struct ipt_target *target; struct ipt_target *target;
struct ipt_entry *de; struct ipt_entry *de;
unsigned int origsize; unsigned int origsize;
int ret, h, j; int ret, h;
ret = 0; ret = 0;
origsize = *size; origsize = *size;
de = (struct ipt_entry *)*dstptr; de = (struct ipt_entry *)*dstptr;
memcpy(de, e, sizeof(struct ipt_entry)); memcpy(de, e, sizeof(struct ipt_entry));
j = 0;
*dstptr += sizeof(struct compat_ipt_entry); *dstptr += sizeof(struct compat_ipt_entry);
ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size, 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) if (ret)
goto cleanup_matches; goto err;
de->target_offset = e->target_offset - (origsize - *size); de->target_offset = e->target_offset - (origsize - *size);
t = ipt_get_target(e); t = ipt_get_target(e);
target = t->u.kernel.target; target = t->u.kernel.target;
...@@ -1599,12 +1603,7 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr, ...@@ -1599,12 +1603,7 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
goto err; goto err;
} }
ret = 0; ret = 0;
return ret;
err: err:
module_put(t->u.kernel.target->me);
cleanup_matches:
IPT_MATCH_ITERATE(e, cleanup_match, &j);
return ret; return ret;
} }
...@@ -1618,7 +1617,7 @@ translate_compat_table(const char *name, ...@@ -1618,7 +1617,7 @@ translate_compat_table(const char *name,
unsigned int *hook_entries, unsigned int *hook_entries,
unsigned int *underflows) unsigned int *underflows)
{ {
unsigned int i; unsigned int i, j;
struct xt_table_info *newinfo, *info; struct xt_table_info *newinfo, *info;
void *pos, *entry0, *entry1; void *pos, *entry0, *entry1;
unsigned int size; unsigned int size;
...@@ -1636,21 +1635,21 @@ translate_compat_table(const char *name, ...@@ -1636,21 +1635,21 @@ translate_compat_table(const char *name,
} }
duprintf("translate_compat_table: size %u\n", info->size); duprintf("translate_compat_table: size %u\n", info->size);
i = 0; j = 0;
xt_compat_lock(AF_INET); xt_compat_lock(AF_INET);
/* Walk through entries, checking offsets. */ /* Walk through entries, checking offsets. */
ret = IPT_ENTRY_ITERATE(entry0, total_size, ret = IPT_ENTRY_ITERATE(entry0, total_size,
check_compat_entry_size_and_hooks, check_compat_entry_size_and_hooks,
info, &size, entry0, info, &size, entry0,
entry0 + total_size, entry0 + total_size,
hook_entries, underflows, &i, name); hook_entries, underflows, &j, name);
if (ret != 0) if (ret != 0)
goto out_unlock; goto out_unlock;
ret = -EINVAL; ret = -EINVAL;
if (i != number) { if (j != number) {
duprintf("translate_compat_table: %u not %u entries\n", duprintf("translate_compat_table: %u not %u entries\n",
i, number); j, number);
goto out_unlock; goto out_unlock;
} }
...@@ -1709,8 +1708,10 @@ translate_compat_table(const char *name, ...@@ -1709,8 +1708,10 @@ translate_compat_table(const char *name,
free_newinfo: free_newinfo:
xt_free_table_info(newinfo); xt_free_table_info(newinfo);
out: out:
IPT_ENTRY_ITERATE(entry0, total_size, cleanup_entry, &j);
return ret; return ret;
out_unlock: out_unlock:
compat_flush_offsets();
xt_compat_unlock(AF_INET); xt_compat_unlock(AF_INET);
goto out; goto out;
} }
......
...@@ -329,7 +329,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, ...@@ -329,7 +329,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
return err; 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; struct iovec *iov;
u8 __user *type = NULL; u8 __user *type = NULL;
...@@ -338,7 +338,7 @@ static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg) ...@@ -338,7 +338,7 @@ static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
unsigned int i; unsigned int i;
if (!msg->msg_iov) if (!msg->msg_iov)
return; return 0;
for (i = 0; i < msg->msg_iovlen; i++) { for (i = 0; i < msg->msg_iovlen; i++) {
iov = &msg->msg_iov[i]; iov = &msg->msg_iov[i];
...@@ -360,8 +360,9 @@ static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg) ...@@ -360,8 +360,9 @@ static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
code = iov->iov_base; code = iov->iov_base;
if (type && code) { if (type && code) {
get_user(fl->fl_icmp_type, type); if (get_user(fl->fl_icmp_type, type) ||
get_user(fl->fl_icmp_code, code); get_user(fl->fl_icmp_code, code))
return -EFAULT;
probed = 1; probed = 1;
} }
break; break;
...@@ -372,6 +373,7 @@ static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg) ...@@ -372,6 +373,7 @@ static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
if (probed) if (probed)
break; break;
} }
return 0;
} }
static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, 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,8 +482,11 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
.proto = inet->hdrincl ? IPPROTO_RAW : .proto = inet->hdrincl ? IPPROTO_RAW :
sk->sk_protocol, sk->sk_protocol,
}; };
if (!inet->hdrincl) if (!inet->hdrincl) {
raw_probe_proto_opt(&fl, msg); err = raw_probe_proto_opt(&fl, msg);
if (err)
goto done;
}
security_sk_classify_flow(sk, &fl); security_sk_classify_flow(sk, &fl);
err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT)); err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT));
......
...@@ -330,8 +330,10 @@ fl_create(struct in6_flowlabel_req *freq, char __user *optval, int optlen, int * ...@@ -330,8 +330,10 @@ fl_create(struct in6_flowlabel_req *freq, char __user *optval, int optlen, int *
fl->share = freq->flr_share; fl->share = freq->flr_share;
addr_type = ipv6_addr_type(&freq->flr_dst); addr_type = ipv6_addr_type(&freq->flr_dst);
if ((addr_type&IPV6_ADDR_MAPPED) if ((addr_type&IPV6_ADDR_MAPPED)
|| addr_type == IPV6_ADDR_ANY) || addr_type == IPV6_ADDR_ANY) {
err = -EINVAL;
goto done; goto done;
}
ipv6_addr_copy(&fl->dst, &freq->flr_dst); ipv6_addr_copy(&fl->dst, &freq->flr_dst);
atomic_set(&fl->users, 1); atomic_set(&fl->users, 1);
switch (fl->share) { switch (fl->share) {
...@@ -587,6 +589,8 @@ static struct ip6_flowlabel *ip6fl_get_next(struct seq_file *seq, struct ip6_flo ...@@ -587,6 +589,8 @@ static struct ip6_flowlabel *ip6fl_get_next(struct seq_file *seq, struct ip6_flo
while (!fl) { while (!fl) {
if (++state->bucket <= FL_HASH_MASK) if (++state->bucket <= FL_HASH_MASK)
fl = fl_ht[state->bucket]; fl = fl_ht[state->bucket];
else
break;
} }
return fl; return fl;
} }
...@@ -623,9 +627,13 @@ static void ip6fl_seq_stop(struct seq_file *seq, void *v) ...@@ -623,9 +627,13 @@ static void ip6fl_seq_stop(struct seq_file *seq, void *v)
read_unlock_bh(&ip6_fl_lock); 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, seq_printf(seq,
"%05X %-1d %-6d %-6d %-6ld %-8ld " NIP6_SEQFMT " %-4d\n", "%05X %-1d %-6d %-6d %-6ld %-8ld " NIP6_SEQFMT " %-4d\n",
(unsigned)ntohl(fl->label), (unsigned)ntohl(fl->label),
...@@ -636,17 +644,7 @@ static void ip6fl_fl_seq_show(struct seq_file *seq, struct ip6_flowlabel *fl) ...@@ -636,17 +644,7 @@ static void ip6fl_fl_seq_show(struct seq_file *seq, struct ip6_flowlabel *fl)
(long)(fl->expires - jiffies)/HZ, (long)(fl->expires - jiffies)/HZ,
NIP6(fl->dst), NIP6(fl->dst),
fl->opt ? fl->opt->opt_nflen : 0); 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; return 0;
} }
......
...@@ -40,7 +40,7 @@ config IP6_NF_QUEUE ...@@ -40,7 +40,7 @@ config IP6_NF_QUEUE
To compile it as a module, choose M here. If unsure, say N. To compile it as a module, choose M here. If unsure, say N.
config IP6_NF_IPTABLES config IP6_NF_IPTABLES
tristate "IP6 tables support (required for filtering/masq/NAT)" tristate "IP6 tables support (required for filtering)"
depends on NETFILTER_XTABLES depends on NETFILTER_XTABLES
help help
ip6tables is a general, extensible packet identification framework. ip6tables is a general, extensible packet identification framework.
......
...@@ -586,12 +586,19 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size, ...@@ -586,12 +586,19 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
return -EINVAL; return -EINVAL;
} }
if (e->target_offset + sizeof(struct ip6t_entry_target) >
e->next_offset)
return -EINVAL;
j = 0; j = 0;
ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j); ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
if (ret != 0) if (ret != 0)
goto cleanup_matches; goto cleanup_matches;
t = ip6t_get_target(e); 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, target = try_then_request_module(xt_find_target(AF_INET6,
t->u.user.name, t->u.user.name,
t->u.user.revision), t->u.user.revision),
...@@ -751,19 +758,17 @@ translate_table(const char *name, ...@@ -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 */ /* Finally, each sanity check must pass */
i = 0; i = 0;
ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size, ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
check_entry, name, size, &i); check_entry, name, size, &i);
if (ret != 0) { if (ret != 0)
IP6T_ENTRY_ITERATE(entry0, newinfo->size, goto cleanup;
cleanup_entry, &i);
return ret; ret = -ELOOP;
} if (!mark_source_chains(newinfo, valid_hooks, entry0))
goto cleanup;
/* And one copy for every other CPU */ /* And one copy for every other CPU */
for_each_possible_cpu(i) { for_each_possible_cpu(i) {
...@@ -771,6 +776,9 @@ translate_table(const char *name, ...@@ -771,6 +776,9 @@ translate_table(const char *name,
memcpy(newinfo->entries[i], entry0, newinfo->size); memcpy(newinfo->entries[i], entry0, newinfo->size);
} }
return 0;
cleanup:
IP6T_ENTRY_ITERATE(entry0, newinfo->size, cleanup_entry, &i);
return ret; return ret;
} }
......
...@@ -604,7 +604,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, ...@@ -604,7 +604,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
return err; 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; struct iovec *iov;
u8 __user *type = NULL; u8 __user *type = NULL;
...@@ -616,7 +616,7 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) ...@@ -616,7 +616,7 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
int i; int i;
if (!msg->msg_iov) if (!msg->msg_iov)
return; return 0;
for (i = 0; i < msg->msg_iovlen; i++) { for (i = 0; i < msg->msg_iovlen; i++) {
iov = &msg->msg_iov[i]; iov = &msg->msg_iov[i];
...@@ -638,8 +638,9 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) ...@@ -638,8 +638,9 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
code = iov->iov_base; code = iov->iov_base;
if (type && code) { if (type && code) {
get_user(fl->fl_icmp_type, type); if (get_user(fl->fl_icmp_type, type) ||
get_user(fl->fl_icmp_code, code); get_user(fl->fl_icmp_code, code))
return -EFAULT;
probed = 1; probed = 1;
} }
break; break;
...@@ -650,7 +651,8 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) ...@@ -650,7 +651,8 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
/* check if type field is readable or not. */ /* check if type field is readable or not. */
if (iov->iov_len > 2 - len) { if (iov->iov_len > 2 - len) {
u8 __user *p = iov->iov_base; 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; probed = 1;
} else } else
len += iov->iov_len; len += iov->iov_len;
...@@ -664,6 +666,7 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) ...@@ -664,6 +666,7 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
if (probed) if (probed)
break; break;
} }
return 0;
} }
static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, 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,7 +790,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
opt = ipv6_fixup_options(&opt_space, opt); opt = ipv6_fixup_options(&opt_space, opt);
fl.proto = proto; 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); ipv6_addr_copy(&fl.fl6_dst, daddr);
if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr))
......
...@@ -1520,9 +1520,10 @@ get_next_corpse(int (*iter)(struct nf_conn *i, void *data), ...@@ -1520,9 +1520,10 @@ get_next_corpse(int (*iter)(struct nf_conn *i, void *data),
if (iter(ct, data)) if (iter(ct, data))
goto found; goto found;
} }
write_unlock_bh(&nf_conntrack_lock);
return NULL; return NULL;
found: found:
atomic_inc(&nf_ct_tuplehash_to_ctrack(h)->ct_general.use); atomic_inc(&ct->ct_general.use);
write_unlock_bh(&nf_conntrack_lock); write_unlock_bh(&nf_conntrack_lock);
return ct; return ct;
} }
......
...@@ -1075,8 +1075,9 @@ static int netlink_getsockopt(struct socket *sock, int level, int optname, ...@@ -1075,8 +1075,9 @@ static int netlink_getsockopt(struct socket *sock, int level, int optname,
return -EINVAL; return -EINVAL;
len = sizeof(int); len = sizeof(int);
val = nlk->flags & NETLINK_RECV_PKTINFO ? 1 : 0; val = nlk->flags & NETLINK_RECV_PKTINFO ? 1 : 0;
put_user(len, optlen); if (put_user(len, optlen) ||
put_user(val, optval); put_user(val, optval))
return -EFAULT;
err = 0; err = 0;
break; break;
default: default:
......
...@@ -346,11 +346,18 @@ void sctp_association_free(struct sctp_association *asoc) ...@@ -346,11 +346,18 @@ void sctp_association_free(struct sctp_association *asoc)
struct list_head *pos, *temp; struct list_head *pos, *temp;
int i; 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. */ /* Decrement the backlog value for a TCP-style listening
if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) * socket.
sk->sk_ack_backlog--; */
if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
sk->sk_ack_backlog--;
}
/* Mark as dead, so other users can know this structure is /* Mark as dead, so other users can know this structure is
* going away. * going away.
......
...@@ -144,6 +144,13 @@ void sctp_endpoint_add_asoc(struct sctp_endpoint *ep, ...@@ -144,6 +144,13 @@ void sctp_endpoint_add_asoc(struct sctp_endpoint *ep,
{ {
struct sock *sk = ep->base.sk; 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 */ /* Now just add it to our list of asocs */
list_add_tail(&asoc->asocs, &ep->asocs); list_add_tail(&asoc->asocs, &ep->asocs);
......
...@@ -135,6 +135,9 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -135,6 +135,9 @@ int sctp_rcv(struct sk_buff *skb)
SCTP_INC_STATS_BH(SCTP_MIB_INSCTPPACKS); SCTP_INC_STATS_BH(SCTP_MIB_INSCTPPACKS);
if (skb_linearize(skb))
goto discard_it;
sh = (struct sctphdr *) skb->h.raw; sh = (struct sctphdr *) skb->h.raw;
/* Pull up the IP and SCTP headers. */ /* Pull up the IP and SCTP headers. */
...@@ -768,6 +771,9 @@ static void __sctp_hash_established(struct sctp_association *asoc) ...@@ -768,6 +771,9 @@ static void __sctp_hash_established(struct sctp_association *asoc)
/* Add an association to the hash. Local BH-safe. */ /* Add an association to the hash. Local BH-safe. */
void sctp_hash_established(struct sctp_association *asoc) void sctp_hash_established(struct sctp_association *asoc)
{ {
if (asoc->temp)
return;
sctp_local_bh_disable(); sctp_local_bh_disable();
__sctp_hash_established(asoc); __sctp_hash_established(asoc);
sctp_local_bh_enable(); sctp_local_bh_enable();
...@@ -801,6 +807,9 @@ static void __sctp_unhash_established(struct sctp_association *asoc) ...@@ -801,6 +807,9 @@ static void __sctp_unhash_established(struct sctp_association *asoc)
/* Remove association from the hash table. Local BH-safe. */ /* Remove association from the hash table. Local BH-safe. */
void sctp_unhash_established(struct sctp_association *asoc) void sctp_unhash_established(struct sctp_association *asoc)
{ {
if (asoc->temp)
return;
sctp_local_bh_disable(); sctp_local_bh_disable();
__sctp_unhash_established(asoc); __sctp_unhash_established(asoc);
sctp_local_bh_enable(); sctp_local_bh_enable();
......
...@@ -591,7 +591,7 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk, ...@@ -591,7 +591,7 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk,
newinet->dport = htons(asoc->peer.port); newinet->dport = htons(asoc->peer.port);
newinet->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr; newinet->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr;
newinet->pmtudisc = inet->pmtudisc; newinet->pmtudisc = inet->pmtudisc;
newinet->id = 0; newinet->id = asoc->next_tsn ^ jiffies;
newinet->uc_ttl = -1; newinet->uc_ttl = -1;
newinet->mc_loop = 1; newinet->mc_loop = 1;
......
...@@ -3372,6 +3372,7 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc, ...@@ -3372,6 +3372,7 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc,
{ {
struct sock *sk = asoc->base.sk; struct sock *sk = asoc->base.sk;
struct socket *sock; struct socket *sock;
struct inet_sock *inetsk;
int err = 0; int err = 0;
/* An association cannot be branched off from an already peeled-off /* 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,6 +3390,14 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc,
* asoc to the newsk. * asoc to the newsk.
*/ */
sctp_sock_migrate(sk, sock->sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH); 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; *sockp = sock;
return err; return err;
......
...@@ -323,7 +323,7 @@ static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info * ...@@ -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.replay_window = p->replay_window;
x->props.reqid = p->reqid; x->props.reqid = p->reqid;
x->props.family = p->family; 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; x->props.flags = p->flags;
} }
...@@ -545,7 +545,7 @@ static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) ...@@ -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->lft, &x->lft, sizeof(p->lft));
memcpy(&p->curlft, &x->curlft, sizeof(p->curlft)); memcpy(&p->curlft, &x->curlft, sizeof(p->curlft));
memcpy(&p->stats, &x->stats, sizeof(p->stats)); 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->mode = x->props.mode;
p->replay_window = x->props.replay_window; p->replay_window = x->props.replay_window;
p->reqid = x->props.reqid; p->reqid = x->props.reqid;
......
...@@ -3313,7 +3313,13 @@ static int selinux_socket_getpeername(struct socket *sock) ...@@ -3313,7 +3313,13 @@ static int selinux_socket_getpeername(struct socket *sock)
static int selinux_socket_setsockopt(struct socket *sock,int level,int optname) 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, static int selinux_socket_getsockopt(struct socket *sock, int level,
......
...@@ -53,6 +53,9 @@ void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec, ...@@ -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, void selinux_netlbl_sk_clone_security(struct sk_security_struct *ssec,
struct sk_security_struct *newssec); struct sk_security_struct *newssec);
int selinux_netlbl_inode_permission(struct inode *inode, int mask); int selinux_netlbl_inode_permission(struct inode *inode, int mask);
int selinux_netlbl_socket_setsockopt(struct socket *sock,
int level,
int optname);
#else #else
static inline void selinux_netlbl_cache_invalidate(void) static inline void selinux_netlbl_cache_invalidate(void)
{ {
...@@ -114,6 +117,13 @@ static inline int selinux_netlbl_inode_permission(struct inode *inode, ...@@ -114,6 +117,13 @@ static inline int selinux_netlbl_inode_permission(struct inode *inode,
{ {
return 0; return 0;
} }
static inline int selinux_netlbl_socket_setsockopt(struct socket *sock,
int level,
int optname)
{
return 0;
}
#endif /* CONFIG_NETLABEL */ #endif /* CONFIG_NETLABEL */
#endif #endif
...@@ -2682,4 +2682,41 @@ u32 selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb) ...@@ -2682,4 +2682,41 @@ u32 selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb)
return peer_sid; 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 */ #endif /* CONFIG_NETLABEL */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment