Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Null pointer dereference in kernel module #352

Open
sysvinit opened this issue Jan 3, 2021 · 12 comments
Open

Null pointer dereference in kernel module #352

sysvinit opened this issue Jan 3, 2021 · 12 comments
Labels
Bug Status: Stuck Development paused due to unavailable external input

Comments

@sysvinit
Copy link
Contributor

sysvinit commented Jan 3, 2021

I'm running Jool on a pair of Debian Buster VM's, which are acting as border routers for a test network I'm operating. Both of these machines are running Debian's 4.19.160 kernel, and Jool version 4.1.4 with the issue #340 patches cherry-picked from master (so NAT64 session replication works correctly).

One of these two routers (which I suspect handles more traffic than the other) has spontaneously crashed twice within 24 hours, with the same kernel panic trace in both cases, which seems to indicate a null pointer dereference within the jool_common kernel module.

Both machines are performing SIIT and NAT64 functions simultaneously, using iptables to inject traffic to the appropriate kernel module based on source and destination address:

  • IPv4 packets entering the test network whose destination address is in the NAT64 pool4 are sent to jool.
  • IPv4 packets entering the network whose destination address is within a prefix configured in the SIIT EAMT are sent to jool_siit.
  • IPv6 packets leaving the test network whose destination is within the pool6 prefix and whose source address is within a prefix configured in the SIIT EAMT are sent to jool_siit.
  • All other egress IPv6 packets whose destination is within the pool6 prefix are sent to jool.

iptables on Debian Buster is a synonym for iptables-nft, so the packet matching logic is actually attached to netfilter instead of the old kernel iptables implementation.

Panic trace:

