Skip to content

Commit a192144

Browse files
committed
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
2 parents b732d96 + b9f75f4 commit a192144

File tree

9 files changed

+52
-7
lines changed

9 files changed

+52
-7
lines changed

drivers/net/pppoe.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -942,7 +942,7 @@ static int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock,
942942
m->msg_namelen = 0;
943943

944944
if (skb) {
945-
total_len = min(total_len, skb->len);
945+
total_len = min_t(size_t, total_len, skb->len);
946946
error = skb_copy_datagram_iovec(skb, 0, m->msg_iov, total_len);
947947
if (error == 0)
948948
error = total_len;

include/net/ipv6.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,12 @@ static inline int ipv6_addr_any(const struct in6_addr *a)
367367
a->s6_addr32[2] | a->s6_addr32[3] ) == 0);
368368
}
369369

370+
static inline int ipv6_addr_loopback(const struct in6_addr *a)
371+
{
372+
return ((a->s6_addr32[0] | a->s6_addr32[1] |
373+
a->s6_addr32[2] | (a->s6_addr32[3] ^ htonl(1))) == 0);
374+
}
375+
370376
static inline int ipv6_addr_v4mapped(const struct in6_addr *a)
371377
{
372378
return ((a->s6_addr32[0] | a->s6_addr32[1] |

include/net/net_namespace.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ extern struct list_head net_namespace_list;
9595
#ifdef CONFIG_NET_NS
9696
extern void __put_net(struct net *net);
9797

98+
static inline int net_alive(struct net *net)
99+
{
100+
return net && atomic_read(&net->count);
101+
}
102+
98103
static inline struct net *get_net(struct net *net)
99104
{
100105
atomic_inc(&net->count);
@@ -125,6 +130,12 @@ int net_eq(const struct net *net1, const struct net *net2)
125130
return net1 == net2;
126131
}
127132
#else
133+
134+
static inline int net_alive(struct net *net)
135+
{
136+
return 1;
137+
}
138+
128139
static inline struct net *get_net(struct net *net)
129140
{
130141
return net;

net/core/dev.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2077,6 +2077,10 @@ int netif_receive_skb(struct sk_buff *skb)
20772077

20782078
rcu_read_lock();
20792079

2080+
/* Don't receive packets in an exiting network namespace */
2081+
if (!net_alive(dev_net(skb->dev)))
2082+
goto out;
2083+
20802084
#ifdef CONFIG_NET_CLS_ACT
20812085
if (skb->tc_verd & TC_NCLS) {
20822086
skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);

net/core/net_namespace.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@ static void cleanup_net(struct work_struct *work)
140140
struct pernet_operations *ops;
141141
struct net *net;
142142

143+
/* Be very certain incoming network packets will not find us */
144+
rcu_barrier();
145+
143146
net = container_of(work, struct net, work);
144147

145148
mutex_lock(&net_mutex);

net/ipv6/ip6_input.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,15 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
102102
if (hdr->version != 6)
103103
goto err;
104104

105+
/*
106+
* RFC4291 2.5.3
107+
* A packet received on an interface with a destination address
108+
* of loopback must be dropped.
109+
*/
110+
if (!(dev->flags & IFF_LOOPBACK) &&
111+
ipv6_addr_loopback(&hdr->daddr))
112+
goto err;
113+
105114
skb->transport_header = skb->network_header + sizeof(*hdr);
106115
IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
107116

net/ipv6/ipv6_sockglue.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -345,18 +345,21 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
345345
case IPV6_DSTOPTS:
346346
{
347347
struct ipv6_txoptions *opt;
348+
349+
/* remove any sticky options header with a zero option
350+
* length, per RFC3542.
351+
*/
348352
if (optlen == 0)
349353
optval = NULL;
354+
else if (optlen < sizeof(struct ipv6_opt_hdr) ||
355+
optlen & 0x7 || optlen > 8 * 255)
356+
goto e_inval;
350357

351358
/* hop-by-hop / destination options are privileged option */
352359
retv = -EPERM;
353360
if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW))
354361
break;
355362

356-
if (optlen < sizeof(struct ipv6_opt_hdr) ||
357-
optlen & 0x7 || optlen > 8 * 255)
358-
goto e_inval;
359-
360363
opt = ipv6_renew_options(sk, np->opt, optname,
361364
(struct ipv6_opt_hdr __user *)optval,
362365
optlen);

net/mac80211/tx.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1132,7 +1132,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
11321132
ieee80211_tx_handler *handler;
11331133
struct ieee80211_tx_data tx;
11341134
ieee80211_tx_result res = TX_DROP, res_prepare;
1135-
int ret, i;
1135+
int ret, i, retries = 0;
11361136

11371137
WARN_ON(__ieee80211_queue_pending(local, control->queue));
11381138

@@ -1216,6 +1216,13 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
12161216
if (!__ieee80211_queue_stopped(local, control->queue)) {
12171217
clear_bit(IEEE80211_LINK_STATE_PENDING,
12181218
&local->state[control->queue]);
1219+
retries++;
1220+
/*
1221+
* Driver bug, it's rejecting packets but
1222+
* not stopping queues.
1223+
*/
1224+
if (WARN_ON_ONCE(retries > 5))
1225+
goto drop;
12191226
goto retry;
12201227
}
12211228
memcpy(&store->control, control,

net/sctp/socket.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4401,7 +4401,9 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
44014401
if (copy_from_user(&getaddrs, optval, len))
44024402
return -EFAULT;
44034403

4404-
if (getaddrs.addr_num <= 0) return -EINVAL;
4404+
if (getaddrs.addr_num <= 0 ||
4405+
getaddrs.addr_num >= (INT_MAX / sizeof(union sctp_addr)))
4406+
return -EINVAL;
44054407
/*
44064408
* For UDP-style sockets, id specifies the association to query.
44074409
* If the id field is set to the value '0' then the locally bound

0 commit comments

Comments
 (0)