| From cc274ae7763d9700a56659f3228641d7069e7a3f Mon Sep 17 00:00:00 2001 |
| From: Scott Mayhew <smayhew@redhat.com> |
| Date: Wed, 15 Dec 2021 16:28:40 -0500 |
| Subject: selinux: fix sleeping function called from invalid context |
| |
| From: Scott Mayhew <smayhew@redhat.com> |
| |
| commit cc274ae7763d9700a56659f3228641d7069e7a3f upstream. |
| |
| selinux_sb_mnt_opts_compat() is called via sget_fc() under the sb_lock |
| spinlock, so it can't use GFP_KERNEL allocations: |
| |
| [ 868.565200] BUG: sleeping function called from invalid context at |
| include/linux/sched/mm.h:230 |
| [ 868.568246] in_atomic(): 1, irqs_disabled(): 0, |
| non_block: 0, pid: 4914, name: mount.nfs |
| [ 868.569626] preempt_count: 1, expected: 0 |
| [ 868.570215] RCU nest depth: 0, expected: 0 |
| [ 868.570809] Preemption disabled at: |
| [ 868.570810] [<0000000000000000>] 0x0 |
| [ 868.571848] CPU: 1 PID: 4914 Comm: mount.nfs Kdump: loaded |
| Tainted: G W 5.16.0-rc5.2585cf9dfa #1 |
| [ 868.573273] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), |
| BIOS 1.14.0-4.fc34 04/01/2014 |
| [ 868.574478] Call Trace: |
| [ 868.574844] <TASK> |
| [ 868.575156] dump_stack_lvl+0x34/0x44 |
| [ 868.575692] __might_resched.cold+0xd6/0x10f |
| [ 868.576308] slab_pre_alloc_hook.constprop.0+0x89/0xf0 |
| [ 868.577046] __kmalloc_track_caller+0x72/0x420 |
| [ 868.577684] ? security_context_to_sid_core+0x48/0x2b0 |
| [ 868.578569] kmemdup_nul+0x22/0x50 |
| [ 868.579108] security_context_to_sid_core+0x48/0x2b0 |
| [ 868.579854] ? _nfs4_proc_pathconf+0xff/0x110 [nfsv4] |
| [ 868.580742] ? nfs_reconfigure+0x80/0x80 [nfs] |
| [ 868.581355] security_context_str_to_sid+0x36/0x40 |
| [ 868.581960] selinux_sb_mnt_opts_compat+0xb5/0x1e0 |
| [ 868.582550] ? nfs_reconfigure+0x80/0x80 [nfs] |
| [ 868.583098] security_sb_mnt_opts_compat+0x2a/0x40 |
| [ 868.583676] nfs_compare_super+0x113/0x220 [nfs] |
| [ 868.584249] ? nfs_try_mount_request+0x210/0x210 [nfs] |
| [ 868.584879] sget_fc+0xb5/0x2f0 |
| [ 868.585267] nfs_get_tree_common+0x91/0x4a0 [nfs] |
| [ 868.585834] vfs_get_tree+0x25/0xb0 |
| [ 868.586241] fc_mount+0xe/0x30 |
| [ 868.586605] do_nfs4_mount+0x130/0x380 [nfsv4] |
| [ 868.587160] nfs4_try_get_tree+0x47/0xb0 [nfsv4] |
| [ 868.587724] vfs_get_tree+0x25/0xb0 |
| [ 868.588193] do_new_mount+0x176/0x310 |
| [ 868.588782] __x64_sys_mount+0x103/0x140 |
| [ 868.589388] do_syscall_64+0x3b/0x90 |
| [ 868.589935] entry_SYSCALL_64_after_hwframe+0x44/0xae |
| [ 868.590699] RIP: 0033:0x7f2b371c6c4e |
| [ 868.591239] Code: 48 8b 0d dd 71 0e 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e |
| 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 49 89 ca b8 a5 00 |
| 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d aa 71 |
| 0e 00 f7 d8 64 89 01 48 |
| [ 868.593810] RSP: 002b:00007ffc83775d88 EFLAGS: 00000246 |
| ORIG_RAX: 00000000000000a5 |
| [ 868.594691] RAX: ffffffffffffffda RBX: 00007ffc83775f10 RCX: 00007f2b371c6c4e |
| [ 868.595504] RDX: 0000555d517247a0 RSI: 0000555d51724700 RDI: 0000555d51724540 |
| [ 868.596317] RBP: 00007ffc83775f10 R08: 0000555d51726890 R09: 0000555d51726890 |
| [ 868.597162] R10: 0000000000000000 R11: 0000000000000246 R12: 0000555d51726890 |
| [ 868.598005] R13: 0000000000000003 R14: 0000555d517246e0 R15: 0000555d511ac925 |
| [ 868.598826] </TASK> |
| |
| Cc: stable@vger.kernel.org |
| Fixes: 69c4a42d72eb ("lsm,selinux: add new hook to compare new mount to an existing mount") |
| Signed-off-by: Scott Mayhew <smayhew@redhat.com> |
| [PM: cleanup/line-wrap the backtrace] |
| Signed-off-by: Paul Moore <paul@paul-moore.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| security/selinux/hooks.c | 33 +++++++++++++++++++-------------- |
| 1 file changed, 19 insertions(+), 14 deletions(-) |
| |
| --- a/security/selinux/hooks.c |
| +++ b/security/selinux/hooks.c |
| @@ -611,10 +611,11 @@ static int bad_option(struct superblock_ |
| return 0; |
| } |
| |
| -static int parse_sid(struct super_block *sb, const char *s, u32 *sid) |
| +static int parse_sid(struct super_block *sb, const char *s, u32 *sid, |
| + gfp_t gfp) |
| { |
| int rc = security_context_str_to_sid(&selinux_state, s, |
| - sid, GFP_KERNEL); |
| + sid, gfp); |
| if (rc) |
| pr_warn("SELinux: security_context_str_to_sid" |
| "(%s) failed for (dev %s, type %s) errno=%d\n", |
| @@ -685,7 +686,8 @@ static int selinux_set_mnt_opts(struct s |
| */ |
| if (opts) { |
| if (opts->fscontext) { |
| - rc = parse_sid(sb, opts->fscontext, &fscontext_sid); |
| + rc = parse_sid(sb, opts->fscontext, &fscontext_sid, |
| + GFP_KERNEL); |
| if (rc) |
| goto out; |
| if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, |
| @@ -694,7 +696,8 @@ static int selinux_set_mnt_opts(struct s |
| sbsec->flags |= FSCONTEXT_MNT; |
| } |
| if (opts->context) { |
| - rc = parse_sid(sb, opts->context, &context_sid); |
| + rc = parse_sid(sb, opts->context, &context_sid, |
| + GFP_KERNEL); |
| if (rc) |
| goto out; |
| if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, |
| @@ -703,7 +706,8 @@ static int selinux_set_mnt_opts(struct s |
| sbsec->flags |= CONTEXT_MNT; |
| } |
| if (opts->rootcontext) { |
| - rc = parse_sid(sb, opts->rootcontext, &rootcontext_sid); |
| + rc = parse_sid(sb, opts->rootcontext, &rootcontext_sid, |
| + GFP_KERNEL); |
| if (rc) |
| goto out; |
| if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, |
| @@ -712,7 +716,8 @@ static int selinux_set_mnt_opts(struct s |
| sbsec->flags |= ROOTCONTEXT_MNT; |
| } |
| if (opts->defcontext) { |
| - rc = parse_sid(sb, opts->defcontext, &defcontext_sid); |
| + rc = parse_sid(sb, opts->defcontext, &defcontext_sid, |
| + GFP_KERNEL); |
| if (rc) |
| goto out; |
| if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, |
| @@ -2701,14 +2706,14 @@ static int selinux_sb_mnt_opts_compat(st |
| return (sbsec->flags & SE_MNTMASK) ? 1 : 0; |
| |
| if (opts->fscontext) { |
| - rc = parse_sid(sb, opts->fscontext, &sid); |
| + rc = parse_sid(sb, opts->fscontext, &sid, GFP_NOWAIT); |
| if (rc) |
| return 1; |
| if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid)) |
| return 1; |
| } |
| if (opts->context) { |
| - rc = parse_sid(sb, opts->context, &sid); |
| + rc = parse_sid(sb, opts->context, &sid, GFP_NOWAIT); |
| if (rc) |
| return 1; |
| if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid)) |
| @@ -2718,14 +2723,14 @@ static int selinux_sb_mnt_opts_compat(st |
| struct inode_security_struct *root_isec; |
| |
| root_isec = backing_inode_security(sb->s_root); |
| - rc = parse_sid(sb, opts->rootcontext, &sid); |
| + rc = parse_sid(sb, opts->rootcontext, &sid, GFP_NOWAIT); |
| if (rc) |
| return 1; |
| if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid)) |
| return 1; |
| } |
| if (opts->defcontext) { |
| - rc = parse_sid(sb, opts->defcontext, &sid); |
| + rc = parse_sid(sb, opts->defcontext, &sid, GFP_NOWAIT); |
| if (rc) |
| return 1; |
| if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid)) |
| @@ -2748,14 +2753,14 @@ static int selinux_sb_remount(struct sup |
| return 0; |
| |
| if (opts->fscontext) { |
| - rc = parse_sid(sb, opts->fscontext, &sid); |
| + rc = parse_sid(sb, opts->fscontext, &sid, GFP_KERNEL); |
| if (rc) |
| return rc; |
| if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid)) |
| goto out_bad_option; |
| } |
| if (opts->context) { |
| - rc = parse_sid(sb, opts->context, &sid); |
| + rc = parse_sid(sb, opts->context, &sid, GFP_KERNEL); |
| if (rc) |
| return rc; |
| if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid)) |
| @@ -2764,14 +2769,14 @@ static int selinux_sb_remount(struct sup |
| if (opts->rootcontext) { |
| struct inode_security_struct *root_isec; |
| root_isec = backing_inode_security(sb->s_root); |
| - rc = parse_sid(sb, opts->rootcontext, &sid); |
| + rc = parse_sid(sb, opts->rootcontext, &sid, GFP_KERNEL); |
| if (rc) |
| return rc; |
| if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid)) |
| goto out_bad_option; |
| } |
| if (opts->defcontext) { |
| - rc = parse_sid(sb, opts->defcontext, &sid); |
| + rc = parse_sid(sb, opts->defcontext, &sid, GFP_KERNEL); |
| if (rc) |
| return rc; |
| if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid)) |