Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6:
  netns: Don't receive new packets in a dead network namespace.
  sctp: Make sure N * sizeof(union sctp_addr) does not overflow.
  pppoe: warning fix
  ipv6: Drop packets for loopback address from outside of the box.
  ipv6: Remove options header when setsockopt's optlen is 0
  mac80211: detect driver tx bugs
This commit is contained in:
Linus Torvalds 2008-06-21 08:44:08 -07:00
commit a19214430d
9 changed files with 52 additions and 7 deletions

View File

@ -942,7 +942,7 @@ static int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock,
m->msg_namelen = 0; m->msg_namelen = 0;
if (skb) { if (skb) {
total_len = min(total_len, skb->len); total_len = min_t(size_t, total_len, skb->len);
error = skb_copy_datagram_iovec(skb, 0, m->msg_iov, total_len); error = skb_copy_datagram_iovec(skb, 0, m->msg_iov, total_len);
if (error == 0) if (error == 0)
error = total_len; error = total_len;

View File

@ -367,6 +367,12 @@ static inline int ipv6_addr_any(const struct in6_addr *a)
a->s6_addr32[2] | a->s6_addr32[3] ) == 0); a->s6_addr32[2] | a->s6_addr32[3] ) == 0);
} }
static inline int ipv6_addr_loopback(const struct in6_addr *a)
{
return ((a->s6_addr32[0] | a->s6_addr32[1] |
a->s6_addr32[2] | (a->s6_addr32[3] ^ htonl(1))) == 0);
}
static inline int ipv6_addr_v4mapped(const struct in6_addr *a) static inline int ipv6_addr_v4mapped(const struct in6_addr *a)
{ {
return ((a->s6_addr32[0] | a->s6_addr32[1] | return ((a->s6_addr32[0] | a->s6_addr32[1] |

View File

@ -95,6 +95,11 @@ extern struct list_head net_namespace_list;
#ifdef CONFIG_NET_NS #ifdef CONFIG_NET_NS
extern void __put_net(struct net *net); extern void __put_net(struct net *net);
static inline int net_alive(struct net *net)
{
return net && atomic_read(&net->count);
}
static inline struct net *get_net(struct net *net) static inline struct net *get_net(struct net *net)
{ {
atomic_inc(&net->count); atomic_inc(&net->count);
@ -125,6 +130,12 @@ int net_eq(const struct net *net1, const struct net *net2)
return net1 == net2; return net1 == net2;
} }
#else #else
static inline int net_alive(struct net *net)
{
return 1;
}
static inline struct net *get_net(struct net *net) static inline struct net *get_net(struct net *net)
{ {
return net; return net;

View File

@ -2077,6 +2077,10 @@ int netif_receive_skb(struct sk_buff *skb)
rcu_read_lock(); rcu_read_lock();
/* Don't receive packets in an exiting network namespace */
if (!net_alive(dev_net(skb->dev)))
goto out;
#ifdef CONFIG_NET_CLS_ACT #ifdef CONFIG_NET_CLS_ACT
if (skb->tc_verd & TC_NCLS) { if (skb->tc_verd & TC_NCLS) {
skb->tc_verd = CLR_TC_NCLS(skb->tc_verd); skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);

View File

@ -140,6 +140,9 @@ static void cleanup_net(struct work_struct *work)
struct pernet_operations *ops; struct pernet_operations *ops;
struct net *net; struct net *net;
/* Be very certain incoming network packets will not find us */
rcu_barrier();
net = container_of(work, struct net, work); net = container_of(work, struct net, work);
mutex_lock(&net_mutex); mutex_lock(&net_mutex);

View File

@ -102,6 +102,15 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
if (hdr->version != 6) if (hdr->version != 6)
goto err; goto err;
/*
* RFC4291 2.5.3
* A packet received on an interface with a destination address
* of loopback must be dropped.
*/
if (!(dev->flags & IFF_LOOPBACK) &&
ipv6_addr_loopback(&hdr->daddr))
goto err;
skb->transport_header = skb->network_header + sizeof(*hdr); skb->transport_header = skb->network_header + sizeof(*hdr);
IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr); IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);

View File

@ -345,18 +345,21 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
case IPV6_DSTOPTS: case IPV6_DSTOPTS:
{ {
struct ipv6_txoptions *opt; struct ipv6_txoptions *opt;
/* remove any sticky options header with a zero option
* length, per RFC3542.
*/
if (optlen == 0) if (optlen == 0)
optval = NULL; optval = NULL;
else if (optlen < sizeof(struct ipv6_opt_hdr) ||
optlen & 0x7 || optlen > 8 * 255)
goto e_inval;
/* hop-by-hop / destination options are privileged option */ /* hop-by-hop / destination options are privileged option */
retv = -EPERM; retv = -EPERM;
if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW)) if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW))
break; break;
if (optlen < sizeof(struct ipv6_opt_hdr) ||
optlen & 0x7 || optlen > 8 * 255)
goto e_inval;
opt = ipv6_renew_options(sk, np->opt, optname, opt = ipv6_renew_options(sk, np->opt, optname,
(struct ipv6_opt_hdr __user *)optval, (struct ipv6_opt_hdr __user *)optval,
optlen); optlen);

View File

@ -1132,7 +1132,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
ieee80211_tx_handler *handler; ieee80211_tx_handler *handler;
struct ieee80211_tx_data tx; struct ieee80211_tx_data tx;
ieee80211_tx_result res = TX_DROP, res_prepare; ieee80211_tx_result res = TX_DROP, res_prepare;
int ret, i; int ret, i, retries = 0;
WARN_ON(__ieee80211_queue_pending(local, control->queue)); WARN_ON(__ieee80211_queue_pending(local, control->queue));
@ -1216,6 +1216,13 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
if (!__ieee80211_queue_stopped(local, control->queue)) { if (!__ieee80211_queue_stopped(local, control->queue)) {
clear_bit(IEEE80211_LINK_STATE_PENDING, clear_bit(IEEE80211_LINK_STATE_PENDING,
&local->state[control->queue]); &local->state[control->queue]);
retries++;
/*
* Driver bug, it's rejecting packets but
* not stopping queues.
*/
if (WARN_ON_ONCE(retries > 5))
goto drop;
goto retry; goto retry;
} }
memcpy(&store->control, control, memcpy(&store->control, control,

View File

@ -4401,7 +4401,9 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
if (copy_from_user(&getaddrs, optval, len)) if (copy_from_user(&getaddrs, optval, len))
return -EFAULT; return -EFAULT;
if (getaddrs.addr_num <= 0) return -EINVAL; if (getaddrs.addr_num <= 0 ||
getaddrs.addr_num >= (INT_MAX / sizeof(union sctp_addr)))
return -EINVAL;
/* /*
* For UDP-style sockets, id specifies the association to query. * For UDP-style sockets, id specifies the association to query.
* If the id field is set to the value '0' then the locally bound * If the id field is set to the value '0' then the locally bound