From 14ace024b1e16d2bb9445c8387494fbbd820a738 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 18 Dec 2009 16:28:05 -0500 Subject: SUNRPC: Fix up an error return value in gss_import_sec_context_kerberos() If the context allocation fails, the function currently returns a random error code, since the variable 'p' still points to a valid memory location. Ensure that it returns ENOMEM... Cc: stable@kernel.org Signed-off-by: Trond Myklebust --- net/sunrpc/auth_gss/gss_krb5_mech.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index ef45eba2248..2deb0ed72ff 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c @@ -131,8 +131,10 @@ gss_import_sec_context_kerberos(const void *p, struct krb5_ctx *ctx; int tmp; - if (!(ctx = kzalloc(sizeof(*ctx), GFP_NOFS))) + if (!(ctx = kzalloc(sizeof(*ctx), GFP_NOFS))) { + p = ERR_PTR(-ENOMEM); goto out_err; + } p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate)); if (IS_ERR(p)) -- cgit v1.2.3 From b891e4a05ef6beac85465295a032431577c66b16 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 18 Dec 2009 16:28:12 -0500 Subject: SUNRPC: Fix the return value in gss_import_sec_context() If the context allocation fails, it will return GSS_S_FAILURE, which is neither a valid error code, nor is it even negative. Return ENOMEM instead... Reported-by: Jeff Layton Cc: stable@kernel.org Signed-off-by: Trond Myklebust --- net/sunrpc/auth_gss/gss_mech_switch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index 6efbb0cd3c7..76e4c6f4ac3 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c @@ -252,7 +252,7 @@ gss_import_sec_context(const void *input_token, size_t bufsize, struct gss_ctx **ctx_id) { if (!(*ctx_id = kzalloc(sizeof(**ctx_id), GFP_KERNEL))) - return GSS_S_FAILURE; + return -ENOMEM; (*ctx_id)->mech_type = gss_mech_get(mech); return mech->gm_ops -- cgit v1.2.3 From 486bad2e40e938cd68fd853b7a9fa3115a9d3a4a Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 18 Dec 2009 16:28:20 -0500 Subject: sunrpc: on successful gss error pipe write, don't return error When handling the gssd downcall, the kernel should distinguish between a successful downcall that contains an error code and a failed downcall (i.e. where the parsing failed or some other sort of problem occurred). In the former case, gss_pipe_downcall should be returning the number of bytes written to the pipe instead of an error. In the event of other errors, we generally want the initiating task to retry the upcall so we set msg.errno to -EAGAIN. An unexpected error code here is a bug however, so BUG() in that case. Signed-off-by: Jeff Layton Cc: stable@kernel.org Signed-off-by: Trond Myklebust --- net/sunrpc/auth_gss/auth_gss.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 3c3c50f38a1..66cb89c1834 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -644,7 +644,22 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) p = gss_fill_context(p, end, ctx, gss_msg->auth->mech); if (IS_ERR(p)) { err = PTR_ERR(p); - gss_msg->msg.errno = (err == -EAGAIN) ? -EAGAIN : -EACCES; + switch (err) { + case -EACCES: + gss_msg->msg.errno = err; + err = mlen; + break; + case -EFAULT: + case -ENOMEM: + case -EINVAL: + case -ENOSYS: + gss_msg->msg.errno = -EAGAIN; + break; + default: + printk(KERN_CRIT "%s: bad return from " + "gss_fill_context: %ld\n", __func__, err); + BUG(); + } goto err_release_msg; } gss_msg->ctx = gss_get_ctx(ctx); -- cgit v1.2.3 From ae24e578de02b87cce3dc59248c29b2ecb071e9e Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 22 Dec 2009 09:42:06 +0100 Subject: ipvs: ip_vs_wrr.c: use lib/gcd.c Remove the private version of the greatest common divider to use lib/gcd.c, the latter also implementing the a < b case. [akpm@linux-foundation.org: repair neighboring whitespace because the diff looked odd] Signed-off-by: Florian Fainelli Cc: Sergei Shtylyov Cc: Takashi Iwai Acked-by: Simon Horman Cc: Julius Volz Cc: David S. Miller Cc: Patrick McHardy Signed-off-by: Andrew Morton Signed-off-by: Patrick McHardy --- net/netfilter/ipvs/Kconfig | 3 ++- net/netfilter/ipvs/ip_vs_wrr.c | 15 +-------------- 2 files changed, 3 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/net/netfilter/ipvs/Kconfig b/net/netfilter/ipvs/Kconfig index 79a69805221..f2d76238b9b 100644 --- a/net/netfilter/ipvs/Kconfig +++ b/net/netfilter/ipvs/Kconfig @@ -112,7 +112,8 @@ config IP_VS_RR module, choose M here. If unsure, say N. config IP_VS_WRR - tristate "weighted round-robin scheduling" + tristate "weighted round-robin scheduling" + select GCD ---help--- The weighted robin-robin scheduling algorithm directs network connections to different real servers based on server weights diff --git a/net/netfilter/ipvs/ip_vs_wrr.c b/net/netfilter/ipvs/ip_vs_wrr.c index 6182e8ea0be..3c115fc1978 100644 --- a/net/netfilter/ipvs/ip_vs_wrr.c +++ b/net/netfilter/ipvs/ip_vs_wrr.c @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -38,20 +39,6 @@ struct ip_vs_wrr_mark { }; -/* - * Get the gcd of server weights - */ -static int gcd(int a, int b) -{ - int c; - - while ((c = a % b)) { - a = b; - b = c; - } - return b; -} - static int ip_vs_wrr_gcd_weight(struct ip_vs_service *svc) { struct ip_vs_dest *dest; -- cgit v1.2.3 From 1f731b63752dac76ff4dbf568a08ff2e3663316f Mon Sep 17 00:00:00 2001 From: Bernard Pidoux F6BVP Date: Thu, 17 Dec 2009 05:25:18 +0000 Subject: rose_loopback_timer sets VC number <= ROSE_DEFAULT_MAXVC cat /proc/net/rose displayed a rose sockets abnormal lci value, i.e. greater than maximum number of VCs per neighbour allowed. This number prevents further test of lci value during rose operations. Example (lines shortened) : [bernard]# cat /proc/net/rose dest_addr dest_call src_addr src_call dev lci neigh st vs vr va * * 2080175520 F6BVP-1 rose0 000 00000 0 0 0 0 2080175520 FPAD-0 2080175520 WP-0 rose0 FFE 00001 3 0 0 0 Here are the default parameters : linux/include/net/rose.h:#define ROSE_DEFAULT_MAXVC 50 /* Maximum number of VCs per neighbour */ linux/net/rose/af_rose.c:int sysctl_rose_maximum_vcs = ROSE_DEFAULT_MAXVC; With the following patch, rose_loopback_timer() attributes a VC number within limits. Signed-off-by: Bernard Pidoux Signed-off-by: David S. Miller --- net/rose/rose_loopback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/rose/rose_loopback.c b/net/rose/rose_loopback.c index 114df6eec8c..968e8bac1b5 100644 --- a/net/rose/rose_loopback.c +++ b/net/rose/rose_loopback.c @@ -75,7 +75,7 @@ static void rose_loopback_timer(unsigned long param) lci_i = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); frametype = skb->data[2]; dest = (rose_address *)(skb->data + 4); - lci_o = 0xFFF - lci_i; + lci_o = ROSE_DEFAULT_MAXVC + 1 - lci_i; skb_reset_transport_header(skb); -- cgit v1.2.3 From 8ffd32083c849dcf476e56e6c5f728c80797ecdd Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 21 Dec 2009 14:25:06 +0000 Subject: net/sctp/socket.c: squish warning net/sctp/socket.c: In function 'sctp_setsockopt_autoclose': net/sctp/socket.c:2090: warning: comparison is always false due to limited range of data type Cc: Andrei Pelinescu-Onciul Cc: Vlad Yasevich Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- net/sctp/socket.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 89ab66e5474..67fdac9d2d3 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2087,8 +2087,7 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval, if (copy_from_user(&sp->autoclose, optval, optlen)) return -EFAULT; /* make sure it won't exceed MAX_SCHEDULE_TIMEOUT */ - if (sp->autoclose > (MAX_SCHEDULE_TIMEOUT / HZ) ) - sp->autoclose = (__u32)(MAX_SCHEDULE_TIMEOUT / HZ) ; + sp->autoclose = min_t(long, sp->autoclose, MAX_SCHEDULE_TIMEOUT / HZ); return 0; } -- cgit v1.2.3 From 04bcef2a83f40c6db24222b27a52892cba39dffb Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Mon, 4 Jan 2010 16:37:12 +0100 Subject: ipvs: Add boundary check on ioctl arguments The ipvs code has a nifty system for doing the size of ioctl command copies; it defines an array with values into which it indexes the cmd to find the right length. Unfortunately, the ipvs code forgot to check if the cmd was in the range that the array provides, allowing for an index outside of the array, which then gives a "garbage" result into the length, which then gets used for copying into a stack buffer. Fix this by adding sanity checks on these as well as the copy size. [ horms@verge.net.au: adjusted limit to IP_VS_SO_GET_MAX ] Signed-off-by: Arjan van de Ven Acked-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Patrick McHardy --- net/netfilter/ipvs/ip_vs_ctl.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 6bde12da2fe..c37ac2d7bec 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -2077,6 +2077,10 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (cmd < IP_VS_BASE_CTL || cmd > IP_VS_SO_SET_MAX) + return -EINVAL; + if (len < 0 || len > MAX_ARG_LEN) + return -EINVAL; if (len != set_arglen[SET_CMDID(cmd)]) { pr_err("set_ctl: len %u != %u\n", len, set_arglen[SET_CMDID(cmd)]); @@ -2352,17 +2356,25 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) { unsigned char arg[128]; int ret = 0; + unsigned int copylen; if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (cmd < IP_VS_BASE_CTL || cmd > IP_VS_SO_GET_MAX) + return -EINVAL; + if (*len < get_arglen[GET_CMDID(cmd)]) { pr_err("get_ctl: len %u < %u\n", *len, get_arglen[GET_CMDID(cmd)]); return -EINVAL; } - if (copy_from_user(arg, user, get_arglen[GET_CMDID(cmd)]) != 0) + copylen = get_arglen[GET_CMDID(cmd)]; + if (copylen > 128) + return -EINVAL; + + if (copy_from_user(arg, user, copylen) != 0) return -EFAULT; if (mutex_lock_interruptible(&__ip_vs_mutex)) -- cgit v1.2.3 From 6c8530993e1fdf1d6af0403e796fe14d80b4b097 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 6 Jan 2010 17:26:27 -0500 Subject: sunrpc: fix build-time warning Fix auth_gss printk format warning: net/sunrpc/auth_gss/auth_gss.c:660: warning: format '%ld' expects type 'long int', but argument 3 has type 'ssize_t' Signed-off-by: Randy Dunlap Acked-by: Jeff Layton Signed-off-by: Trond Myklebust --- net/sunrpc/auth_gss/auth_gss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 66cb89c1834..f7a7f8380e3 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -657,7 +657,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) break; default: printk(KERN_CRIT "%s: bad return from " - "gss_fill_context: %ld\n", __func__, err); + "gss_fill_context: %zd\n", __func__, err); BUG(); } goto err_release_msg; -- cgit v1.2.3 From b292cf9ce70d221c3f04ff62db5ab13d9a249ca8 Mon Sep 17 00:00:00 2001 From: Xiaotian Feng Date: Thu, 31 Dec 2009 10:52:36 +0800 Subject: sunrpc: fix peername failed on closed listener There're some warnings of "nfsd: peername failed (err 107)!" socket error -107 means Transport endpoint is not connected. This warning message was outputed by svc_tcp_accept() [net/sunrpc/svcsock.c], when kernel_getpeername returns -107. This means socket might be CLOSED. And svc_tcp_accept was called by svc_recv() [net/sunrpc/svc_xprt.c] if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) { newxpt = xprt->xpt_ops->xpo_accept(xprt); So this might happen when xprt->xpt_flags has both XPT_LISTENER and XPT_CLOSE. Let's take a look at commit b0401d72, this commit has moved the close processing after do recvfrom method, but this commit also introduces this warnings, if the xpt_flags has both XPT_LISTENER and XPT_CLOSED, we should close it, not accpet then close. Signed-off-by: Xiaotian Feng Cc: J. Bruce Fields Cc: Neil Brown Cc: Trond Myklebust Cc: David S. Miller Cc: stable@kernel.org Signed-off-by: J. Bruce Fields --- net/sunrpc/svc_xprt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 2c58b75a236..810ffe8a636 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -699,7 +699,8 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) spin_unlock_bh(&pool->sp_lock); len = 0; - if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) { + if (test_bit(XPT_LISTENER, &xprt->xpt_flags) && + !test_bit(XPT_CLOSE, &xprt->xpt_flags)) { struct svc_xprt *newxpt; newxpt = xprt->xpt_ops->xpo_accept(xprt); if (newxpt) { -- cgit v1.2.3 From 7ad6848c7e81a603605fad3f3575841aab004eea Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Wed, 6 Jan 2010 20:37:01 -0800 Subject: ip: fix mc_loop checks for tunnels with multicast outer addresses When we have L3 tunnels with different inner/outer families (i.e. IPV4/IPV6) which use a multicast address as the outer tunnel destination address, multicast packets will be loopbacked back to the sending socket even if IP*_MULTICAST_LOOP is set to disabled. The mc_loop flag is present in the family specific part of the socket (e.g. the IPv4 or IPv4 specific part). setsockopt sets the inner family mc_loop flag. When the packet is pushed through the L3 tunnel it will eventually be processed by the outer family which if different will check the flag in a different part of the socket then it was set. Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- net/ipv4/ip_output.c | 2 +- net/ipv6/ip6_output.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index e34013a78ef..3451799e3db 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -254,7 +254,7 @@ int ip_mc_output(struct sk_buff *skb) */ if (rt->rt_flags&RTCF_MULTICAST) { - if ((!sk || inet_sk(sk)->mc_loop) + if (sk_mc_loop(sk) #ifdef CONFIG_IP_MROUTE /* Small optimization: do not loopback not local frames, which returned after forwarding; they will be dropped diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index cd48801a8d6..eb6d0972863 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -121,10 +121,9 @@ static int ip6_output2(struct sk_buff *skb) skb->dev = dev; if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) { - struct ipv6_pinfo* np = skb->sk ? inet6_sk(skb->sk) : NULL; struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); - if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) && + if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(skb->sk) && ((mroute6_socket(dev_net(dev)) && !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) || ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr, -- cgit v1.2.3 From aaff23a95aea5f000895f50d90e91f1e2f727002 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 7 Jan 2010 18:33:18 +0100 Subject: netfilter: nf_ct_ftp: fix out of bounds read in update_nl_seq() As noticed by Dan Carpenter , update_nl_seq() currently contains an out of bounds read of the seq_aft_nl array when looking for the oldest sequence number position. Fix it to only compare valid positions. Cc: stable@kernel.org Signed-off-by: Patrick McHardy --- net/netfilter/nf_conntrack_ftp.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c index 38ea7ef3ccd..f0732aa18e4 100644 --- a/net/netfilter/nf_conntrack_ftp.c +++ b/net/netfilter/nf_conntrack_ftp.c @@ -323,24 +323,24 @@ static void update_nl_seq(struct nf_conn *ct, u32 nl_seq, struct nf_ct_ftp_master *info, int dir, struct sk_buff *skb) { - unsigned int i, oldest = NUM_SEQ_TO_REMEMBER; + unsigned int i, oldest; /* Look for oldest: if we find exact match, we're done. */ for (i = 0; i < info->seq_aft_nl_num[dir]; i++) { if (info->seq_aft_nl[dir][i] == nl_seq) return; - - if (oldest == info->seq_aft_nl_num[dir] || - before(info->seq_aft_nl[dir][i], - info->seq_aft_nl[dir][oldest])) - oldest = i; } if (info->seq_aft_nl_num[dir] < NUM_SEQ_TO_REMEMBER) { info->seq_aft_nl[dir][info->seq_aft_nl_num[dir]++] = nl_seq; - } else if (oldest != NUM_SEQ_TO_REMEMBER && - after(nl_seq, info->seq_aft_nl[dir][oldest])) { - info->seq_aft_nl[dir][oldest] = nl_seq; + } else { + if (before(info->seq_aft_nl[dir][0], info->seq_aft_nl[dir][1])) + oldest = 0; + else + oldest = 1; + + if (after(nl_seq, info->seq_aft_nl[dir][oldest])) + info->seq_aft_nl[dir][oldest] = nl_seq; } } -- cgit v1.2.3 From 704da560c0a0120d8869187f511491a00951a1d3 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Fri, 8 Jan 2010 00:00:09 -0800 Subject: tcp: update the netstamp_needed counter when cloning sockets This fixes a netstamp_needed accounting issue when the listen socket has SO_TIMESTAMP set: s = socket(AF_INET, SOCK_STREAM, 0); setsockopt(s, SOL_SOCKET, SO_TIMESTAMP, 1); -> netstamp_needed = 1 bind(s, ...); listen(s, ...); s2 = accept(s, ...); -> netstamp_needed = 1 close(s2); -> netstamp_needed = 0 close(s); -> netstamp_needed = -1 Signed-off-by: Octavian Purdila Signed-off-by: David S. Miller --- net/core/sock.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net') diff --git a/net/core/sock.c b/net/core/sock.c index 76ff58d43e2..e1f6f225f01 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1205,6 +1205,10 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority) if (newsk->sk_prot->sockets_allocated) percpu_counter_inc(newsk->sk_prot->sockets_allocated); + + if (sock_flag(newsk, SOCK_TIMESTAMP) || + sock_flag(newsk, SOCK_TIMESTAMPING_RX_SOFTWARE)) + net_enable_timestamp(); } out: return newsk; -- cgit v1.2.3 From dce766af541f6605fa9889892c0280bab31c66ab Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 8 Jan 2010 17:31:24 +0100 Subject: netfilter: ebtables: enforce CAP_NET_ADMIN normal users are currently allowed to set/modify ebtables rules. Restrict it to processes with CAP_NET_ADMIN. Note that this cannot be reproduced with unmodified ebtables binary because it uses SOCK_RAW. Signed-off-by: Florian Westphal Cc: stable@kernel.org Signed-off-by: Patrick McHardy --- net/bridge/netfilter/ebtables.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net') diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index bd1c65425d4..0b7f262cd14 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -1406,6 +1406,9 @@ static int do_ebt_set_ctl(struct sock *sk, { int ret; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + switch(cmd) { case EBT_SO_SET_ENTRIES: ret = do_replace(sock_net(sk), user, len); @@ -1425,6 +1428,9 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) struct ebt_replace tmp; struct ebt_table *t; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (copy_from_user(&tmp, user, sizeof(tmp))) return -EFAULT; -- cgit v1.2.3 From eb70df13ee52dbc0f2c0ffd8ed34a8cd27440baf Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Sun, 10 Jan 2010 22:04:19 +0000 Subject: af_packet: Don't use skb after dev_queue_xmit() tpacket_snd() can change and kfree an skb after dev_queue_xmit(), which is illegal. With debugging by: Stephen Hemminger Reported-by: Michael Breuer With help from: David S. Miller Signed-off-by: Jarek Poplawski Tested-by: Michael Breuer Signed-off-by: David S. Miller --- net/packet/af_packet.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index e0516a22be2..f126d18dbdc 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1021,8 +1021,20 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) status = TP_STATUS_SEND_REQUEST; err = dev_queue_xmit(skb); - if (unlikely(err > 0 && (err = net_xmit_errno(err)) != 0)) - goto out_xmit; + if (unlikely(err > 0)) { + err = net_xmit_errno(err); + if (err && __packet_get_status(po, ph) == + TP_STATUS_AVAILABLE) { + /* skb was destructed already */ + skb = NULL; + goto out_status; + } + /* + * skb was dropped but not destructed yet; + * let's treat it like congestion or err < 0 + */ + err = 0; + } packet_increment_head(&po->tx_ring); len_sum += tp_len; } while (likely((ph != NULL) || @@ -1033,9 +1045,6 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) err = len_sum; goto out_put; -out_xmit: - skb->destructor = sock_wfree; - atomic_dec(&po->tx_ring.pending); out_status: __packet_set_status(po, ph, status); kfree_skb(skb); -- cgit v1.2.3