Re: SMACK LSM checks wrong object label during ingress network traffic
From: Casey Schaufler <casey@schaufler-ca.com>
Date: 2022-08-31 14:38:49
On 8/31/2022 5:13 AM, Lontke, Michael wrote:
On Tue, 2022-08-30 at 07:06 -0700, Casey Schaufler wrote:quoted
On 8/30/2022 2:30 AM, Lontke, Michael wrote:quoted
On Fri, 2022-08-26 at 09:15 -0700, Casey Schaufler wrote:quoted
On 8/26/2022 1:40 AM, Lontke, Michael wrote:quoted
On Thu, 2022-08-25 at 08:59 -0700, Casey Schaufler wrote:quoted
On 8/25/2022 2:25 AM, Lontke, Michael wrote:quoted
Hello Mr. Schaufler, we observed the following behavior of the SMACK LSM kernel feature. PROBLEM: SMACK LSM is checking the wrong label when receiving network packets during high system load. Full Descrpition of the Problem: During a test scenario involving high system load (cpu, memory and io) in combination with ingress tcp network traffic, SMACK is checking wrong object labels leading to denied access for valid scenarios. In below test scenario the label 'stresstest' is only used for the application 'stress' but appears in SMACK audit logs as object together with netlabels. This issue initially appeared on hardware with kernel version 4.14.237 but was also being reproduced with qemu for kernel version 4.14.290 and latest 6.0-rc2. The used rootfs was generated via buildroot version 2022.08-rc1. KEYWORDS: smack, networking KERNEL INFORMATION: Linux stable kernel KERNEL VERSION: 4.14.237, 4.14.290, 6.0-rc2 KERNEL CONFIG: smack related kernel configuration CONFIG_NETLABEL=y CONFIG_SECURITY_NETWORK=y CONFIG_SECURITY_SMACK=y CONFIG_DEFAULT_SECURITY_SMACK=y CONFIG_DEFAULT_SECURITY="smack"What is the value for CONFIG_SECURITY_SMACK_NETFILTER ?# CONFIG_NETWORK_SECMARK is not set therefore CONFIG_SECURITY_SMACK_NETFILTER is not set as well.quoted
The implementation for IPv6 is much more robust for the netfilter enabled path.You are stating that CONFIG_NETWORK_SECMARK=y CONFIG_SECURITY_SMACK_NETFILTER=y and therefore using SMACK_IPV6_SECMARK_LABELING instead of SMACK_IPV6_PORT_LABELING path in kernel code is more reliable?Yes. The netfilter version is used in all known commercial deployments of Smack, and hence has gotten more attention. The port labeling code is a "clever hack". I hope to replace it with CALIPSO now that CALIPSO is supported by newlabel.Today I tested with your suggested configuration (secmark + netfilter). Executing the same test case I run into almost the same issue: [ 288.200206] audit: type=1400 audit(1661844069.376:742): lsm=SMACK fn=smack_socket_sock_rcv_skb action=denied subject="net_host" object="stresstest" requested=w pid=185 comm="stress" saddr=<host- ipv6- addr> src=49812 daddr=<qemu-ipv6-addr> dest=42511 netif=ens3 Instead of defining the netlabel via /sys/fs/smackfs/ip6hosts I added a nehosttfilter rule to mark the package with secmark:The netfilter rule is unnecessary if you set the host label. Smack will set the secmark based on the host label. The approach you've use should work just fine. Seeing that the problem occurs in both cases will help narrow down the possibilities. With the configuration and cases you provided I am able to reproduce the problem reliably. I am working on tracking down what I think is a lack of locking issue. Any more information you can provide could be most helpful.I added some debug output and stack dumps: [ 48.056297] SMACK DEBUG: smack_sk_alloc_security:2321 - sk=ffff8feb1cc3a200 - smk_in=stresstest smk_out=stresstest skp=ffff8feb1cc51000 [ 48.056792] CPU: 0 PID: 1544 Comm: stress Not tainted 4.14.0+ #9 [ 48.057085] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014 [ 48.057463] Call Trace: [ 48.057600] <IRQ> [ 48.057741] dump_stack+0x4d/0x71 [ 48.057936] smack_sk_alloc_security+0x109/0x110 [ 48.058165] security_sk_alloc+0x3e/0x60 [ 48.058364] sk_prot_alloc+0x53/0x130 [ 48.058553] sk_clone_lock+0x19/0x3d0 [ 48.058737] inet_csk_clone_lock+0x11/0xe0 [ 48.058953] tcp_create_openreq_child+0x1e/0x420 [ 48.059172] tcp_v6_syn_recv_sock+0x91/0x710 [ 48.059380] tcp_check_req+0x3b2/0x510 [ 48.059558] ? tcp_v6_inbound_md5_hash+0x54/0x1c0 [ 48.059782] tcp_v6_rcv+0x4c1/0x950 [ 48.059954] ? ip6table_mangle_hook+0x41/0x120 [ 48.060172] ip6_input_finish+0xb9/0x420 [ 48.060374] ip6_input+0x2b/0x90 [ 48.060535] ? ip6_rcv_finish+0xa0/0xa0 [ 48.060718] ip6_rcv_finish+0x41/0xa0 [ 48.060892] ipv6_rcv+0x31d/0x520 [ 48.061053] ? ip6_make_skb+0x1b0/0x1b0 [ 48.061240] __netif_receive_skb_core+0x33a/0xa90 [ 48.061490] ? ipv6_gro_receive+0x1b5/0x350 [ 48.061687] __netif_receive_skb+0x13/0x60 [ 48.061895] ? __netif_receive_skb+0x13/0x60 [ 48.062089] netif_receive_skb_internal+0x23/0xb0 [ 48.062305] napi_gro_receive+0xbd/0xe0 [ 48.062485] e1000_clean_rx_irq+0x1c9/0x4e0 [ 48.062686] e1000_clean+0x260/0x860 [ 48.062860] net_rx_action+0x11b/0x350 [ 48.063031] ? e1000_intr+0x78/0xf0 [ 48.063202] __do_softirq+0xcf/0x2a8 [ 48.063376] irq_exit+0xab/0xb0 [ 48.063528] do_IRQ+0x7b/0xc0 [ 48.063679] common_interrupt+0x90/0x90 [ 48.063854] </IRQ> [ 48.063977] RIP: 0033:0x56307cef0baf [ 48.064135] RSP: 002b:00007ffcd9734540 EFLAGS: 00000206 ORIG_RAX: ffffffffffffffc4 [ 48.064466] RAX: 0000000037581fac RBX: 0000000000003a98 RCX: 0000000037581fac [ 48.064765] RDX: 000000003b388e7d RSI: 00007ffcd973451c RDI: 00007f2023c62680 [ 48.065033] RBP: 0000000000000003 R08: 0000000000000000 R09: 00007f2023c62024 [ 48.065326] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 [ 48.065625] R13: 0000000000000003 R14: 0000000000000001 R15: 000056307cef2004 [ 48.066462] SMACK DEBUG: smack_socket_sock_rcv_skb:4057 - sk=ffff8feb1cc3a200 smk_in=stresstest rc=-13 [ 48.066852] CPU: 0 PID: 1544 Comm: stress Not tainted 4.14.0+ #9 [ 48.067142] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014 [ 48.067507] Call Trace: [ 48.067620] <IRQ> [ 48.067738] dump_stack+0x4d/0x71 [ 48.067898] smack_socket_sock_rcv_skb+0x269/0x270 [ 48.068109] ? default_wake_function+0xd/0x10 [ 48.068301] ? pollwake+0x61/0x70 [ 48.068464] ? wake_up_q+0x70/0x70 [ 48.068621] ? __wake_up_common+0x68/0x120 [ 48.068806] security_sock_rcv_skb+0x36/0x50 [ 48.068987] sk_filter_trim_cap+0x2c/0x150 [ 48.069156] ? tcp_v6_inbound_md5_hash+0x54/0x1c0 [ 48.069356] tcp_filter+0x26/0x40 [ 48.069510] tcp_v6_rcv+0x805/0x950 [ 48.069663] ? ip6table_mangle_hook+0x41/0x120 [ 48.069856] ip6_input_finish+0xb9/0x420 [ 48.070029] ip6_input+0x2b/0x90 [ 48.070174] ? ip6_rcv_finish+0xa0/0xa0 [ 48.070337] ip6_rcv_finish+0x9a/0xa0 [ 48.070498] ipv6_rcv+0x31d/0x520 [ 48.070651] ? ip6_make_skb+0x1b0/0x1b0 [ 48.070832] __netif_receive_skb_core+0x33a/0xa90 [ 48.071028] ? ipv6_gro_receive+0x1b5/0x350 [ 48.071214] __netif_receive_skb+0x13/0x60 [ 48.071396] ? __netif_receive_skb+0x13/0x60 [ 48.071595] netif_receive_skb_internal+0x23/0xb0 [ 48.071808] napi_gro_receive+0xbd/0xe0 [ 48.072001] e1000_clean_rx_irq+0x1c9/0x4e0 [ 48.072197] e1000_clean+0x260/0x860 [ 48.072376] net_rx_action+0x11b/0x350 [ 48.072542] ? e1000_intr+0x78/0xf0 [ 48.072709] __do_softirq+0xcf/0x2a8 [ 48.072881] irq_exit+0xab/0xb0 [ 48.073041] do_IRQ+0x7b/0xc0 [ 48.073232] common_interrupt+0x90/0x90 [ 48.073433] </IRQ> [ 48.073544] RIP: 0033:0x56307cef0baf [ 48.073697] RSP: 002b:00007ffcd9734540 EFLAGS: 00000206 ORIG_RAX: ffffffffffffffc4 [ 48.074007] RAX: 0000000037581fac RBX: 0000000000003a98 RCX: 0000000037581fac [ 48.074297] RDX: 000000003b388e7d RSI: 00007ffcd973451c RDI: 00007f2023c62680 [ 48.074580] RBP: 0000000000000003 R08: 0000000000000000 R09: 00007f2023c62024 [ 48.074875] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 [ 48.075157] R13: 0000000000000003 R14: 0000000000000001 R15: 000056307cef2004 [ 48.075903] SMACK DEBUG: smack_sock_graft:4185 - sk=ffff8feb1cc3a200 - before smk_in=stresstest smk_out=stresstest [ 48.076643] CPU: 0 PID: 1634 Comm: socat Not tainted 4.14.0+ #9 [ 48.076892] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014 [ 48.077329] Call Trace: [ 48.077485] dump_stack+0x4d/0x71 [ 48.077654] smack_sock_graft+0xe9/0xf0 [ 48.077834] security_sock_graft+0x28/0x40 [ 48.078024] inet_accept+0xa8/0x140 [ 48.078198] SYSC_accept4+0xe8/0x1e0 [ 48.078372] ? __audit_syscall_entry+0xba/0x100 [ 48.078580] ? syscall_trace_enter+0x1c3/0x2b0 [ 48.078781] SyS_accept+0xb/0x10 [ 48.078933] do_syscall_64+0x4e/0x100 [ 48.079105] entry_SYSCALL64_slow_path+0x25/0x25 [ 48.079314] RIP: 0033:0x7f8d116b85ea [ 48.079465] RSP: 002b:00007fff87c2ef28 EFLAGS: 00000246 ORIG_RAX: 000000000000002b [ 48.079778] RAX: ffffffffffffffda RBX: 00007fff87c2f160 RCX: 00007f8d116b85ea [ 48.080063] RDX: 00007fff87c2f134 RSI: 00007fff87c2f160 RDI: 0000000000000005 [ 48.080363] RBP: 00007fff87c2f134 R08: 00007fff87c2f134 R09: 0000000000000000 [ 48.080648] R10: 0000000000000040 R11: 0000000000000246 R12: 0000000000000005 [ 48.080903] R13: 00000000ffffffff R14: 00007fff87c2f160 R15: 00007fff87c2f1e0 [ 48.081236] SMACK DEBUG: smack_sock_graft:4193 - sk=ffff8feb1cc3a200 - after smk_in=tcp_test smk_out=tcp_test It looks like the socket is already initialized with the wrong security context. It is later corrected by smack_sock_graft, but tool late since it is called during accept. We looked into smack_sk_alloc_security and thought this line could be the issue: struct smack_known *skp = smk_of_current(); Looking at how selinux solved it, we saw it initializes with a blank security context and later copys the correct context within security_sk_clone LSM hook. At least with this patch we don't see our issue anymore:
I will run the patch through my tests, but it looks reasonable. Assuming it passes, and I expect it will, I'll add it to the Smack next branch. May I add your "Signed-off-by:" ? Also, let me know if anyone wants to add a "Reported-by:". Thank you for tracking this down and contributing to Smack.
quoted hunk ↗ jump to hunk
From: Lontke Michael <redacted> Date: Wed, 31 Aug 2022 14:03:26 +0200 Subject: [PATCH] SMACK: Add sk_clone_security LSM hook Using smk_of_current() during sk_alloc_security hook leads in rare cases to a faulty initialization of the security context of the created socket. By adding the LSM hook sk_clone_security to SMACK this initialization fault is corrected by copying the security context of the old socket pointer to the newly cloned one. --- security/smack/smack_lsm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 286171a16ed2..8eb47396376f 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c@@ -2348,6 +2348,21 @@ static void smack_sk_free_security(struct sock*sk) kfree(sk->sk_security); } +/** + * smack_sk_clone_security - Copy security context + * @sk: the old socket + * @newsk: the new socket + * + * Copy the security context of the old socket pointer to the cloned + */ +static void smack_sk_clone_security(const struct sock *sk, struct sock *newsk) +{ + struct socket_smack *ssp_old = sk->sk_security; + struct socket_smack *ssp_new = newsk->sk_security; + + *ssp_new = *ssp_old; +} + /** * smack_ipv4host_label - check host based restrictions * @sip: the object end@@ -4710,6 +4725,7 @@ static struct security_hook_list smack_hooks[]__lsm_ro_after_init = { LSM_HOOK_INIT(socket_getpeersec_dgram, smack_socket_getpeersec_dgram), LSM_HOOK_INIT(sk_alloc_security, smack_sk_alloc_security), LSM_HOOK_INIT(sk_free_security, smack_sk_free_security), + LSM_HOOK_INIT(sk_clone_security, smack_sk_clone_security), LSM_HOOK_INIT(sock_graft, smack_sock_graft), LSM_HOOK_INIT(inet_conn_request, smack_inet_conn_request), LSM_HOOK_INIT(inet_csk_clone, smack_inet_csk_clone),