[41296.788688] BUG: unable to handle kernel NULL pointer dereference at 0000000000000008
[41296.791050] PGD 0 P4D 0
[41296.791770] Oops: 0000 [#1] SMP PTI
[41296.792699] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G           OE     4.19.0-13-amd64 #1 Debian 4.19.160-2
[41296.795322] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014
[41296.797575] RIP: 0010:skb_release_data+0x76/0x170
[41296.799032] Code: 00 31 db 41 80 7c 24 02 00 48 89 fd 75 10 eb 46 41 0f b6 44 24 02 48 83 c3 01 39 d8 7e 38 48 89 d8 48 c1 e0 04 49 8b 7c 04 30 <48> 8b 47 08 48 8d 50 ff a8 01 48 0f 45 fa 66 66 66 66 90 f0 ff 4f
[41296.804273] RSP: 0018:ffff9ddb3ba03960 EFLAGS: 00010246
[41296.806451] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000004
[41296.808209] RDX: 0000000000000000 RSI: 0000000000000043 RDI: 0000000000000000
[41296.809723] RBP: ffff9ddb35c18200 R08: 0000000034e3ffff R09: 0000000000000000
[41296.811240] R10: 0000000000000000 R11: 0000000000000003 R12: ffff9dda970c6cc0
[41296.812690] R13: ffff9ddb35c18d00 R14: ffff9ddb0fd0e500 R15: ffff9ddb0fd0e5c8
[41296.814198] FS:  0000000000000000(0000) GS:ffff9ddb3ba00000(0000) knlGS:0000000000000000
[41296.815823] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[41296.817072] CR2: 0000000000000008 CR3: 0000000135a66000 CR4: 00000000000406f0
[41296.819049] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[41296.820942] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[41296.822950] Call Trace:
[41296.823572]  
[41296.824031]  ? kfree_skb_list+0x13/0x20
[41296.824866]  kfree_skb+0x32/0xa0
[41296.825648]  kfree_skb_list+0x13/0x20
[41296.826448]  translating_the_packet+0x197/0x200 [jool_common]
[41296.827645]  core_common+0x44/0x110 [jool_common]
[41296.828604]  core_4to6+0x7c/0xd0 [jool_common]
[41296.829489]  target_ipv4+0x65/0x80 [jool_common]
[41296.830615]  nft_target_eval_xt+0x35/0x50 [nft_compat]
[41296.831676]  nft_do_chain+0xea/0x420 [nf_tables]
[41296.832621]  ? nf_ct_get_tuple+0x1da/0x1f0 [nf_conntrack]
[41296.833861]  ? ip_route_input_slow+0x33f/0xae0
[41296.834770]  ? __skb_checksum+0x6c/0x2c0
[41296.835746]  ? nf_ct_get_tuplepr+0x70/0xa0 [nf_conntrack]
[41296.837343]  ? icmp_packet+0x50/0x50 [nf_conntrack]
[41296.838808]  ? icmp_error+0x1ca/0x2c0 [nf_conntrack]
[41296.840510]  ? nf_conntrack_in+0xd0/0x4c0 [nf_conntrack]
[41296.842112]  nft_do_chain_ipv4+0x66/0x80 [nf_tables]
[41296.843208]  nf_hook_slow+0x44/0xc0
[41296.843938]  ip_rcv+0x91/0xd0
[41296.844577]  ? ip_rcv_finish_core.isra.18+0x360/0x360
[41296.845836]  __netif_receive_skb_one_core+0x5a/0x80
[41296.847004]  netif_receive_skb_internal+0x2f/0xa0
[41296.848035]  napi_gro_receive+0xba/0xe0
[41296.849027]  receive_buf+0x175/0x1510 [virtio_net]
[41296.851930]  ? try_to_wake_up+0x54/0x470
[41296.854334]  ? vring_unmap_one+0x16/0x70 [virtio_ring]
[41296.856923]  ? detach_buf+0x69/0x110 [virtio_ring]
[41296.859383]  virtnet_poll+0x143/0x328 [virtio_net]
[41296.862004]  net_rx_action+0x149/0x3b0
[41296.864069]  __do_softirq+0xde/0x2d8
[41296.866086]  irq_exit+0xba/0xc0
[41296.868398]  do_IRQ+0x7f/0xe0
[41296.871163]  common_interrupt+0xf/0xf
[41296.873226]  
[41296.874842] RIP: 0010:native_safe_halt+0xe/0x10
[41296.876902] Code: ff ff 7f c3 65 48 8b 04 25 40 5c 01 00 f0 80 48 02 20 48 8b 00 a8 08 75 c4 eb 80 90 e9 07 00 00 00 0f 00 2d d6 4d 4d 00 fb f4  90 e9 07 00 00 00 0f 00 2d c6 4d 4d 00 f4 c3 90 90 66 66 66 66
[41296.883374] RSP: 0018:ffffffff8c603e88 EFLAGS: 00000246 ORIG_RAX: ffffffffffffffd7
[41296.886095] RAX: ffffffff8bd32cc0 RBX: 0000000000000000 RCX: ffffffff8c64f210
[41296.889116] RDX: 000000000a7a7fc6 RSI: ffffffff8c64ae78 RDI: 0000000000000086
[41296.891816] RBP: 0000000000000000 R08: 00002771dc7ffa1d R09: 0000258f0798cb79
[41296.894458] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000
[41296.897380] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
[41296.900296]  ? __sched_text_end+0x7/0x7
[41296.903448]  default_idle+0x1c/0x140
[41296.905487]  do_idle+0x1e3/0x270
[41296.907426]  cpu_startup_entry+0x6f/0x80
[41296.909477]  start_kernel+0x507/0x52a
[41296.911695]  secondary_startup_64+0xa4/0xb0
[41296.914003] Modules linked in: sctp nft_chain_route_ipv6 ipt_REJECT nf_reject_ipv4 xt_multiport nft_counter nft_chain_route_ipv4 xt_conntrack nf_conntrack libcrc32c nft_compat nf_tables nfnetlink crct10dif_pclmul crc32_pclmul cirrus ghash_clmulni_intel ttm drm_kms_helper sg joydev evdev virtio_balloon drm serio_raw pcspkr qemu_fw_cfg button jool_siit(OE) jool(OE) jool_common(OE) nf_defrag_ipv6 nf_defrag_ipv4 tun dummy wireguard(E) ip6_udp_tunnel udp_tunnel ip_tables x_tables autofs4 ext4 hid_generic usbhid hid crc16 mbcache jbd2 crc32c_generic fscrypto ecb virtio_net net_failover virtio_blk failover sr_mod cdrom ata_generic crc32c_intel ata_piix libata aesni_intel uhci_hcd aes_x86_64 ehci_pci crypto_simd cryptd ehci_hcd glue_helper usbcore scsi_mod psmouse usb_common virtio_pci virtio_ring virtio
[41296.941006]  i2c_piix4 floppy
[41296.944211] CR2: 0000000000000008
[41296.946906] ---[ end trace a83411d47bce2273 ]---
[41296.949420] RIP: 0010:skb_release_data+0x76/0x170
[41296.952295] Code: 00 31 db 41 80 7c 24 02 00 48 89 fd 75 10 eb 46 41 0f b6 44 24 02 48 83 c3 01 39 d8 7e 38 48 89 d8 48 c1 e0 04 49 8b 7c 04 30 <48> 8b 47 08 48 8d 50 ff a8 01 48 0f 45 fa 66 66 66 66 90 f0 ff 4f
[41296.959247] RSP: 0018:ffff9ddb3ba03960 EFLAGS: 00010246
[41296.961815] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000004
[41296.965986] RDX: 0000000000000000 RSI: 0000000000000043 RDI: 0000000000000000
[41296.969640] RBP: ffff9ddb35c18200 R08: 0000000034e3ffff R09: 0000000000000000
[41296.972795] R10: 0000000000000000 R11: 0000000000000003 R12: ffff9dda970c6cc0
[41296.975884] R13: ffff9ddb35c18d00 R14: ffff9ddb0fd0e500 R15: ffff9ddb0fd0e5c8
[41296.979414] FS:  0000000000000000(0000) GS:ffff9ddb3ba00000(0000) knlGS:0000000000000000
[41296.982955] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[41296.986260] CR2: 0000000000000008 CR3: 0000000135a66000 CR4: 00000000000406f0
[41296.989694] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[41296.992820] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[41296.996134] Kernel panic - not syncing: Fatal exception in interrupt
[41297.000474] Kernel Offset: 0xa600000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
[41297.004614] ---[ end Kernel panic - not syncing: Fatal exception in interrupt ]---
@ydahhrk
Copy link
Member

ydahhrk commented Jan 3, 2021

According to the vmlinux, it's crashing here.

(One possible call stack is skb_release_data() -> __skb_frag_unref() > put_page() > compound_head() > READ_ONCE() > __READ_ONCE() -> __read_once_size().)

So apparently, some packet page is NULL. It's annoying, because page management is buried deep within the confines of the kernel API. Jool has nothing to do with them.

But what's more baffling is that you got two kernel crashes in so little time. The bug doesn't seem to have anything to do with joold, which means it's likely to not have been introduced in the #340 patches. But if it was still present in Jool 4.1.4, I'm surprised nobody seems to have run into it before. 4.1.4 is almost three months old.

Would you be able to attempt to reproduce the bug with Jool 4.1.4, and without joold?

@ydahhrk ydahhrk added Bug Status: Active Development is underway labels Jan 3, 2021
@sysvinit
Copy link
Contributor Author

sysvinit commented Jan 3, 2021

Unfortunately, I don't have any reliable means to trigger this particular crash. Both of the times when it's crashed so far have been overnight when I've been asleep, and I've woken up in the morning to find the machine unresponsive.

If I find that the crashes continue, I'll revert the #340 patches, reinstall, and see what happens without running joold.

@ydahhrk
Copy link
Member

ydahhrk commented Jan 3, 2021

Here's a likely better option: I just uploaded a patch to the issue352 branch.

If my suspicions are correct, the patch should catch the bug, print a bunch of debugging information and leak the packet. (Instead of crashing the kernel.) It is not a long-term solution, but should give us valuable insight.

Sample output:

[  362.444325] Bug #352 found!
[  362.444326] =================
[  362.444327] Incoming packet
[  362.444328]     skb fields:
[  362.444330]         prev:          (null)
[  362.444332]         next:          (null)
[  362.444334]         dev:00000000ef69ff80
[  362.444336]         len:32
[  362.444338]         data_len:0
[  362.444340]         mac_len:14
[  362.444341]         hdr_len:0
[  362.444343]         truesize:768
[  362.444345]         pkt_type:0
[  362.444346]         ignore_df:0
[  362.444348]         ip_summed:0 (CHECKSUM_NONE)
[  362.444350]         csum_valid:0
[  362.444351]         csum_start:0
[  362.444353]         csum_offset:0
[  362.444355]         mark:0
[  362.444356]         inner_transport_header:0
[  362.444358]         inner_network_header:0
[  362.444359]         inner_mac_header:0
[  362.444361]         protocol:2048 (IPv4)
[  362.444363]         transport_header:148
[  362.444364]         network_header:128
[  362.444366]         mac_header:114
[  362.444368]         head:00000000c7151709
[  362.444369]         data:128
[  362.444371]         tail:160
[  362.444373]         end:192
[  362.444374]     Content:
[  362.444376]         IPv4 header:
[  362.444378]             Version: 4
[  362.444379]             IHL: 5
[  362.444381]             TOS: 0
[  362.444383]             Total Length: 32
[  362.444385]             Fragment ID: 0
[  362.444387]             Reserved:0 DF:1 MF:1 FragmentOffset: 0
[  362.444389]             TTL: 64
[  362.444391]             Protocol: 17
[  362.444393]             Checksum: 0x2e76
[  362.444395]             Source Address: 198.51.100.2
[  362.444397]             Destination Address: 192.0.2.33
[  362.444399]         UDP header:
[  362.444401]             Src Port: 2000
[  362.444403]             Dst Port: 4000
[  362.444405]             Length: 12
[  362.444407]             Checksum: 0x0
[  362.444409]         Payload:
[  362.444410]             00 01 02 03 
[  362.444414]     shared info:
[  362.444415]         nr_frags:0
[  362.444417]         tx_flags:0
[  362.444418]         gso_size:0
[  362.444420]         gso_segs:0
[  362.444421]         gso_type:0
[  362.444423]         frags:
[  362.444424] =================
[  362.444426] Outgoing packet
[  362.444426]     skb fields:
[  362.444428]         prev:          (null)
[  362.444429]         next:          (null)
[  362.444431]         dev:00000000ef69ff80
[  362.444433]         len:60
[  362.444434]         data_len:0
[  362.444436]         mac_len:0
[  362.444437]         hdr_len:0
[  362.444439]         truesize:768
[  362.444440]         pkt_type:0
[  362.444442]         ignore_df:0
[  362.444443]         ip_summed:0 (CHECKSUM_NONE)
[  362.444445]         csum_valid:0
[  362.444446]         csum_start:0
[  362.444448]         csum_offset:0
[  362.444450]         mark:0
[  362.444451]         inner_transport_header:0
[  362.444453]         inner_network_header:0
[  362.444454]         inner_mac_header:0
[  362.444456]         protocol:34525 (IPv6)
[  362.444458]         transport_header:176
[  362.444459]         network_header:128
[  362.444461]         mac_header:128
[  362.444462]         head:00000000ba5af142
[  362.444464]         data:128
[  362.444465]         tail:188
[  362.444467]         end:192
[  362.444468]     Content:
[  362.444470]         IPv6 header:
[  362.444471]             Version: 6
[  362.444473]             Priority: 0
[  362.444475]             Flow Label: 0x000000
[  362.444477]             Payload Length: 20
[  362.444479]             Next Header: 44
[  362.444480]             Hop Limit: 63
[  362.444482]             Source Address: 2001:db8:1c6:3364:2::
[  362.444485]             Destination Address: 2001:db8:1c0:2:21::
[  362.444487]         Fragment Header:
[  362.444489]             Next Header: 17
[  362.444491]             Reserved: 0
[  362.444493]             FragmentOffset:0 Res:0 M:1
[  362.444495]             Identification: 0
[  362.444497]         UDP header:
[  362.444498]             Src Port: 2000
[  362.444500]             Dst Port: 4000
[  362.444502]             Length: 12
[  362.444503]             Checksum: 0x0
[  362.444505]         Payload:
[  362.444506]             00 01 02 03 
[  362.444510]     shared info:
[  362.444511]         nr_frags:0
[  362.444512]         tx_flags:0
[  362.444514]         gso_size:0
[  362.444515]         gso_segs:0
[  362.444517]         gso_type:0
[  362.444518]         frags:

You can get the output from dmesg, after the bug has happened.

@sysvinit
Copy link
Contributor Author

sysvinit commented Jan 3, 2021

Okay, I'll patch and rebuild the kernel module on the affected router, and see if that logs anything.

@ydahhrk
Copy link
Member

ydahhrk commented Jan 11, 2021

Still nothing?

@sysvinit
Copy link
Contributor Author

Unfortunately I haven't seen any further cases of this error happening since I installed a version of Jool with the logging patch applied.

@ydahhrk
Copy link
Member

ydahhrk commented Jan 11, 2021

Ok.

  • This bug is unlikely to have been introduced in the latest patches.
  • We might have to wait a while before the bug happens again.
  • I don't want this wait to stall the release of 4.1.5.

Therefore, I'm going to commit the temporary patch to master. A memory leak is a bug, but it's better than a kernel crash at least.

I'm expecting to release 4.1.5 roughly at the end of the month.

@ydahhrk ydahhrk added this to the 4.1.5 milestone Jan 11, 2021
@sysvinit
Copy link
Contributor Author

Okay, that works for me.

ydahhrk added a commit that referenced this issue Feb 18, 2021
Looking for #352 by code analysis, I was hampered by the cluttered
Netlink API. Managing translator instances and Netlink responses
separately lead to overcoding for no practical benefit, and managing
error messages in yet another separate module was just confusing for no
reason. (And dangerous, since it was storing the errors in a global
variable. This didn't cause any errors that I'm aware of, though.)

This centralizes all of that into a request handling state structure,
jnl_state, which lives in the heap, and which mirrors the translation
state structure. (xlation, which would benefit from a rename now.) This
leads to a better substance-to-boilerplate ratio in the Netlink
handlers.

Unfortunately, this is just developer vanity. While I certainly prefer
the new API, I didn't find #352 in the end, or any other errors for that
matter.
@ydahhrk ydahhrk added Status: Stuck Development paused due to unavailable external input and removed Status: Active Development is underway labels Feb 18, 2021
@ydahhrk
Copy link
Member

ydahhrk commented Feb 24, 2021

4.1.5 released; removing from 4.1.5 milestone.

Still no output in dmesg?

@ydahhrk ydahhrk removed this from the 4.1.5 milestone Feb 24, 2021
@sysvinit
Copy link
Contributor Author

Still nothing, unfortunately. My test machines were moved to kernel 4.9 a few weeks after I opened this issue, in order to work around an unrelated IPv6 forwarding bug which was causing problems (I did briefly try 5.9 instead of moving backwards, but session state replication didn't immediately work and I didn't have time to work out why).

I think this issue should probably be closed, as I haven't been able to reproduce this since my original report, and it can be reopened in the future if the bug reappears.

@ydahhrk
Copy link
Member

ydahhrk commented Feb 24, 2021

You're free to close it if you want, but I'd personally rather keep it in the radar for at least a year.

(It has the "Status: Stuck" tag, so it's easy to filter out of the TODO list.)

@sysvinit
Copy link
Contributor Author

Okay, I'll leave it open for now; if i have time to look at the 5.9 issues again, then I'll open a separate issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Status: Stuck Development paused due to unavailable external input
Projects
None yet
Development

No branches or pull requests

2 participants