Bug 95211
Summary: | IPsec + VTI: kernel BUG xfrm_input (NULL pointer dereference) | ||
---|---|---|---|
Product: | Networking | Reporter: | Mike Noordermeer (mike) |
Component: | Other | Assignee: | Stephen Hemminger (stephen) |
Status: | NEW --- | ||
Severity: | normal | CC: | adobriyan |
Priority: | P1 | ||
Hardware: | All | ||
OS: | Linux | ||
Kernel Version: | 4.0-rc4, 3.16.7, 3.17.8, 3.18.9 | Subsystem: | |
Regression: | No | Bisected commit-id: | |
Attachments: |
poison ->outer_mode
Panics incl patch Config file XFRM_STATE_ACQ origin Panic incl. debug trace do xfrm_tunnel_check() later |
Description
Mike Noordermeer
2015-03-22 13:28:55 UTC
Created attachment 171981 [details]
poison ->outer_mode
Please try running debugging patch, it will dump bogus xfrm_state object. Created attachment 172331 [details]
Panics incl patch
One of the machines just panicked with the patch applied - it then entered a 'panic loop', each time the IPSec daemon (Strongswan) started the machine panicked again. Attached are the dumps, panic is at the same line as before. Hope it helps, let me know if you need more info.
Thanks for testing. Could you please also attach .config you've used for building this 4.0.0-rc4 kernel. Layout of xfrm_state can be somewhat different. Created attachment 172341 [details]
Config file
Attached is the config file (based on default Debian config from 3.16)
The very first xfrm_state in dmesg posted: non-0/NULL fields are name offset/sizeof ------------------ ->xs_net 0/8 ->bydst 8/16 ->bysrc 18/16 ->byspi 28/16 ->refcnt 38/4 ->lock 3c/4 ->id 40/24 ->sel 58/56 ->km a0/32 ->props c0/40 ->lft e8/64 ->rtimer 1a8/80 ->curlft 208/32 ->mtimer 228/144 ->km.state at b0/1 x->km.state = XFRM_STATE_ACQ; //1 Created attachment 172351 [details]
XFRM_STATE_ACQ origin
Please apply patch, it will print address of guilty xfrm_state object before panic. There are only 2 places which set XFRM_STATE_ACQ, find that address previously in dmesg. It will be either XFRM_STATE_ACQ 001 x XXXXXXXX or XFRM_STATE_ACQ 002 x XXXXXXXX I don't know how much spam it will result in. If it is not much, then insert "dump_stack();" into the place where XFRM_STATE_ACQ came from. I only see XFRM_STATE_ACQ 002 messages - I'll insert dump_stack(); to get a full stack trace. Created attachment 172811 [details]
Panic incl. debug trace
Panic with the debug traces is attached. It seems to panic on the last XFRM_STATE_ACQ, which was logged less than a second ago, probably the IPsec tunnel has not yet been fully established or something? > It seems to panic on the last XFRM_STATE_ACQ,
> which was logged less than a second ago
yeah, the pointers are the same:
XFRM_STATE_ACQ 002 x ffff88003c543000
[<ffffffff8150b731>] ? __find_acq_core+0x1d1/0x410
[<ffffffff8150b9ff>] ? xfrm_find_acq+0x8f/0xc0
[<ffffffffa0612803>] ? xfrm_alloc_userspi+0xe3/0x210 [xfrm_user]
vs
xfrm_tunnel_check: ->outer_mode NULL: x ffff88003c543000
BUG: unable to handle kernel NULL pointer dereference at 0000000000000034
IP: [<ffffffff8150dd1b>] xfrm_input+0x3fb/0x5e0
[<ffffffff81500fc6>] ? xfrm4_esp_rcv+0x36/0x70
Well, technically bug is simple: 1) userspace sends XFRM_MSG_ALLOCSPI, xfrm_alloc_userspi() xfrm_find_acq(create=1) xfrm_alloc_spi() inserts object into state_byspi hash 2) packet comes xfrm_input() xfrm_parse_spi() gets spi xfrm_state_lookup() finds object in spi hash but ->outer_mode is not yet set in __xfrm_init_state() which is executed only for XFRM_MSG_NEWSA Can you test patch which does xfrm_tunnel_check() later? All previous patches aren't needed anymore. Created attachment 172821 [details]
do xfrm_tunnel_check() later
Thanks for the analysis and patch, building/installing a new kernel with the patch now, I will let you know the results. I am wondering though - will it now drop the packet if it is still in XFRM_STATE_ACQ? I disabled reauth, so shouldn't it use the old SA while it is rekeying, i.e., should it not match a different SA/state? Packet will be dropped, yes. Please, don't change userspace settings, so there would be no false fixes. I have not changed the reauth/userspace settings (reauth was already disabled), was just wondering if the dropping of the packet could be prevented somehow - it seems weird to need to drop a packet for an active tunnel. That tunnel check is relatively recent. Packet was dropped in earlier versions as well. commit 4c4d41f200db375b2d2cc6d0a1de0606c8266398 xfrm: add LINUX_MIB_XFRMACQUIREERROR statistic counter When host ping its peer, ICMP echo request packet triggers IPsec policy, then host negotiates SA secret with its peer. After IKE installed SA for OUT direction, but before SA for IN direction installed, host get ICMP echo reply from its peer. At the time being, the SA state for IN direction could be XFRM_STATE_ACQ, then the received packet will be dropped after adding LINUX_MIB_XFRMINSTATEINVALID statistic. Adding a LINUX_MIB_XFRMACQUIREERROR statistic counter for such scenario when SA in larval state is much clearer for user than LINUX_MIB_XFRMINSTATEINVALID which indicates the SA is totally bad. Uptime of the machines is 6+ days now, where it would crash every 1-2 days before, so the patch seems to have fixed the issue. Thanks! I am still wondering though: why packets should ever be dropped for an existing tunnel? I know that reauthing removes the existing tunnel and creates a new one (but reauth is disabled), and rekeying should first install new keys and then remove the old ones, so that shouldn't drop packets? fixed by commit 68c11e98ef6748ddb63865799b12fc45abb3755d xfrm: fix xfrm_input/xfrm_tunnel_check oops |