* Re: [PATCH] Fix NULL pointer dereference on firmware name for early calls to get_drvinfo.
From: David Miller @ 2012-03-31 0:51 UTC (permalink / raw)
To: notting; +Cc: netdev, wimax, inaky.perez-gonzalez
In-Reply-To: <1333139045-18170-1-git-send-email-notting@redhat.com>
From: Bill Nottingham <notting@redhat.com>
Date: Fri, 30 Mar 2012 16:24:05 -0400
> The driver comments show an initialization sequence of:
> * i2400m_setup()
> * i2400m->bus_setup()
> * i2400m_bootrom_init()
> * register_netdev()
> * wimax_dev_add()
> * i2400m_dev_start()
> * __i2400m_dev_start()
> * i2400m_dev_bootstrap()
>
> dev_bootstrap() is where the firmware is loaded. So, if something calls
> get_drvinfo() from a register_netdevice_notifier (such as the cnic driver),
> we won't have a firmware name, and strncpy will crash.
>
> https://bugzilla.redhat.com/show_bug.cgi?id=808603
>
> Signed-off-by: Bill Nottingham <notting@redhat.com>
Already fixed in current sources.
^ permalink raw reply
* 答复: 答复: 答复: [PATCH] set fake_rtable's dst to NULL to avoid kernel Oops.
From: Peter Huang (Peng) @ 2012-03-31 1:26 UTC (permalink / raw)
To: 'Eric Dumazet'
Cc: linux-kernel, harry.majun, zhoukang7, 'netdev'
In-Reply-To: <1333020682.2325.517.camel@edumazet-glaptop>
> > >Check net/bridge/br_netfilter.c and commits e688a6048076 (net: introduce
> > >DST_NOPEER dst flag ) 4adf0af6818f3ea5 (bridge: send correct MTU value
> > >in PMTU (revised))
Hi, Eric
I confirmed the patch contents again.
For our case, NF_INET_PRE_ROUTING is involved, not NF_BR_LOCAL_IN.
It seems pre-routing is not included in the patch you mentioned.
BTW, our pkts are all ipv6 DHCP pkts(with MAC 33 33 00 01 00 02).
We verified the patch bellow, and this works fine, no WARN_ON happened.
--------------------------------
Peter Huang(peng)
> On Thu, 2012-03-29 at 17:38 +0800, Peter Huang (Peng) wrote:
> > Thks for your mail.
> >
> > >Check net/bridge/br_netfilter.c and commits e688a6048076 (net: introduce
> > >DST_NOPEER dst flag ) 4adf0af6818f3ea5 (bridge: send correct MTU value
> > >in PMTU (revised))
> >
> > This patch already included in kernel-3.3, but for our case, virtual tap device's delayed
> > Deletion will also cause kernel oops even in kernel3.3.
>
> I was suggesting you take a look at the commit content ;)
>
> Then you can see the code in br_nf_local_in(), a bit cleaner than yours.
>
^ permalink raw reply
* Re: [PATCH v17 08/15] seccomp: add system call filtering using BPF
From: Vladimir Murzin @ 2012-03-31 4:40 UTC (permalink / raw)
To: Will Drewry
Cc: linux-kernel, linux-security-module, linux-arch, linux-doc,
kernel-hardening, netdev, x86, arnd, davem, hpa, mingo, oleg,
peterz, rdunlap, mcgrathr, tglx, luto, eparis, serge.hallyn, djm,
scarybeasts, indan, pmoore, akpm, corbet, eric.dumazet, markus,
coreyb, keescook, jmorris
In-Reply-To: <1333051320-30872-9-git-send-email-wad@chromium.org>
Hi Will,
On Thu, Mar 29, 2012 at 03:01:53PM -0500, Will Drewry wrote:
snipped
> +
> +/* Limit any path through the tree to 256KB worth of instructions. */
> +#define MAX_INSNS_PER_PATH ((1 << 18) / sizeof(struct sock_filter))
> +
> +static void seccomp_filter_log_failure(int syscall)
> +{
> + int compat = 0;
> +#ifdef CONFIG_COMPAT
> + compat = is_compat_task();
> +#endif
> + pr_info("%s[%d]: %ssystem call %d blocked at 0x%lx\n",
> + current->comm, task_pid_nr(current),
> + (compat ? "compat " : ""),
> + syscall, KSTK_EIP(current));
> +}
snipped
> +/**
> + * seccomp_attach_user_filter - attaches a user-supplied sock_fprog
> + * @user_filter: pointer to the user data containing a sock_fprog.
> + *
> + * Returns 0 on success and non-zero otherwise.
> + */
> +long seccomp_attach_user_filter(char __user *user_filter)
> +{
> + struct sock_fprog fprog;
> + long ret = -EFAULT;
> +
> +#ifdef CONFIG_COMPAT
> + if (is_compat_task()) {
> + struct compat_sock_fprog fprog32;
> + if (copy_from_user(&fprog32, user_filter, sizeof(fprog32)))
> + goto out;
> + fprog.len = fprog32.len;
> + fprog.filter = compat_ptr(fprog32.filter);
> + } else /* falls through to the if below. */
> +#endif
> + if (copy_from_user(&fprog, user_filter, sizeof(fprog)))
> + goto out;
> + ret = seccomp_attach_filter(&fprog);
> +out:
> + return ret;
> +}
Do we really need to surround is_compat_task() with CNFIG_COMPAT?
It seems that this case has already handled in compat.h [1]
[1] http://lxr.linux.no/#linux+v3.3/include/linux/compat.h#L566
Best wishes
Vladimir Murzin
^ permalink raw reply
* Re: 答复: 答复: 答复: [PATCH] set fake_rtable's dst to NULL to avoid kernel Oops.
From: Eric Dumazet @ 2012-03-31 5:41 UTC (permalink / raw)
To: Peter Huang (Peng); +Cc: linux-kernel, harry.majun, zhoukang7, 'netdev'
In-Reply-To: <004d01cd0edd$593f3bd0$0bbdb370$%huangpeng@huawei.com>
On Sat, 2012-03-31 at 09:26 +0800, Peter Huang (Peng) wrote:
> > > >Check net/bridge/br_netfilter.c and commits e688a6048076 (net: introduce
> > > >DST_NOPEER dst flag ) 4adf0af6818f3ea5 (bridge: send correct MTU value
> > > >in PMTU (revised))
>
> Hi, Eric
>
> I confirmed the patch contents again.
> For our case, NF_INET_PRE_ROUTING is involved, not NF_BR_LOCAL_IN.
> It seems pre-routing is not included in the patch you mentioned.
> BTW, our pkts are all ipv6 DHCP pkts(with MAC 33 33 00 01 00 02).
>
> We verified the patch bellow, and this works fine, no WARN_ON happened.
Hi Peter
I claim that your patch is not the good one and you need to refine it.
First, code is not needed if CONFIG_BRIDGE_NETFILTER is not set.
In fact, if CONFIG_BRIDGE_NETFILTER is not set, compilation will fail
since fake_rtable doesnt exist in "struct net_bridge", so you fix a bug
and introduce a new one.
CC [M] net/bridge/br_forward.o
net/bridge/br_forward.c: In function ‘__br_forward’:
net/bridge/br_forward.c:94: error: ‘struct sk_buff’ has no member named ‘_skb_dst’
net/bridge/br_forward.c:94: error: ‘struct net_bridge’ has no member named ‘fake_rtable’
make[1]: *** [net/bridge/br_forward.o] Error 1
make: *** [_module_net/bridge] Error 2
Then, the test is using obsolete dst internals and cast that should not
be in a C file. :
if (skb->_skb_dst == (unsigned long)&to->br->fake_rtable)
So I suggested you take a look at net/bridge/br_netfilter.c code to see
how this can be done properly. Maybe you need to add a helper in an
include file to make this proper.
I hope this is now clear to you, because your initial patch cannot be
applied as is. If you want full credit for this work, you must go a step
forward, or else another guy will finish the job.
Thanks
^ permalink raw reply
* 答复: 答复: 答复: 答复: [PATCH] set fake_rtable's dst to NULL to avoid kernel Oops.
From: Peter Huang (Peng) @ 2012-03-31 7:29 UTC (permalink / raw)
To: 'Eric Dumazet'
Cc: linux-kernel, harry.majun, zhoukang7, 'netdev'
In-Reply-To: <1333172486.2325.3101.camel@edumazet-glaptop>
Hi, Eric
Thanks very much for your reply.
I will refine this patch and send it out later.
--------------------------------
Peter Huang(peng)
> -----邮件原件-----
> 发件人: Eric Dumazet [mailto:eric.dumazet@gmail.com]
> 发送时间: 2012年3月31日 13:41
> 收件人: Peter Huang (Peng)
> 抄送: linux-kernel@vger.kernel.org; harry.majun@huawei.com; zhoukang7@huawei.com; 'netdev'
> 主题: Re: 答复: 答复: 答复: [PATCH] set fake_rtable's dst to NULL to avoid kernel Oops.
>
> On Sat, 2012-03-31 at 09:26 +0800, Peter Huang (Peng) wrote:
> > > > >Check net/bridge/br_netfilter.c and commits e688a6048076 (net: introduce
> > > > >DST_NOPEER dst flag ) 4adf0af6818f3ea5 (bridge: send correct MTU value
> > > > >in PMTU (revised))
> >
> > Hi, Eric
> >
> > I confirmed the patch contents again.
> > For our case, NF_INET_PRE_ROUTING is involved, not NF_BR_LOCAL_IN.
> > It seems pre-routing is not included in the patch you mentioned.
> > BTW, our pkts are all ipv6 DHCP pkts(with MAC 33 33 00 01 00 02).
> >
> > We verified the patch bellow, and this works fine, no WARN_ON happened.
>
> Hi Peter
>
> I claim that your patch is not the good one and you need to refine it.
>
> First, code is not needed if CONFIG_BRIDGE_NETFILTER is not set.
>
> In fact, if CONFIG_BRIDGE_NETFILTER is not set, compilation will fail
> since fake_rtable doesnt exist in "struct net_bridge", so you fix a bug
> and introduce a new one.
>
> CC [M] net/bridge/br_forward.o
> net/bridge/br_forward.c: In function ‘__br_forward’:
> net/bridge/br_forward.c:94: error: ‘struct sk_buff’ has no member named ‘_skb_dst’
> net/bridge/br_forward.c:94: error: ‘struct net_bridge’ has no member named ‘fake_rtable’
> make[1]: *** [net/bridge/br_forward.o] Error 1
> make: *** [_module_net/bridge] Error 2
>
>
> Then, the test is using obsolete dst internals and cast that should not
> be in a C file. :
>
> if (skb->_skb_dst == (unsigned long)&to->br->fake_rtable)
>
> So I suggested you take a look at net/bridge/br_netfilter.c code to see
> how this can be done properly. Maybe you need to add a helper in an
> include file to make this proper.
>
> I hope this is now clear to you, because your initial patch cannot be
> applied as is. If you want full credit for this work, you must go a step
> forward, or else another guy will finish the job.
>
> Thanks
^ permalink raw reply
* Re: question about frag_can_reassemble()
From: Marek Lindner @ 2012-03-31 8:52 UTC (permalink / raw)
To: b.a.t.m.a.n-ZwoEplunGu2X36UT3dwllkB+6BGkLq7r
Cc: netdev-u79uwXL29TY76Z2rM5mHXA, Dan Carpenter
In-Reply-To: <20120330200236.GH3289@mwanda>
Dan,
> I had a question about the code in frag_can_reassemble().
>
> net/batman-adv/unicast.h
> 51
> 52 merged_size = (skb->len - sizeof(*unicast_packet)) * 2;
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 53 merged_size += sizeof(struct unicast_packet) +
> uneven_correction; 54
> 55 return merged_size <= mtu;
> 56 }
>
> Can the skb->len be less than sizeof(*unicast_packet) (ie 20 bytes)?
> If "len" is less than 10 then we would return false but if it's
> over 10 then we would return true. Roughly.
the calling function checks for an existing unicast header. The call tree
looks like this:
recv_ucast_frag_packet() -> route_unicast_packet() -> frag_can_reassemble()
The first function does a unicast length check by calling
check_unicast_packet(). As a result we ensure that we at least have the length
of the unicast header in our packet unless we overlooked something ?
Regards,
Marek
^ permalink raw reply
* Re: [PATCH v5 2/2] Ethernet driver for the WIZnet W5100 chip
From: Francois Romieu @ 2012-03-31 9:40 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Mike Sinkovsky, netdev, linux-kernel
In-Reply-To: <1333099431.19659.15.camel@edumazet-laptop>
Eric Dumazet <eric.dumazet@gmail.com> :
> Le vendredi 30 mars 2012 ?? 13:00 +0600, Mike Sinkovsky a ??crit :
> > Tested and used in production with Blackfin BF531 embedded processor.
[...]
> > +static int w5100_start_tx(struct sk_buff *skb, struct net_device *ndev)
> > +{
> > + struct w5100_priv *priv = netdev_priv(ndev);
> > + u16 offset;
> > +
> > + if (w5100_read16(priv, W5100_S0_TX_FSR) < skb->len) {
>
> There is a race here.
>
> Interrupt came come right here before you set the stop_queue()
>
>
> > + netif_stop_queue(ndev);
>
> So Here I suggest adding a test again
>
> if (w5100_read16(priv, W5100_S0_TX_FSR) >= skb->len)
> netif_wake_queue(ndev);
> else
> return NETDEV_TX_BUSY;
The start_tx logic seems broken anyway: it claims it always can take
packets until it is given one it can't process. The driver should rather
do the opposite and stop queueing as soon as there is no guarantee for
the next packet.
--
Ueimor
^ permalink raw reply
* Re: [PATCH v5 2/2] Ethernet driver for the WIZnet W5100 chip
From: Francois Romieu @ 2012-03-31 9:46 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Mike Sinkovsky, netdev, linux-kernel
In-Reply-To: <20120331094014.GA7746@electric-eye.fr.zoreil.com>
Francois Romieu <romieu@fr.zoreil.com> :
[...]
> The start_tx logic seems broken anyway: it claims it always can take
> packets until it is given one it can't process. The driver should rather
> do the opposite and stop queueing as soon as there is no guarantee for
> the next packet.
Forget it: the driver stops queuing in this path anyway.
--
Ueimor
^ permalink raw reply
* [PATCH] net: bpf_jit: fix BPF_S_ALU_AND_K compilation
From: Indan Zupancic @ 2012-03-31 9:52 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev, stable, linux-kernel
Hello,
Finally, after much searching I found one little bug.
[PATCH] net: bpf_jit: fix BPF_S_ALU_AND_K compilation
Small typo resulted in bad code generation for certain
values of K for the BPF_S_ALU_AND_K instruction.
Signed-off-by: Indan Zupancic <indan@nul.nu>
---
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 7c1b765..28bc807 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -289,7 +289,7 @@ void bpf_jit_compile(struct sk_filter *fp)
EMIT2(0x24, K & 0xFF); /* and imm8,%al */
} else if (K >= 0xFFFF0000) {
EMIT2(0x66, 0x25); /* and imm16,%ax */
- EMIT2(K, 2);
+ EMIT(K, 2);
} else {
EMIT1_off32(0x25, K); /* and imm32,%eax */
}
^ permalink raw reply related
* Re: [PATCH v5 2/2] Ethernet driver for the WIZnet W5100 chip
From: Mike Sinkovsky @ 2012-03-31 9:52 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev, linux-kernel
In-Reply-To: <1333099431.19659.15.camel@edumazet-laptop>
30.03.2012 15:23, Eric Dumazet написал:
>> +static int w5100_start_tx(struct sk_buff *skb, struct net_device *ndev)
>> +{
>> + struct w5100_priv *priv = netdev_priv(ndev);
>> + u16 offset;
>> +
>> + if (w5100_read16(priv, W5100_S0_TX_FSR)< skb->len) {
>
> There is a race here.
> Interrupt came come right here before you set the stop_queue()
>
>> + netif_stop_queue(ndev);
>
> So Here I suggest adding a test again
>
> if (w5100_read16(priv, W5100_S0_TX_FSR)>= skb->len)
> netif_wake_queue(ndev);
> else
> return NETDEV_TX_BUSY;
>
>> + return NETDEV_TX_BUSY;
Maybe, but I cannot test this, sorry - when I set breakpoint on this
branch - it never triggered, on all my tests on all boards.
Appears that my processor is too slow and cannot feed packets fast enough.
But will do, maybe it triggers for someone on fastest processors.
--
Mike
^ permalink raw reply
* Re: [PATCH] net: bpf_jit: fix BPF_S_ALU_AND_K compilation
From: Eric Dumazet @ 2012-03-31 10:23 UTC (permalink / raw)
To: Indan Zupancic; +Cc: netdev, stable, linux-kernel
In-Reply-To: <40f4b91c5200771f223966f368095c63.squirrel@webmail.greenhost.nl>
On Sat, 2012-03-31 at 20:52 +1100, Indan Zupancic wrote:
> Hello,
>
> Finally, after much searching I found one little bug.
>
> [PATCH] net: bpf_jit: fix BPF_S_ALU_AND_K compilation
>
> Small typo resulted in bad code generation for certain
> values of K for the BPF_S_ALU_AND_K instruction.
>
> Signed-off-by: Indan Zupancic <indan@nul.nu>
> ---
>
> diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
> index 7c1b765..28bc807 100644
> --- a/arch/x86/net/bpf_jit_comp.c
> +++ b/arch/x86/net/bpf_jit_comp.c
> @@ -289,7 +289,7 @@ void bpf_jit_compile(struct sk_filter *fp)
> EMIT2(0x24, K & 0xFF); /* and imm8,%al */
> } else if (K >= 0xFFFF0000) {
> EMIT2(0x66, 0x25); /* and imm16,%ax */
> - EMIT2(K, 2);
> + EMIT(K, 2);
> } else {
> EMIT1_off32(0x25, K); /* and imm32,%eax */
> }
>
>
Thanks but it was already fixed.
commit 1d24fb3684f347226747c6b11ea426b7b992694e
Author: zhuangfeiran@ict.ac.cn <zhuangfeiran@ict.ac.cn>
Date: Wed Mar 28 23:27:00 2012 +0000
x86 bpf_jit: fix a bug in emitting the 16-bit immediate operand of AND
When K >= 0xFFFF0000, AND needs the two least significant bytes of K as
its operand, but EMIT2() gives it the least significant byte of K and
0x2. EMIT() should be used here to replace EMIT2().
Signed-off-by: Feiran Zhuang <zhuangfeiran@ict.ac.cn>
Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
^ permalink raw reply
* Re: [PATCH v5 2/2] Ethernet driver for the WIZnet W5100 chip
From: Eric Dumazet @ 2012-03-31 10:24 UTC (permalink / raw)
To: Mike Sinkovsky; +Cc: netdev, linux-kernel
In-Reply-To: <4F76D3E5.6050605@permonline.ru>
On Sat, 2012-03-31 at 15:52 +0600, Mike Sinkovsky wrote:
> Maybe, but I cannot test this, sorry - when I set breakpoint on this
> branch - it never triggered, on all my tests on all boards.
> Appears that my processor is too slow and cannot feed packets fast enough.
Really ?
A pktgen script should certainly hit your NIC limit, unless this is a
100Gbit link ...
^ permalink raw reply
* [RFC] net: bpf_jit: Two pass JIT and other changes
From: Indan Zupancic @ 2012-03-31 12:12 UTC (permalink / raw)
To: Eric Dumazet, netdev, linux-kernel
Hello,
After fiddling with x86 JIT code I got it to compile the BPF
filters always in two passes instead of looping until the result
is stable. The current code loops at least three times, more
if jump offsets change from far to near because other jumps got
shorter. In the process I simplifying the code a bit, but I
tried to avoid controversial code changes. After the changes
bpf_jit_comp.o is about 1kb smaller.
As I moved the inner loop to a helper function, pretty much all
lines in bpf_jit_comp.c changed and a diff isn't very helpful.
Later changes I can redo for the original version and I'll send
a diff for those separately. But before I go to the trouble of
trying to get a readable patch series for the two pass version,
I'll attach the end result below so people can see if it's worth
the trouble or not.
As I'm currently travelling I've no access to a 64-bit machine,
so everything is done on 32-bit and as yet untested. JITing
should be quite a bit faster with this version, while the
generated code should have pretty much the same speed, as
nothing major changed.
Summary of the changes:
1) Sadly, gcc isn't always smart enough to inline emit_code().
So turn it into a macro to force gcc to inline it. This saves
about 500 bytes. Tested with gcc 4.6.0. An alternative to the
macro would be to create inline emit_code1(), emit_code2() etc.
2) Split EMIT2() in the JMP macro's into a constant bit and a
variable bit. This avoids the need to add them together and
saves about 15 bytes. Adding __builtin_constant_p checks to
emit macros saves more (50 bytes), but is ugly.
3) Only generate a CLEAR_X() when necessary. This is done by having
an extra flag saying if X is used before it is set.
4) Simplify the code by adding a RET 0 as epilogue. This way the
pc_ret0 and cleanup_addr logic can be merged. This was inspired
by tcpdump always generating a RET 0 as last instruction. To make
two pass compilation possible, the pc_ret0 had to go, as it's a
backward jump.
5) Compile in two passes by doing the first pass in reverse.
As all jumps are forward jumps, this way all offsets are known
when needed, making it possible to do just two passes: One to
check if we can JIT the filter and to calculate the code size.
The second pass generates the real code directly into the
allocated memory.
Are these changes worth pursuing? In the end it should speed up
JITing, saves 1kb, doesn't generate worse filter code and I think
it streamlines the code a bit.
Greetings,
Indan
---
Two-pass version of arch/x86/net/bpf_jit_comp.c:
---
/* bpf_jit_comp.c : BPF JIT compiler
*
* Copyright (C) 2011 Eric Dumazet (eric.dumazet@gmail.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2
* of the License.
*/
#include <linux/moduleloader.h>
#include <asm/cacheflush.h>
#include <linux/netdevice.h>
#include <linux/filter.h>
/*
* Conventions :
* EAX : BPF A accumulator
* EBX : BPF X accumulator
* RDI : pointer to skb (first argument given to JIT function)
* RBP : frame pointer (even if CONFIG_FRAME_POINTER=n)
* ECX,EDX,ESI : scratch registers
* r9d : skb->len - skb->data_len (headlen)
* r8 : skb->data
* -8(RBP) : saved RBX value
* -16(RBP)..-80(RBP) : BPF_MEMWORDS values
*/
int bpf_jit_enable __read_mostly;
/*
* assembly code in arch/x86/net/bpf_jit.S
*/
extern u8 sk_load_word[], sk_load_half[], sk_load_byte[], sk_load_byte_msh[];
extern u8 sk_load_word_ind[], sk_load_half_ind[], sk_load_byte_ind[];
#define EMIT(bytes, len) \
({ \
if ((len) == 1) \
*prog = (u8)(bytes); \
else if ((len) == 2) \
*(u16 *)prog = (u16)(bytes); \
else { \
*(u32 *)prog = (bytes); \
} \
prog += (len); \
})
#define EMIT1(b1) EMIT(b1, 1)
#define EMIT2(b1, b2) EMIT((b1) | ((b2) << 8), 2)
#define EMIT3(b1, b2, b3) EMIT((b1) + ((b2) << 8) + ((b3) << 16), 3)
#define EMIT4(b1, b2, b3, b4) EMIT((b1) + ((b2) << 8) + ((b3) << 16) + ((b4) << 24), 4)
#define EMIT1_off32(b1, off) do { EMIT1(b1); EMIT(off, 4);} while (0)
#define CLEAR_A() EMIT2(0x31, 0xc0) /* xor %eax,%eax */
#define CLEAR_X() EMIT2(0x31, 0xdb) /* xor %ebx,%ebx */
static inline bool is_imm8(int value)
{
return value <= 127 && value >= -128;
}
#define EMIT_JMP(offset) \
do { \
if (is_imm8(offset)) { \
EMIT1(0xeb); /* jmp .+off8 */ \
EMIT1(offset); \
} else { \
EMIT1_off32(0xe9, offset); /* jmp .+off32 */ \
} \
} while (0)
/* list of x86 cond jumps opcodes (. + s8)
* Add 0x10 (and an extra 0x0f) to generate far jumps (. + s32)
*/
#define X86_JB 0x72
#define X86_JAE 0x73
#define X86_JE 0x74
#define X86_JNE 0x75
#define X86_JBE 0x76
#define X86_JA 0x77
#define EMIT_COND_JMP(op, offset) \
do { \
if (is_imm8(offset)) { \
EMIT1(op); /* jxx .+off8 */ \
EMIT1(offset); \
} else { \
EMIT2(0x0f, op + 0x10); \
EMIT(offset, 4); /* jxx .+off32 */ \
} \
} while (0)
#define COND_SEL(CODE, TOP, FOP) \
case CODE: \
t_op = TOP; \
f_op = FOP; \
goto cond_branch
#define SKB_OFF(field) offsetof(struct sk_buff, field)
#define SEEN_DATAREF 1 /* might call external helpers */
#define SEEN_MEM 2 /* use mem[] for temporary storage */
#define USE_XREG 4 /* ebx is used */
#define CLEAR_XREG 8 /* ebx needs to be zeroed */
#define SEEN_XREG (USE_XREG|CLEAR_XREG) /* ebx is used as input */
static inline void bpf_flush_icache(void *start, void *end)
{
mm_segment_t old_fs = get_fs();
set_fs(KERNEL_DS);
smp_wmb();
flush_icache_range((unsigned long)start, (unsigned long)end);
set_fs(old_fs);
}
static u8* bpf_jit_ins(u8 *prog, const struct sock_filter *f, u16 *addrs, u8 *flags)
{
int t_offset, f_offset;
u8 t_op, f_op;
u8 *func;
u8 seen = *flags;
unsigned int K = f->k;
switch (f->code) {
case BPF_S_ALU_ADD_X: /* A += X; */
seen |= SEEN_XREG;
EMIT2(0x01, 0xd8); /* add %ebx,%eax */
break;
case BPF_S_ALU_ADD_K: /* A += K; */
if (!K)
break;
if (is_imm8(K))
EMIT3(0x83, 0xc0, K); /* add imm8,%eax */
else
EMIT1_off32(0x05, K); /* add imm32,%eax */
break;
case BPF_S_ALU_SUB_X: /* A -= X; */
seen |= SEEN_XREG;
EMIT2(0x29, 0xd8); /* sub %ebx,%eax */
break;
case BPF_S_ALU_SUB_K: /* A -= K */
if (!K)
break;
if (is_imm8(K))
EMIT3(0x83, 0xe8, K); /* sub imm8,%eax */
else
EMIT1_off32(0x2d, K); /* sub imm32,%eax */
break;
case BPF_S_ALU_MUL_X: /* A *= X; */
seen |= SEEN_XREG;
EMIT3(0x0f, 0xaf, 0xc3); /* imul %ebx,%eax */
break;
case BPF_S_ALU_MUL_K: /* A *= K */
if (is_imm8(K))
EMIT3(0x6b, 0xc0, K); /* imul imm8,%eax,%eax */
else {
EMIT2(0x69, 0xc0); /* imul imm32,%eax */
EMIT(K, 4);
}
break;
case BPF_S_ALU_DIV_X: /* A /= X; */
seen |= SEEN_XREG;
EMIT2(0x85, 0xdb); /* test %ebx,%ebx */
/*
* Add 4 to jump over "xor %edx,%edx; div %ebx".
*/
EMIT_COND_JMP(X86_JE, 4 + addrs[0]);
EMIT4(0x31, 0xd2, 0xf7, 0xf3); /* xor %edx,%edx; div %ebx */
break;
case BPF_S_ALU_DIV_K: /* A = reciprocal_divide(A, K); */
EMIT3(0x48, 0x69, 0xc0); /* imul imm32,%rax,%rax */
EMIT(K, 4);
EMIT4(0x48, 0xc1, 0xe8, 0x20); /* shr $0x20,%rax */
break;
case BPF_S_ALU_AND_X:
seen |= SEEN_XREG;
EMIT2(0x21, 0xd8); /* and %ebx,%eax */
break;
case BPF_S_ALU_AND_K:
if (K >= 0xFFFFFF00) {
EMIT2(0x24, K & 0xFF); /* and imm8,%al */
} else if (K >= 0xFFFF0000) {
EMIT2(0x66, 0x25); /* and imm16,%ax */
EMIT(K, 2);
} else {
EMIT1_off32(0x25, K); /* and imm32,%eax */
}
break;
case BPF_S_ALU_OR_X:
seen |= SEEN_XREG;
EMIT2(0x09, 0xd8); /* or %ebx,%eax */
break;
case BPF_S_ALU_OR_K:
if (is_imm8(K))
EMIT3(0x83, 0xc8, K); /* or imm8,%eax */
else
EMIT1_off32(0x0d, K); /* or imm32,%eax */
break;
case BPF_S_ALU_LSH_X: /* A <<= X; */
seen |= SEEN_XREG;
EMIT4(0x89, 0xd9, 0xd3, 0xe0); /* mov %ebx,%ecx; shl %cl,%eax */
break;
case BPF_S_ALU_LSH_K:
if (K == 0)
break;
else if (K == 1)
EMIT2(0xd1, 0xe0); /* shl %eax */
else
EMIT3(0xc1, 0xe0, K);
break;
case BPF_S_ALU_RSH_X: /* A >>= X; */
seen |= SEEN_XREG;
EMIT4(0x89, 0xd9, 0xd3, 0xe8); /* mov %ebx,%ecx; shr %cl,%eax */
break;
case BPF_S_ALU_RSH_K: /* A >>= K; */
if (K == 0)
break;
else if (K == 1)
EMIT2(0xd1, 0xe8); /* shr %eax */
else
EMIT3(0xc1, 0xe8, K);
break;
case BPF_S_ALU_NEG:
EMIT2(0xf7, 0xd8); /* neg %eax */
break;
case BPF_S_RET_K:
t_offset = addrs[0];
if (!K && t_offset) {
EMIT_JMP(t_offset);
} else {
EMIT1_off32(0xb8, K); /* mov $imm32,%eax */
EMIT_JMP(t_offset + 2);
}
break;
case BPF_S_RET_A:
EMIT_JMP(addrs[0] + 2);
break;
case BPF_S_MISC_TAX: /* X = A */
seen |= USE_XREG;
seen &= ~CLEAR_XREG;
EMIT2(0x89, 0xc3); /* mov %eax,%ebx */
break;
case BPF_S_MISC_TXA: /* A = X */
seen |= SEEN_XREG;
EMIT2(0x89, 0xd8); /* mov %ebx,%eax */
break;
case BPF_S_LD_IMM: /* A = K */
if (!K)
CLEAR_A();
else
EMIT1_off32(0xb8, K); /* mov $imm32,%eax */
break;
case BPF_S_LDX_IMM: /* X = K */
seen |= USE_XREG;
seen &= ~CLEAR_XREG;
if (!K)
CLEAR_X();
else
EMIT1_off32(0xbb, K); /* mov $imm32,%ebx */
break;
case BPF_S_LD_MEM: /* A = mem[K] : mov off8(%rbp),%eax */
seen |= SEEN_MEM;
EMIT3(0x8b, 0x45, 0xf0 - K*4);
break;
case BPF_S_LDX_MEM: /* X = mem[K] : mov off8(%rbp),%ebx */
seen |= USE_XREG | SEEN_MEM;
seen &= ~CLEAR_XREG;
EMIT3(0x8b, 0x5d, 0xf0 - K*4);
break;
case BPF_S_ST: /* mem[K] = A : mov %eax,off8(%rbp) */
seen |= SEEN_MEM;
EMIT3(0x89, 0x45, 0xf0 - K*4);
break;
case BPF_S_STX: /* mem[K] = X : mov %ebx,off8(%rbp) */
seen |= SEEN_XREG | SEEN_MEM;
EMIT3(0x89, 0x5d, 0xf0 - K*4);
break;
case BPF_S_LD_W_LEN: /* A = skb->len; */
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4);
if (is_imm8(SKB_OFF(len)))
/* mov off8(%rdi),%eax */
EMIT3(0x8b, 0x47, SKB_OFF(len));
else {
EMIT2(0x8b, 0x87);
EMIT(SKB_OFF(len), 4);
}
break;
case BPF_S_LDX_W_LEN: /* X = skb->len; */
seen |= USE_XREG;
seen &= ~CLEAR_XREG;
if (is_imm8(SKB_OFF(len)))
/* mov off8(%rdi),%ebx */
EMIT3(0x8b, 0x5f, SKB_OFF(len));
else {
EMIT2(0x8b, 0x9f);
EMIT(SKB_OFF(len), 4);
}
break;
case BPF_S_ANC_PROTOCOL: /* A = ntohs(skb->protocol); */
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, protocol) != 2);
if (is_imm8(SKB_OFF(protocol))) {
/* movzwl off8(%rdi),%eax */
EMIT4(0x0f, 0xb7, 0x47, SKB_OFF(protocol));
} else {
EMIT3(0x0f, 0xb7, 0x87); /* movzwl off32(%rdi),%eax */
EMIT(SKB_OFF(protocol), 4);
}
EMIT2(0x86, 0xc4); /* ntohs() : xchg %al,%ah */
break;
case BPF_S_ANC_IFINDEX:
if (is_imm8(SKB_OFF(dev))) {
/* movq off8(%rdi),%rax */
EMIT4(0x48, 0x8b, 0x47, SKB_OFF(dev));
} else {
EMIT3(0x48, 0x8b, 0x87); /* movq off32(%rdi),%rax */
EMIT(SKB_OFF(dev), 4);
}
EMIT3(0x48, 0x85, 0xc0); /* test %rax,%rax */
EMIT_COND_JMP(X86_JE, 6 + addrs[0]);
EMIT2(0x8b, 0x80); /* mov off32(%rax),%eax */
EMIT(offsetof(struct net_device, ifindex), 4);
BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, ifindex) != 4);
break;
case BPF_S_ANC_MARK:
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
if (is_imm8(SKB_OFF(mark))) {
/* mov off8(%rdi),%eax */
EMIT3(0x8b, 0x47, SKB_OFF(mark));
} else {
EMIT2(0x8b, 0x87);
EMIT(SKB_OFF(mark), 4);
}
break;
case BPF_S_ANC_RXHASH:
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
if (is_imm8(SKB_OFF(rxhash))) {
/* mov off8(%rdi),%eax */
EMIT3(0x8b, 0x47, SKB_OFF(rxhash));
} else {
EMIT2(0x8b, 0x87);
EMIT(SKB_OFF(rxhash), 4);
}
break;
case BPF_S_ANC_QUEUE:
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, queue_mapping) != 2);
if (is_imm8(SKB_OFF(queue_mapping))) {
/* movzwl off8(%rdi),%eax */
EMIT4(0x0f, 0xb7, 0x47, SKB_OFF(queue_mapping));
} else {
EMIT3(0x0f, 0xb7, 0x87); /* movzwl off32(%rdi),%eax */
EMIT(SKB_OFF(queue_mapping), 4);
}
break;
case BPF_S_ANC_CPU:
#ifdef CONFIG_SMP
EMIT4(0x65, 0x8b, 0x04, 0x25); /* mov %gs:off32,%eax */
EMIT((u32)(unsigned long)&cpu_number, 4); /* A = smp_processor_id(); */
#else
CLEAR_A();
#endif
break;
case BPF_S_LD_W_ABS:
func = sk_load_word;
common_load: seen |= SEEN_DATAREF;
if ((int)K < 0) {
/* Abort the JIT because __load_pointer() is needed. */
return NULL;
}
t_offset = func - (prog + 10);
EMIT1_off32(0xbe, K); /* mov imm32,%esi */
EMIT1_off32(0xe8, t_offset); /* call */
break;
case BPF_S_LD_H_ABS:
func = sk_load_half;
goto common_load;
case BPF_S_LD_B_ABS:
func = sk_load_byte;
goto common_load;
case BPF_S_LDX_B_MSH:
if ((int)K < 0) {
/* Abort the JIT because __load_pointer() is needed. */
return NULL;
}
seen |= SEEN_DATAREF | USE_XREG;
seen &= ~CLEAR_XREG;
t_offset = sk_load_byte_msh - (prog + 10);
EMIT1_off32(0xbe, K); /* mov imm32,%esi */
EMIT1_off32(0xe8, t_offset); /* call sk_load_byte_msh */
break;
case BPF_S_LD_W_IND:
func = sk_load_word_ind;
common_load_ind:
seen |= SEEN_DATAREF | SEEN_XREG;
t_offset = func - (prog + 10);
EMIT1_off32(0xbe, K); /* mov imm32,%esi */
EMIT1_off32(0xe8, t_offset); /* call sk_load_xxx_ind */
break;
case BPF_S_LD_H_IND:
func = sk_load_half_ind;
goto common_load_ind;
case BPF_S_LD_B_IND:
func = sk_load_byte_ind;
goto common_load_ind;
case BPF_S_JMP_JA:
t_offset = addrs[0] - addrs[K];
if (t_offset)
EMIT_JMP(t_offset);
break;
COND_SEL(BPF_S_JMP_JGT_K, X86_JA, X86_JBE);
COND_SEL(BPF_S_JMP_JGE_K, X86_JAE, X86_JB);
COND_SEL(BPF_S_JMP_JEQ_K, X86_JE, X86_JNE);
COND_SEL(BPF_S_JMP_JSET_K,X86_JNE, X86_JE);
COND_SEL(BPF_S_JMP_JGT_X, X86_JA, X86_JBE);
COND_SEL(BPF_S_JMP_JGE_X, X86_JAE, X86_JB);
COND_SEL(BPF_S_JMP_JEQ_X, X86_JE, X86_JNE);
COND_SEL(BPF_S_JMP_JSET_X,X86_JNE, X86_JE);
cond_branch: f_offset = addrs[0] - addrs[f->jf];
t_offset = addrs[0] - addrs[f->jt];
/* same targets, can avoid doing the test :) */
if (f->jt == f->jf) {
EMIT_JMP(t_offset);
break;
}
switch (f->code) {
case BPF_S_JMP_JGT_X:
case BPF_S_JMP_JGE_X:
case BPF_S_JMP_JEQ_X:
seen |= SEEN_XREG;
EMIT2(0x39, 0xd8); /* cmp %ebx,%eax */
break;
case BPF_S_JMP_JSET_X:
seen |= SEEN_XREG;
EMIT2(0x85, 0xd8); /* test %ebx,%eax */
break;
case BPF_S_JMP_JEQ_K:
if (K == 0) {
EMIT2(0x85, 0xc0); /* test %eax,%eax */
break;
}
case BPF_S_JMP_JGT_K:
case BPF_S_JMP_JGE_K:
if (K <= 127)
EMIT3(0x83, 0xf8, K); /* cmp imm8,%eax */
else
EMIT1_off32(0x3d, K); /* cmp imm32,%eax */
break;
case BPF_S_JMP_JSET_K:
if (K <= 0xFF)
EMIT2(0xa8, K); /* test imm8,%al */
else if (!(K & 0xFFFF00FF))
EMIT3(0xf6, 0xc4, K >> 8); /* test imm8,%ah */
else if (K <= 0xFFFF) {
EMIT2(0x66, 0xa9); /* test imm16,%ax */
EMIT(K, 2);
} else {
EMIT1_off32(0xa9, K); /* test imm32,%eax */
}
break;
}
if (t_offset) {
if (f_offset)
t_offset += is_imm8(f_offset) ? 2 : 5;
EMIT_COND_JMP(t_op, t_offset);
if (f_offset)
EMIT_JMP(f_offset);
break;
}
if (f_offset)
EMIT_COND_JMP(f_op, f_offset);
break;
default:
/* hmm, too complex filter, give up with jit compiler */
return NULL;
}
*flags |= seen;
return prog;
}
void bpf_jit_compile(struct sk_filter *fp)
{
u8 temp[64];
u8 *prog;
unsigned int proglen = 0;
u8 seen = 0;
u8 *image;
u16 *addrs;
const struct sock_filter *filter = fp->insns;
int i, flen = fp->len;
if (!bpf_jit_enable)
return;
addrs = kmalloc(flen * sizeof(*addrs), GFP_KERNEL);
if (addrs == NULL)
return;
/*
* First pass: Check if we can JIT this and calculate the size.
*
* As there are only forward jumps, go backwards through the
* instructions so all jump offsets are known when needed.
*/
for (i = flen - 1; i >= 0; i--) {
/*
* Store the offset from the end of this instruction to
* the beginning of the epilogue (RET 0) in addrs[i].
*
* To return zero, jump addrs[i] bytes.
* To return A, jump addrs[i] + 2 bytes, to skip the CLEAR_A.
* To skip N instructions, jump addrs[i] - addrs[i + N] bytes.
*/
addrs[i] = proglen;
prog = bpf_jit_ins(temp, &filter[i], &addrs[i], &seen);
if (!prog)
goto out;
proglen += prog - temp;
}
/* Allocate extra memory for the prologue and epilogue */
proglen += 64;
/* Don't use too much memory */
if (proglen > 32 * 1024)
goto out;
image = module_alloc(max_t(unsigned int, proglen, sizeof(struct work_struct)));
if (!image)
goto out;
/*
* Second pass, now for real.
*/
prog = image;
/* No prologue for trivial filters (RET something) */
if (seen) {
EMIT4(0x55, 0x48, 0x89, 0xe5); /* push %rbp; mov %rsp,%rbp */
EMIT4(0x48, 0x83, 0xec, 96); /* subq $96,%rsp */
/* note : must save %rbx in case bpf_error is hit */
if (seen & (USE_XREG | SEEN_DATAREF))
EMIT4(0x48, 0x89, 0x5d, 0xf8); /* mov %rbx, -8(%rbp) */
if (seen & CLEAR_XREG)
CLEAR_X(); /* make sure we don't leak kernel memory */
/*
* If this filter needs to access skb data,
* loads r9 and r8 with :
* r9 = skb->len - skb->data_len
* r8 = skb->data
*/
if (seen & SEEN_DATAREF) {
if (is_imm8(SKB_OFF(len)))
/* mov off8(%rdi),%r9d */
EMIT4(0x44, 0x8b, 0x4f, SKB_OFF(len));
else {
/* mov off32(%rdi),%r9d */
EMIT3(0x44, 0x8b, 0x8f);
EMIT(SKB_OFF(len), 4);
}
if (is_imm8(SKB_OFF(data_len)))
/* sub off8(%rdi),%r9d */
EMIT4(0x44, 0x2b, 0x4f, SKB_OFF(data_len));
else {
EMIT3(0x44, 0x2b, 0x8f);
EMIT(SKB_OFF(data_len), 4);
}
/* mov off32(%rdi),%r8 */
EMIT3(0x4c, 0x8b, 0x87);
EMIT(SKB_OFF(data), 4);
}
}
switch (filter[0].code) {
case BPF_S_RET_K:
case BPF_S_LD_W_ABS:
case BPF_S_LD_H_ABS:
case BPF_S_LD_B_ABS:
case BPF_S_LD_W_LEN:
case BPF_S_LD_W_IND:
case BPF_S_LD_H_IND:
case BPF_S_LD_B_IND:
case BPF_S_LD_IMM:
case BPF_S_ANC_PROTOCOL:
case BPF_S_ANC_IFINDEX:
case BPF_S_ANC_MARK:
case BPF_S_ANC_QUEUE:
case BPF_S_ANC_RXHASH:
case BPF_S_ANC_CPU:
/* first instruction sets A register (or is RET 'constant') */
break;
default:
/* make sure we don't leak kernel information to user */
CLEAR_A(); /* A = 0 */
}
for (i = 0; i < flen; i++) {
prog = bpf_jit_ins(prog, &filter[i], &addrs[i], &seen);
}
/*
* Epilogue is a RET 0.
* RET A jumps to addr[i] + 2, to skip the A = 0.
*/
CLEAR_A();
if (seen & USE_XREG)
EMIT4(0x48, 0x8b, 0x5d, 0xf8); /* mov -8(%rbp),%rbx */
if (seen)
EMIT1(0xc9); /* leaveq */
EMIT1(0xc3); /* ret */
proglen = prog - image;
if (bpf_jit_enable > 1) {
pr_err("flen=%d proglen=%u image=%p\n", flen, proglen, image);
print_hex_dump(KERN_ERR, "JIT code: ", DUMP_PREFIX_ADDRESS,
16, 1, image, proglen, false);
}
bpf_flush_icache(image, image + proglen);
fp->bpf_func = (void *)image;
out:
kfree(addrs);
return;
}
static void jit_free_defer(struct work_struct *arg)
{
module_free(NULL, arg);
}
/* run from softirq, we must use a work_struct to call
* module_free() from process context
*/
void bpf_jit_free(struct sk_filter *fp)
{
if (fp->bpf_func != sk_run_filter) {
struct work_struct *work = (struct work_struct *)fp->bpf_func;
INIT_WORK(work, jit_free_defer);
schedule_work(work);
}
}
^ permalink raw reply
* Re: sendmmsg: put_user vs __put_user
From: Ulrich Drepper @ 2012-03-31 12:30 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-kernel
In-Reply-To: <20120330.205120.2221145622131588797.davem@davemloft.net>
On Fri, Mar 30, 2012 at 20:51, David Miller <davem@davemloft.net> wrote:
> Compat processes are not able to generate virtual addresses anywhere
> near the range where the kernel resides, so the address range
> verification done by put_user() is completely superfluous and
> therefore not necessary. The normal exception handling done by the
> access is completely sufficient.
I was more thinking about the effects of might_fault() then additional tests.
^ permalink raw reply
* Re: [PATCH] net: reference the ipv4 sysctl table header
From: Djalal Harouni @ 2012-03-31 14:25 UTC (permalink / raw)
To: Eric W. Biederman; +Cc: David S. Miller, Al Viro, netdev, Steven Rostedt
In-Reply-To: <m1sjgtmozu.fsf@fess.ebiederm.org>
On Tue, Mar 27, 2012 at 07:35:33PM -0700, Eric W. Biederman wrote:
> Djalal Harouni <tixxdz@opendz.org> writes:
>
> > On Mon, Mar 26, 2012 at 03:50:30PM -0700, Eric W. Biederman wrote:
[...]
> > Anyway they seem false positive ones, since keeping a reference to
> > sysctl_header as in my previous (ugly) patch will quiet the last two
> > ones.
>
> Ok thanks. If that is what it is. Then clean way to quite this will
> ultimately be converting these table to be compatible with my brand
> new register_sysctl() and using that to register them.
>
> In fact I am pretty certain we can just do:
> register_sysctl("net/ipv4/route", ipv4_route_table);
> register_sysctl("net/ipv4/neigh", empty);
Thanks, I've tested this and it works, however it seems that there are still
memleaks, please see below.
> instead of:
> register_sysctl_paths(ipv4_path, ipv4_skeleton);
>
> And kill ipv4_skeleton and ipv4_path as they are now unused.
Right, and use the path directly from the .data section.
> There was a tremendous cleanup and speed up that came with not allowing
> sysctl tables to support .child entries in the core, and the older
> registration routines break apart the tables and return a compatilibty
> sysctl_table_header if we do that, and I believe we are just
> leaking that compatibility sysctl_table_header.
Thanks for the explanation, however I don't understand all of this since
I'm not familiar with the old/new code, but I want to report some notes
(I'm not sure if they are correct).
1) memleaks:
After testing your proposed change:
register_sysctl("net/ipv4/route", ipv4_route_table);
for ipv4_route_table it is ok, no memleak is reported since the returned
ctl_table_header is referenced by the ctl_node nodes. This will silence
the memleak report.
for:
register_sysctl("net/ipv4/neigh", empty);
Here we'll still have the memleak, I don't know if this is the "leaking
that compatibility sysctl_table_header" you are referring to. But here the
returned ctl_table_header will not be referenced by the ctl_node nodes
since we have an empty ctl_table. see init_header()
So is there real memleaks that got hidden by the false positive ones ?
or perhaps these are real memleaks that were never spotted ?
2) From the __register_sysctl_table(), if the ctl_table is empty then
nr_entries == 0.
later we have:
header = kzalloc(sizeof(struct ctl_table_header) +
sizeof(struct ctl_node)*nr_entries, GFP_KERNEL);
...
node = (struct ctl_node *)(header + 1);
init_header(header, root, set, node, table);
...
node points to somewhere, but its use in this situations seems restricted.
3) Why we always alloc ctl_table_header in __register_sysctl_table() at
the beginning ? if I'm right, the current design is:
"each directory should have its ctl_table_header", so if some ctl_tables
share the same directory then they should also share the same
ctl_table_header ?
In this case the code can be improved, check if it's a new dir, then alloc
a new ctl_table_header, otherwise just return the old one and increment
the counter and insert ctl_table entries there.
I say this since currently doing:
register_sysctl("net/ipv4/neigh", empty);
register_sysctl("net/ipv4/neigh", empty);
register_sysctl("net/ipv4/neigh", empty);
Will allocate three ctl_table_header however at the second call the code
successfully detects that this is _not_ a new dir, but it will return the
ctl_table_header that was allocated at the beginning of
__register_sysctl_table().
Is this also related to the "leaking that compatibility sysctl_table_header" ?
4) Is the order of sysctl locking inside insert_links() correct ?
If I'm missing something, please just point-me to an http-link and I'll try
to take a closer look when time permits, otherwise someone who knows this
should just take a look at it.
Sorry for the delay (just got some free time).
Thanks.
--
tixxdz
http://opendz.org
^ permalink raw reply
* Re: [PATCH] net: reference the ipv4 sysctl table header
From: Djalal Harouni @ 2012-03-31 14:29 UTC (permalink / raw)
To: David Miller; +Cc: rostedt, ebiederm, viro, netdev
In-Reply-To: <20120328.165132.1309449708287640005.davem@davemloft.net>
On Wed, Mar 28, 2012 at 04:51:32PM -0400, David Miller wrote:
> From: Steven Rostedt <rostedt@goodmis.org>
> Date: Wed, 28 Mar 2012 12:32:20 -0400
>
> > I just started using kmemleak and notice that it reports false positives
> > for several __init functions that call register_sysctl_paths(). The fix
> > you want is:
> >
> > {
> > sturct ctl_table_header *head;
> >
> > head = register_sysctl_paths(ipv4_path, ipv4_skeleton);
> > BUG_ON(!head);
> > kmemleak_ignore(head);
> >
> >
> > No need to waste a pointer just to keep the reference around for
> > kmemleak.
Thanks Steven, yes it's a nice solution for false positive ones.
> That looks a lot saner than the other suggestions, indeed.
Yes, however now I'm not sure that these are real false positive ones,
please check my other email, and someone who knows the code should take a
closer look.
Thank.
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
tixxdz
http://opendz.org
^ permalink raw reply
* Re: [PATCH] net: bpf_jit: fix BPF_S_ALU_AND_K compilation
From: Greg KH @ 2012-03-31 15:13 UTC (permalink / raw)
To: Indan Zupancic; +Cc: Eric Dumazet, netdev, stable, linux-kernel
In-Reply-To: <40f4b91c5200771f223966f368095c63.squirrel@webmail.greenhost.nl>
On Sat, Mar 31, 2012 at 08:52:09PM +1100, Indan Zupancic wrote:
> Hello,
>
> Finally, after much searching I found one little bug.
>
> [PATCH] net: bpf_jit: fix BPF_S_ALU_AND_K compilation
>
> Small typo resulted in bad code generation for certain
> values of K for the BPF_S_ALU_AND_K instruction.
>
> Signed-off-by: Indan Zupancic <indan@nul.nu>
> ---
>
<formletter>
This is not the correct way to submit patches for inclusion in the
stable kernel tree. Please read Documentation/stable_kernel_rules.txt
for how to do this properly.
</formletter>
^ permalink raw reply
* [PATCH iputils] ping,ping6: Fallback to numeric addresses while exiting
From: Sergey Fionov @ 2012-03-31 15:40 UTC (permalink / raw)
To: netdev
When user presses Ctrl-C ping waits for pr_addr() to be finished and
then exits. With poor connection it may result in stuck at
gethostbyaddr().
This patch changes handling of exit signals. After setting "exiting"
flag we longjmp() from gethostbyaddr() and print numeric addresses.
---
ping.c | 7 ++++++-
ping6.c | 6 +++++-
ping_common.c | 4 ++++
ping_common.h | 4 ++++
4 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/ping.c b/ping.c
index eacb29d..ddce1fe 100644
--- a/ping.c
+++ b/ping.c
@@ -1160,12 +1160,17 @@ pr_addr(__u32 addr)
struct hostent *hp;
static char buf[4096];
- if ((options & F_NUMERIC) ||
+ in_pr_addr = !setjmp(pr_addr_jmp);
+
+ if (exiting || (options & F_NUMERIC) ||
!(hp = gethostbyaddr((char *)&addr, 4, AF_INET)))
sprintf(buf, "%s", inet_ntoa(*(struct in_addr *)&addr));
else
snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name,
inet_ntoa(*(struct in_addr *)&addr));
+
+ in_pr_addr = 0;
+
return(buf);
}
diff --git a/ping6.c b/ping6.c
index c5ff881..f5beaf2 100644
--- a/ping6.c
+++ b/ping6.c
@@ -1538,9 +1538,13 @@ char * pr_addr(struct in6_addr *addr)
{
struct hostent *hp = NULL;
- if (!(options&F_NUMERIC))
+ in_pr_addr = !setjmp(pr_addr_jmp);
+
+ if (!(exiting || options&F_NUMERIC))
hp = gethostbyaddr((__u8*)addr, sizeof(struct in6_addr), AF_INET6);
+ in_pr_addr = 0;
+
return hp ? hp->h_name : pr_addr_n(addr);
}
diff --git a/ping_common.c b/ping_common.c
index 82320b1..b45b5c8 100644
--- a/ping_common.c
+++ b/ping_common.c
@@ -30,6 +30,8 @@ struct timeval start_time, cur_time;
volatile int exiting;
volatile int status_snapshot;
int confirm = 0;
+int in_pr_addr = 0; /* pr_addr() is executing */
+jmp_buf pr_addr_jmp;
/* Stupid workarounds for bugs/missing functionality in older linuces.
* confirm_flag fixes refusing service of kernels without MSG_CONFIRM.
@@ -248,6 +250,8 @@ void common_options(int ch)
static void sigexit(int signo)
{
exiting = 1;
+ if (in_pr_addr)
+ longjmp(pr_addr_jmp, 0);
}
static void sigstatus(int signo)
diff --git a/ping_common.h b/ping_common.h
index 730cf9b..2262f91 100644
--- a/ping_common.h
+++ b/ping_common.h
@@ -16,6 +16,7 @@
#include <errno.h>
#include <string.h>
#include <netdb.h>
+#include <setjmp.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -206,3 +207,6 @@ extern int gather_statistics(__u8 *ptr, int icmplen,
int csfailed, struct timeval *tv, char *from,
void (*pr_reply)(__u8 *ptr, int cc));
extern void print_timestamp(void);
+
+extern int in_pr_addr;
+extern jmp_buf pr_addr_jmp;
--
1.7.8.5
^ permalink raw reply related
* ipv6: tunnel: hang when destroying ipv6 tunnel
From: Sasha Levin @ 2012-03-31 17:51 UTC (permalink / raw)
To: davem, kuznet, jmorris, yoshfuji, Patrick McHardy
Cc: netdev, linux-kernel@vger.kernel.org List, Dave Jones
Hi all,
It appears that a hang may occur when destroying an ipv6 tunnel, which
I've reproduced several times in a KVM vm.
The pattern in the stack dump below is consistent with unregistering a
kobject when holding multiple locks. Unregistering a kobject usually
leads to an exit back to userspace with call_usermodehelper_exec().
The userspace code may access sysfs files which in turn will require
locking within the kernel, leading to a deadlock since those locks are
already held by kernel.
[ 1561.564172] INFO: task kworker/u:2:3140 blocked for more than 120 seconds.
[ 1561.566945] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs"
disables this message.
[ 1561.570062] kworker/u:2 D ffff88006ee63000 4504 3140 2 0x00000000
[ 1561.572968] ffff88006ed9f7e0 0000000000000082 ffff88006ed9f790
ffffffff8107d346
[ 1561.575680] ffff88006ed9ffd8 00000000001d4580 ffff88006ed9e010
00000000001d4580
[ 1561.578601] 00000000001d4580 00000000001d4580 ffff88006ed9ffd8
00000000001d4580
[ 1561.581697] Call Trace:
[ 1561.582650] [<ffffffff8107d346>] ? kvm_clock_read+0x46/0x80
[ 1561.584543] [<ffffffff827063d4>] schedule+0x24/0x70
[ 1561.586231] [<ffffffff82704025>] schedule_timeout+0x245/0x2c0
[ 1561.588508] [<ffffffff81117c9a>] ? mark_held_locks+0x7a/0x120
[ 1561.590858] [<ffffffff81119bbd>] ? __lock_release+0x8d/0x1d0
[ 1561.593162] [<ffffffff82707e6b>] ? _raw_spin_unlock_irq+0x2b/0x70
[ 1561.595394] [<ffffffff810e36d1>] ? get_parent_ip+0x11/0x50
[ 1561.597403] [<ffffffff82705919>] wait_for_common+0x119/0x190
[ 1561.599707] [<ffffffff810ed1b0>] ? try_to_wake_up+0x2c0/0x2c0
[ 1561.601758] [<ffffffff82705a38>] wait_for_completion+0x18/0x20
[ 1561.603843] [<ffffffff810cdcd8>] call_usermodehelper_exec+0x228/0x240
[ 1561.606059] [<ffffffff82705844>] ? wait_for_common+0x44/0x190
[ 1561.608352] [<ffffffff81878445>] kobject_uevent_env+0x615/0x650
[ 1561.610908] [<ffffffff810e36d1>] ? get_parent_ip+0x11/0x50
[ 1561.613146] [<ffffffff8187848b>] kobject_uevent+0xb/0x10
[ 1561.615312] [<ffffffff81876f5a>] kobject_cleanup+0xca/0x1b0
[ 1561.617509] [<ffffffff8187704d>] kobject_release+0xd/0x10
[ 1561.619334] [<ffffffff81876d9c>] kobject_put+0x2c/0x60
[ 1561.621117] [<ffffffff8226ea80>] net_rx_queue_update_kobjects+0xa0/0xf0
[ 1561.623421] [<ffffffff8226ec87>] netdev_unregister_kobject+0x37/0x70
[ 1561.625979] [<ffffffff82253e26>] rollback_registered_many+0x186/0x260
[ 1561.628526] [<ffffffff82253f14>] unregister_netdevice_many+0x14/0x60
[ 1561.631064] [<ffffffff8243922e>] ip6_tnl_destroy_tunnels+0xee/0x160
[ 1561.633549] [<ffffffff8243b8f3>] ip6_tnl_exit_net+0xd3/0x1c0
[ 1561.635843] [<ffffffff8243b820>] ? ip6_tnl_ioctl+0x550/0x550
[ 1561.637972] [<ffffffff81259c86>] ? proc_net_remove+0x16/0x20
[ 1561.639881] [<ffffffff8224f119>] ops_exit_list+0x39/0x60
[ 1561.641666] [<ffffffff8224f72b>] cleanup_net+0xfb/0x1a0
[ 1561.643528] [<ffffffff810ce97d>] process_one_work+0x1cd/0x460
[ 1561.645828] [<ffffffff810ce91c>] ? process_one_work+0x16c/0x460
[ 1561.648180] [<ffffffff8224f630>] ? net_drop_ns+0x40/0x40
[ 1561.650285] [<ffffffff810d1e76>] worker_thread+0x176/0x3b0
[ 1561.652460] [<ffffffff810d1d00>] ? manage_workers+0x120/0x120
[ 1561.654734] [<ffffffff810d727e>] kthread+0xbe/0xd0
[ 1561.656656] [<ffffffff8270a134>] kernel_thread_helper+0x4/0x10
[ 1561.658881] [<ffffffff810e3fe0>] ? finish_task_switch+0x80/0x110
[ 1561.660828] [<ffffffff82708434>] ? retint_restore_args+0x13/0x13
[ 1561.662795] [<ffffffff810d71c0>] ? __init_kthread_worker+0x70/0x70
[ 1561.664932] [<ffffffff8270a130>] ? gs_change+0x13/0x13
[ 1561.667001] 4 locks held by kworker/u:2/3140:
[ 1561.667599] #0: (netns){.+.+.+}, at: [<ffffffff810ce91c>]
process_one_work+0x16c/0x460
[ 1561.668758] #1: (net_cleanup_work){+.+.+.}, at:
[<ffffffff810ce91c>] process_one_work+0x16c/0x460
[ 1561.670002] #2: (net_mutex){+.+.+.}, at: [<ffffffff8224f6b0>]
cleanup_net+0x80/0x1a0
[ 1561.671700] #3: (rtnl_mutex){+.+.+.}, at: [<ffffffff82267f02>]
rtnl_lock+0x12/0x20
^ permalink raw reply
* Re: [PATCH v17 08/15] seccomp: add system call filtering using BPF
From: Will Drewry @ 2012-03-31 18:14 UTC (permalink / raw)
To: Vladimir Murzin
Cc: linux-kernel, linux-security-module, linux-arch, linux-doc,
kernel-hardening, netdev, x86, arnd, davem, hpa, mingo, oleg,
peterz, rdunlap, mcgrathr, tglx, luto, eparis, serge.hallyn, djm,
scarybeasts, indan, pmoore, akpm, corbet, eric.dumazet, markus,
coreyb, keescook, jmorris
In-Reply-To: <20120331044030.GB3077@pinguin>
2012/3/30 Vladimir Murzin <murzin.v@gmail.com>:
> Hi Will,
>
> On Thu, Mar 29, 2012 at 03:01:53PM -0500, Will Drewry wrote:
>
> snipped
>
>> +
>> +/* Limit any path through the tree to 256KB worth of instructions. */
>> +#define MAX_INSNS_PER_PATH ((1 << 18) / sizeof(struct sock_filter))
>> +
>> +static void seccomp_filter_log_failure(int syscall)
>> +{
>> + int compat = 0;
>> +#ifdef CONFIG_COMPAT
>> + compat = is_compat_task();
>> +#endif
>> + pr_info("%s[%d]: %ssystem call %d blocked at 0x%lx\n",
>> + current->comm, task_pid_nr(current),
>> + (compat ? "compat " : ""),
>> + syscall, KSTK_EIP(current));
>> +}
>
> snipped
>
>> +/**
>> + * seccomp_attach_user_filter - attaches a user-supplied sock_fprog
>> + * @user_filter: pointer to the user data containing a sock_fprog.
>> + *
>> + * Returns 0 on success and non-zero otherwise.
>> + */
>> +long seccomp_attach_user_filter(char __user *user_filter)
>> +{
>> + struct sock_fprog fprog;
>> + long ret = -EFAULT;
>> +
>> +#ifdef CONFIG_COMPAT
>> + if (is_compat_task()) {
>> + struct compat_sock_fprog fprog32;
>> + if (copy_from_user(&fprog32, user_filter, sizeof(fprog32)))
>> + goto out;
>> + fprog.len = fprog32.len;
>> + fprog.filter = compat_ptr(fprog32.filter);
>> + } else /* falls through to the if below. */
>> +#endif
>> + if (copy_from_user(&fprog, user_filter, sizeof(fprog)))
>> + goto out;
>> + ret = seccomp_attach_filter(&fprog);
>> +out:
>> + return ret;
>> +}
>
> Do we really need to surround is_compat_task() with CNFIG_COMPAT?
> It seems that this case has already handled in compat.h [1]
>
> [1] http://lxr.linux.no/#linux+v3.3/include/linux/compat.h#L566
In log_failure, it's not needed at all, but that function disappears
in a subsequent patch in the series that converts over to using the
auditing framework. For the next use of CONFIG_COMPAT, it is more
important for guarding the compat_sock_fprog struct (which isn't
doubly defined) rather than the is_compat_task.
Thanks!
will
^ permalink raw reply
* Packet mmap payload alignment.
From: Paul Chavent @ 2012-03-31 19:47 UTC (permalink / raw)
To: davem, netdev, linux-kernel
Hi.
I'm playing with the packet mmap interface. After having success with SOCK_DGRAM, i would like to try SOCK_RAW packet mmap.
I would like to align my payload on 16 bytes boundary. On rx side, it's automatic. But on tx side, it lacks the possibility to tell to the kernel where to begin to read the data.
Do i miss something ?
Do you think it could be possible to have a "reserve" like on the rx side ?
Regards.
Paul.
P.S. : can you cc me your reply please ?
^ permalink raw reply
* Re: ipv6: tunnel: hang when destroying ipv6 tunnel
From: Eric Dumazet @ 2012-03-31 20:59 UTC (permalink / raw)
To: Sasha Levin
Cc: davem, kuznet, jmorris, yoshfuji, Patrick McHardy, netdev,
linux-kernel@vger.kernel.org List, Dave Jones, Oleg Nesterov
In-Reply-To: <CA+1xoqfA9FMowOmAXYHtkXB+D6FqgjCRREKPOk_m2c9ZCyaN4A@mail.gmail.com>
On Sat, 2012-03-31 at 19:51 +0200, Sasha Levin wrote:
> Hi all,
>
> It appears that a hang may occur when destroying an ipv6 tunnel, which
> I've reproduced several times in a KVM vm.
>
> The pattern in the stack dump below is consistent with unregistering a
> kobject when holding multiple locks. Unregistering a kobject usually
> leads to an exit back to userspace with call_usermodehelper_exec().
Yes but this userspace call is done asynchronously and we dont have to
wait its done.
> The userspace code may access sysfs files which in turn will require
> locking within the kernel, leading to a deadlock since those locks are
> already held by kernel.
>
> [ 1561.564172] INFO: task kworker/u:2:3140 blocked for more than 120 seconds.
> [ 1561.566945] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs"
> disables this message.
> [ 1561.570062] kworker/u:2 D ffff88006ee63000 4504 3140 2 0x00000000
> [ 1561.572968] ffff88006ed9f7e0 0000000000000082 ffff88006ed9f790
> ffffffff8107d346
> [ 1561.575680] ffff88006ed9ffd8 00000000001d4580 ffff88006ed9e010
> 00000000001d4580
> [ 1561.578601] 00000000001d4580 00000000001d4580 ffff88006ed9ffd8
> 00000000001d4580
> [ 1561.581697] Call Trace:
> [ 1561.582650] [<ffffffff8107d346>] ? kvm_clock_read+0x46/0x80
> [ 1561.584543] [<ffffffff827063d4>] schedule+0x24/0x70
> [ 1561.586231] [<ffffffff82704025>] schedule_timeout+0x245/0x2c0
> [ 1561.588508] [<ffffffff81117c9a>] ? mark_held_locks+0x7a/0x120
> [ 1561.590858] [<ffffffff81119bbd>] ? __lock_release+0x8d/0x1d0
> [ 1561.593162] [<ffffffff82707e6b>] ? _raw_spin_unlock_irq+0x2b/0x70
> [ 1561.595394] [<ffffffff810e36d1>] ? get_parent_ip+0x11/0x50
> [ 1561.597403] [<ffffffff82705919>] wait_for_common+0x119/0x190
> [ 1561.599707] [<ffffffff810ed1b0>] ? try_to_wake_up+0x2c0/0x2c0
> [ 1561.601758] [<ffffffff82705a38>] wait_for_completion+0x18/0x20
Something is wrong here, call_usermodehelper_exec ( ... UMH_WAIT_EXEC)
should not block forever. Its not like UMH_WAIT_PROC
Cc Oleg Nesterov <oleg@redhat.com>
> [ 1561.603843] [<ffffffff810cdcd8>] call_usermodehelper_exec+0x228/0x240
> [ 1561.606059] [<ffffffff82705844>] ? wait_for_common+0x44/0x190
> [ 1561.608352] [<ffffffff81878445>] kobject_uevent_env+0x615/0x650
> [ 1561.610908] [<ffffffff810e36d1>] ? get_parent_ip+0x11/0x50
> [ 1561.613146] [<ffffffff8187848b>] kobject_uevent+0xb/0x10
> [ 1561.615312] [<ffffffff81876f5a>] kobject_cleanup+0xca/0x1b0
> [ 1561.617509] [<ffffffff8187704d>] kobject_release+0xd/0x10
> [ 1561.619334] [<ffffffff81876d9c>] kobject_put+0x2c/0x60
> [ 1561.621117] [<ffffffff8226ea80>] net_rx_queue_update_kobjects+0xa0/0xf0
> [ 1561.623421] [<ffffffff8226ec87>] netdev_unregister_kobject+0x37/0x70
> [ 1561.625979] [<ffffffff82253e26>] rollback_registered_many+0x186/0x260
> [ 1561.628526] [<ffffffff82253f14>] unregister_netdevice_many+0x14/0x60
> [ 1561.631064] [<ffffffff8243922e>] ip6_tnl_destroy_tunnels+0xee/0x160
> [ 1561.633549] [<ffffffff8243b8f3>] ip6_tnl_exit_net+0xd3/0x1c0
> [ 1561.635843] [<ffffffff8243b820>] ? ip6_tnl_ioctl+0x550/0x550
> [ 1561.637972] [<ffffffff81259c86>] ? proc_net_remove+0x16/0x20
> [ 1561.639881] [<ffffffff8224f119>] ops_exit_list+0x39/0x60
> [ 1561.641666] [<ffffffff8224f72b>] cleanup_net+0xfb/0x1a0
> [ 1561.643528] [<ffffffff810ce97d>] process_one_work+0x1cd/0x460
> [ 1561.645828] [<ffffffff810ce91c>] ? process_one_work+0x16c/0x460
> [ 1561.648180] [<ffffffff8224f630>] ? net_drop_ns+0x40/0x40
> [ 1561.650285] [<ffffffff810d1e76>] worker_thread+0x176/0x3b0
> [ 1561.652460] [<ffffffff810d1d00>] ? manage_workers+0x120/0x120
> [ 1561.654734] [<ffffffff810d727e>] kthread+0xbe/0xd0
> [ 1561.656656] [<ffffffff8270a134>] kernel_thread_helper+0x4/0x10
> [ 1561.658881] [<ffffffff810e3fe0>] ? finish_task_switch+0x80/0x110
> [ 1561.660828] [<ffffffff82708434>] ? retint_restore_args+0x13/0x13
> [ 1561.662795] [<ffffffff810d71c0>] ? __init_kthread_worker+0x70/0x70
> [ 1561.664932] [<ffffffff8270a130>] ? gs_change+0x13/0x13
> [ 1561.667001] 4 locks held by kworker/u:2/3140:
> [ 1561.667599] #0: (netns){.+.+.+}, at: [<ffffffff810ce91c>]
> process_one_work+0x16c/0x460
> [ 1561.668758] #1: (net_cleanup_work){+.+.+.}, at:
> [<ffffffff810ce91c>] process_one_work+0x16c/0x460
> [ 1561.670002] #2: (net_mutex){+.+.+.}, at: [<ffffffff8224f6b0>]
> cleanup_net+0x80/0x1a0
> [ 1561.671700] #3: (rtnl_mutex){+.+.+.}, at: [<ffffffff82267f02>]
> rtnl_lock+0x12/0x20
> --
^ permalink raw reply
* [patch net-next 0/4] Introduce BPF-based TX port selecting for Team device
From: Jiri Pirko @ 2012-03-31 21:01 UTC (permalink / raw)
To: netdev
Cc: davem, eric.dumazet, bhutchings, shemminger, raise.sail,
nuno.martins, matt
Jiri Pirko (4):
filter: Allow to create sk-unattached filters
filter: add XOR operation
team: add binary option type
team: add loadbalance mode
drivers/net/team/Kconfig | 11 ++
drivers/net/team/Makefile | 1 +
drivers/net/team/team.c | 28 ++++-
drivers/net/team/team_mode_loadbalance.c | 188 ++++++++++++++++++++++++++++++
include/linux/filter.h | 7 +-
include/linux/if_team.h | 8 ++
net/core/filter.c | 70 +++++++++++-
7 files changed, 304 insertions(+), 9 deletions(-)
create mode 100644 drivers/net/team/team_mode_loadbalance.c
--
1.7.9.1
^ permalink raw reply
* [patch net-next 1/4] filter: Allow to create sk-unattached filters
From: Jiri Pirko @ 2012-03-31 21:01 UTC (permalink / raw)
To: netdev
Cc: davem, eric.dumazet, bhutchings, shemminger, raise.sail,
nuno.martins, matt
In-Reply-To: <1333227682-10235-1-git-send-email-jpirko@redhat.com>
Today, BPF filters are bind to sockets. Since BPF machine becomes handy
for other purposes, this patch allows to create unattached filter.
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
---
include/linux/filter.h | 3 ++
net/core/filter.c | 66 +++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 65 insertions(+), 4 deletions(-)
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 8eeb205..92dd993 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -153,6 +153,9 @@ static inline unsigned int sk_filter_len(const struct sk_filter *fp)
extern int sk_filter(struct sock *sk, struct sk_buff *skb);
extern unsigned int sk_run_filter(const struct sk_buff *skb,
const struct sock_filter *filter);
+extern int sk_unattached_filter_create(struct sk_filter **pfp,
+ struct sock_fprog *fprog);
+extern void sk_unattached_filter_destroy(struct sk_filter *fp);
extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk);
extern int sk_detach_filter(struct sock *sk);
extern int sk_chk_filter(struct sock_filter *filter, unsigned int flen);
diff --git a/net/core/filter.c b/net/core/filter.c
index 5dea452..cfbea88 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -587,6 +587,67 @@ void sk_filter_release_rcu(struct rcu_head *rcu)
}
EXPORT_SYMBOL(sk_filter_release_rcu);
+static int __sk_prepare_filter(struct sk_filter *fp)
+{
+ int err;
+
+ fp->bpf_func = sk_run_filter;
+
+ err = sk_chk_filter(fp->insns, fp->len);
+ if (err)
+ return err;
+
+ bpf_jit_compile(fp);
+ return 0;
+}
+
+/**
+ * sk_unattached_filter_create - create an unattached filter
+ * @fprog: the filter program
+ * @sk: the socket to use
+ *
+ * Create a filter independent ofr any socket. We first run some
+ * sanity checks on it to make sure it does not explode on us later.
+ * If an error occurs or there is insufficient memory for the filter
+ * a negative errno code is returned. On success the return is zero.
+ */
+int sk_unattached_filter_create(struct sk_filter **pfp,
+ struct sock_fprog *fprog)
+{
+ struct sk_filter *fp;
+ unsigned int fsize = sizeof(struct sock_filter) * fprog->len;
+ int err;
+
+ /* Make sure new filter is there and in the right amounts. */
+ if (fprog->filter == NULL)
+ return -EINVAL;
+
+ fp = kmalloc(fsize + sizeof(*fp), GFP_KERNEL);
+ if (!fp)
+ return -ENOMEM;
+ memcpy(fp->insns, fprog->filter, fsize);
+
+ atomic_set(&fp->refcnt, 1);
+ fp->len = fprog->len;
+
+ err = __sk_prepare_filter(fp);
+ if (err)
+ goto free_mem;
+
+ *pfp = fp;
+ return 0;
+free_mem:
+ kfree(fp);
+ return err;
+}
+EXPORT_SYMBOL_GPL(sk_unattached_filter_create);
+
+void sk_unattached_filter_destroy(struct sk_filter *fp)
+{
+ sk_filter_release(fp);
+}
+EXPORT_SYMBOL_GPL(sk_unattached_filter_destroy);
+
/**
* sk_attach_filter - attach a socket filter
* @fprog: the filter program
@@ -617,16 +678,13 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
atomic_set(&fp->refcnt, 1);
fp->len = fprog->len;
- fp->bpf_func = sk_run_filter;
- err = sk_chk_filter(fp->insns, fp->len);
+ err = __sk_prepare_filter(fp);
if (err) {
sk_filter_uncharge(sk, fp);
return err;
}
- bpf_jit_compile(fp);
-
old_fp = rcu_dereference_protected(sk->sk_filter,
sock_owned_by_user(sk));
rcu_assign_pointer(sk->sk_filter, fp);
--
1.7.9.1
^ permalink raw reply related
* [patch net-next 2/4] filter: add XOR operation
From: Jiri Pirko @ 2012-03-31 21:01 UTC (permalink / raw)
To: netdev
Cc: davem, eric.dumazet, bhutchings, shemminger, raise.sail,
nuno.martins, matt
In-Reply-To: <1333227682-10235-1-git-send-email-jpirko@redhat.com>
Add XOR instruction fo BPF machine. Needed for computing packet hashes.
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
---
include/linux/filter.h | 4 +++-
net/core/filter.c | 4 ++++
2 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 92dd993..7209099 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -126,7 +126,8 @@ struct sock_fprog { /* Required for SO_ATTACH_FILTER. */
#define SKF_AD_HATYPE 28
#define SKF_AD_RXHASH 32
#define SKF_AD_CPU 36
-#define SKF_AD_MAX 40
+#define SKF_AD_ALU_XOR_X 40
+#define SKF_AD_MAX 44
#define SKF_NET_OFF (-0x100000)
#define SKF_LL_OFF (-0x200000)
@@ -231,6 +232,7 @@ enum {
BPF_S_ANC_HATYPE,
BPF_S_ANC_RXHASH,
BPF_S_ANC_CPU,
+ BPF_S_ANC_ALU_XOR_X,
};
#endif /* __KERNEL__ */
diff --git a/net/core/filter.c b/net/core/filter.c
index cfbea88..5099c4b 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -315,6 +315,9 @@ load_b:
case BPF_S_ANC_CPU:
A = raw_smp_processor_id();
continue;
+ case BPF_S_ANC_ALU_XOR_X:
+ A ^= X;
+ continue;
case BPF_S_ANC_NLATTR: {
struct nlattr *nla;
@@ -559,6 +562,7 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen)
ANCILLARY(HATYPE);
ANCILLARY(RXHASH);
ANCILLARY(CPU);
+ ANCILLARY(ALU_XOR_X);
}
}
ftest->code = code;
--
1.7.9.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox