The Ubuntu kernel carries an out of tree patchet, known as "LSM: Module stacking for AppArmor" upstream, to enable stackable LSMs for containers. The revision the Ubuntu kernel carries is an older one, from 2020, and has some slight divergences from the latest revision in development.
One such divergence, is support for Landlock as a stackable LSM. When the stackable LSM patchset was applied, Landlock was still in development and not mainlined yet, and wasn't present in the earlier revision of the "LSM: Module stacking for AppArmor" patchset. Support for this was added by us.
There was a minor omission made during enabling support for Landlock. The LSM slot type was marked as LSMBLOB_NEEDED, when it should have been LSMBLOB_NOT_NEEDED.
Landlock itself does not provide any of the hooks that use a struct lsmblob, such as secid_to_secctx, secctx_to_secid, inode_getsecid, cred_getsecid, kernel_act_as task_getsecid_subj task_getsecid_obj and ipc_getsecid.
When we set .slot = LSMBLOB_NEEDED, this indicates that we need an entry in struct lsmblob, and we need to increment LSMBLOB_ENTRIES by one to fit the entry into the secid array:
Currently, we don't increment LSMBLOB_ENTRIES by one to make an entry for Landlock, so for the Ubuntu kernel, we can fit a maximum of two entries, one for Apparmor and one for bpf.
If you try and configure three LSMs like so and reboot:
LSM: Security Framework initializing
landlock: Up and running.
LSM support for eBPF active
Kernel panic - not syncing: security_add_hooks Too many LSMs registered.
CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.15.0-46-generic #49-Ubuntu
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.15.0-1 04/01/2014
Call Trace:
<TASK>
show_stack+0x52/0x5c
dump_stack_lvl+0x4a/0x63
dump_stack+0x10/0x16
panic+0x149/0x321
security_add_hooks+0x45/0x13a
apparmor_init+0x189/0x1ef
initialize_lsm+0x54/0x74
ordered_lsm_init+0x379/0x392
security_init+0x40/0x49
start_kernel+0x466/0x4dc
x86_64_start_reservations+0x24/0x2a
x86_64_start_kernel+0xe4/0xef
secondary_startup_64_no_verify+0xc2/0xcb
</TASK>
---[ end Kernel panic - not syncing: security_add_hooks Too many LSMs registered. ]---
There is a check added in security_add_hooks() that makes sure that you cannot configure too many LSMs:
if (lsmid->slot == LSMBLOB_NEEDED) {
if (lsm_slot >= LSMBLOB_ENTRIES)
panic("%s Too many LSMs registered.\n", __func__);
lsmid->slot = lsm_slot++;
init_debug("%s assigned lsmblob slot %d\n", lsmid->lsm,
lsmid->slot);
}
A workaround is to enable no more than 2 LSMs until this is fixed.
[Fix]
If you read the following mailing list thread on linux-security-modules from May 2021:
It is explained that Landlock does not provide any of the hooks that use a struct lsmblob, such as secid_to_secctx, secctx_to_secid, inode_getsecid, cred_getsecid, kernel_act_as task_getsecid_subj task_getsecid_obj and ipc_getsecid.
The fix is to change Landlock from LSMBLOB_NEEDED to LSMBLOB_NOT_NEEDED.
Due to the "LSM: Module stacking for AppArmor" patchset being 25 patches long, it was impractical to revert just the below patch and reapply with the fix, due to a large amount of conflicts:
Instead of a panic occurring, the kernel should display all LSMs initialising, and continue to boot.
[ 0.288224] LSM: Security Framework initializing
[ 0.289457] landlock: Up and running.
[ 0.290290] LSM support for eBPF active
[ 0.291189] AppArmor: AppArmor initialized
[Where problems could occur]
The risk of regression in changing Landlock from LSMBLOB_NEEDED to LSMBLOB_NOT_NEEDED is low, due to Landlock not needing a slot in the secid array in struct lsmblob in the first place.
The refactor is minor and unlikely to introduce any issues with Landlock or its security promises.
I feel that simply fixing this small bug is less regression risk than reverting the entire 25 patch patchset and applying the latest V37 upstream patchset, which has undergone significant changes from mid 2020. I think its best we consume the newer patchset once it makes its way into mainline in a future kernel instead.
If a regression were to occur, users could configure 2 LSMs instead of all 3, or not enable Landlock.
BugLink: https:/ /bugs.launchpad .net/bugs/
[Impact]
The Ubuntu kernel carries an out of tree patchet, known as "LSM: Module stacking for AppArmor" upstream, to enable stackable LSMs for containers. The revision the Ubuntu kernel carries is an older one, from 2020, and has some slight divergences from the latest revision in development.
One such divergence, is support for Landlock as a stackable LSM. When the stackable LSM patchset was applied, Landlock was still in development and not mainlined yet, and wasn't present in the earlier revision of the "LSM: Module stacking for AppArmor" patchset. Support for this was added by us.
There was a minor omission made during enabling support for Landlock. The LSM slot type was marked as LSMBLOB_NEEDED, when it should have been LSMBLOB_NOT_NEEDED.
Landlock itself does not provide any of the hooks that use a struct lsmblob, such as secid_to_secctx, secctx_to_secid, inode_getsecid, cred_getsecid, kernel_act_as task_getsecid_subj task_getsecid_obj and ipc_getsecid.
When we set .slot = LSMBLOB_NEEDED, this indicates that we need an entry in struct lsmblob, and we need to increment LSMBLOB_ENTRIES by one to fit the entry into the secid array:
#define LSMBLOB_ENTRIES ( \
(IS_ENABLED( CONFIG_ SECURITY_ SELINUX) ? 1 : 0) + \
(IS_ENABLED( CONFIG_ SECURITY_ SMACK) ? 1 : 0) + \
(IS_ENABLED( CONFIG_ SECURITY_ APPARMOR) ? 1 : 0) + \
(IS_ENABLED( CONFIG_ BPF_LSM) ? 1 : 0))
struct lsmblob { ENTRIES] ;
u32 secid[LSMBLOB_
};
Currently, we don't increment LSMBLOB_ENTRIES by one to make an entry for Landlock, so for the Ubuntu kernel, we can fit a maximum of two entries, one for Apparmor and one for bpf.
If you try and configure three LSMs like so and reboot:
GRUB_CMDLINE_ LINUX_DEFAULT= "lsm=landlock, bpf,apparmor"
You will receive the following panic:
LSM: Security Framework initializing 0x52/0x5c lvl+0x4a/ 0x63 0x10/0x16 add_hooks+ 0x45/0x13a init+0x189/ 0x1ef lsm+0x54/ 0x74 lsm_init+ 0x379/0x392 init+0x40/ 0x49 kernel+ 0x466/0x4dc start_reservati ons+0x24/ 0x2a start_kernel+ 0xe4/0xef startup_ 64_no_verify+ 0xc2/0xcb
landlock: Up and running.
LSM support for eBPF active
Kernel panic - not syncing: security_add_hooks Too many LSMs registered.
CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.15.0-46-generic #49-Ubuntu
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.15.0-1 04/01/2014
Call Trace:
<TASK>
show_stack+
dump_stack_
dump_stack+
panic+0x149/0x321
security_
apparmor_
initialize_
ordered_
security_
start_
x86_64_
x86_64_
secondary_
</TASK>
---[ end Kernel panic - not syncing: security_add_hooks Too many LSMs registered. ]---
There is a check added in security_ add_hooks( ) that makes sure that you cannot configure too many LSMs:
if (lsmid->slot == LSMBLOB_NEEDED) {
if (lsm_slot >= LSMBLOB_ENTRIES)
panic("%s Too many LSMs registered.\n", __func__);
lsmid->slot = lsm_slot++;
init_debug("%s assigned lsmblob slot %d\n", lsmid->lsm,
lsmid->slot);
}
A workaround is to enable no more than 2 LSMs until this is fixed.
[Fix]
If you read the following mailing list thread on linux-security- modules from May 2021:
https:/ /lore.kernel. org/selinux/ 202105141224. 942DE93@ keescook/ T/
It is explained that Landlock does not provide any of the hooks that use a struct lsmblob, such as secid_to_secctx, secctx_to_secid, inode_getsecid, cred_getsecid, kernel_act_as task_getsecid_subj task_getsecid_obj and ipc_getsecid.
I verified this with:
ubuntu-jammy$ grep -Rin "secid_to_secctx" security/landlock/ subj" security/landlock/
ubuntu-jammy$ grep -Rin "secctx_to_secid" security/landlock/
ubuntu-jammy$ grep -Rin "inode_getsecid" security/landlock/
ubuntu-jammy$ grep -Rin "cred_getsecid" security/landlock/
ubuntu-jammy$ grep -Rin "kernel_act_as" security/landlock/
ubuntu-jammy$ grep -Rin "task_getsecid_
ubuntu-jammy$ grep -Rin "task_getsecid_obj" security/landlock/
ubuntu-jammy$ grep -Rin "ipc_getsecid" security/landlock/
The fix is to change Landlock from LSMBLOB_NEEDED to LSMBLOB_NOT_NEEDED.
Due to the "LSM: Module stacking for AppArmor" patchset being 25 patches long, it was impractical to revert just the below patch and reapply with the fix, due to a large amount of conflicts:
commit f17b27a2790e721 98d2aaf45242453 e5a9043049 /git.launchpad. net/~ubuntu- kernel/ ubuntu/ +source/ linux/+ git/jammy/ commit/ ?id=f17b27a2790 e72198d2aaf4524 2453e5a9043049
Author: Casey Schaufler <email address hidden>
Date: Mon Aug 17 16:02:56 2020 -0700
Subject: UBUNTU: SAUCE: LSM: Create and manage the lsmblob data structure.
Link: https:/
So instead, I wrote up a fix that just changes the Landlock LSM slots to follow the latest upstream development, from V37 of the patchset:
https://<email address hidden>/
I refactored the landlock_lsmid struct to only be in one place, and to be marked as extern from security/ landlock/ setup.h.
[Testcase]
Launch a Jammy or Kinetic VM.
1. Edit /etc/default/grub and append the following to GRUB_CMDLINE_ LINUX_DEFAULT: bpf,apparmor"
"lsm=landlock,
2. sudo update-grub
3. reboot
The system will panic on boot.
If you install the test kernel from the following ppa:
https:/ /launchpad. net/~mruffell/ +archive/ ubuntu/ sf343286- test
Instead of a panic occurring, the kernel should display all LSMs initialising, and continue to boot.
[ 0.288224] LSM: Security Framework initializing
[ 0.289457] landlock: Up and running.
[ 0.290290] LSM support for eBPF active
[ 0.291189] AppArmor: AppArmor initialized
[Where problems could occur]
The risk of regression in changing Landlock from LSMBLOB_NEEDED to LSMBLOB_NOT_NEEDED is low, due to Landlock not needing a slot in the secid array in struct lsmblob in the first place.
The refactor is minor and unlikely to introduce any issues with Landlock or its security promises.
I feel that simply fixing this small bug is less regression risk than reverting the entire 25 patch patchset and applying the latest V37 upstream patchset, which has undergone significant changes from mid 2020. I think its best we consume the newer patchset once it makes its way into mainline in a future kernel instead.
If a regression were to occur, users could configure 2 LSMs instead of all 3, or not enable Landlock.