Linux 6.9 Merge Window

Linux v6.8 was released this past Sunday, with the Linux v6.9 merge window opening immediately afterwards. Below are the highlights of the LSM, SELinux, and audit pull requests which Linus has merged into his tree.

LSM

  • The Linux Integrity Subsystem, more commonly known as IMA, or IMA/EVM, has been integrated into the LSM framework. Prior to the start of the LSM stacking work it was important that IMA/EVM remain separate from the rest of the LSMs as it was the only way to enable IMA/EVM at the same time as a LSM, e.g. SELinux. However, now that the bulk of the LSM infrastructure supports multiple simultaneous LSMs, it is possible to integrate both IMA and EVM into the LSM framework as proper LSMs. This moves simplifies the IMA/EVM, LSM, and core Linux kernel code and helps us reduce the likelihood of future bugs. A special thanks to Roberto Sassu for helping turn a long standing wish of mine into reality.

  • Internal improvements relating to how we stack multiple LSMs for a subset of the LSM access control hooks. Many LSM hooks that return an integer value to indicate success or failure used the call_int_hook() macro which required callers to specify a default return value, despite their already being a default return value specified during LSM hook declaration. Unfortunately, there were several cases where these return values were mismatched which triggered buggy behavior in some configurations, specifically those that made use of BPF LSMs. The call_int_hook() macro has been updated to remove the need for the caller to specify a default return value, instead using the value specified when the LSM hook was declared.

  • A number of grammar corrections to the LSM hook documentation in the source code comments.

SELinux

  • No longer restrict extended attribute copy-up when SELinux is enabled but a policy has not yet been loaded. This helps systems that use overlayfs, or similar filesystems, preserve their SELinux labels during early boot when the SELinux policy has yet to be loaded.

  • Fix a problem where the error codes were not consistent across the selinux_socket_getpeersec_dgram() and selinux_socket_getpeersec_stream() functions. The error code inconsistency could lead to confusion among users and applications attempting to determine the SELinux network peer information across labeled networks.

  • Remove a redundant SELinux object class lookup/calculation at inode initialization time. The computing overhead associated with the unnecessary work was rather small, meaning any performance improvements should be minimal.

  • Continue the coding style fixes started in Linux v6.8, this time focusing on the “security/selinux/ss” directory.

Audit

  • Instead of using the kmem_cache_create() function to create the slab audit buffer cache, use the KMEM_CACHE() according to the guidance in the kernel’s header files.

  • Minor change to remove an unnecessary variable initialization during its declaration.

Linux 6.8 Released

Linux v6.8 was released on Sunday, March 10th. I already wrote up a post highlighting the LSM, SELinux, and audit changes that were submitted during the merge window, however there were additional changes that went in during the release candidate process which are described below.

LSM

  • Fix a potential integer overflow bug when sanity checking the size of an argument to the lsm_set_self_attr(2) syscall.

  • Fix a couple of problems relating to a mismatch between the expected default return value of a LSM hook and the actual default value. While the return value mismatches are not new, the recent popularity of BPF LSM modules combined with the unconventional nature of the BPF LSM framework has increased the likelihood of a failure.

SELinux

  • A minor fix to the lsm_get_self_attr(2) syscall SELinux code to ensure that an internal string buffer is always properly initialized before attempting to free the buffer.

In addition to my highlights, LWN.net provides a nice overall summary of the kernel changes made during the first and second weeks of the merge window.

Linux 6.8 Merge Window

Linux v6.7 was released this past Sunday, with the Linux v6.8 merge window opening immediately afterwards. Recently I’ve started writing up the highlights of the SELinux and audit pull requests sent to Linus, but starting with the Linux v6.8 merge window I’m also going to start including the Linux Security Module (LSM) layer highlights. I’m including the LSM in these summaries because with the start of Linux v6.8 the LSM layer itself is taking a step forward in terms of user visibility and I want users, administrators, developers, and distros to be aware of changes that could impact their systems.

With all that out of the way, here are the highlights of the LSM, SELinux, and audit pull requests which Linus has merged into his tree.

UPDATE: The week of March 11, 2024, the week Linux v6.8 was released, we became aware of an incompatibility issue with the new LSM syscalls on 32-bit systems and changed the size_t parameter types to u32 to avoid problems. The syscall signatures below have been updated to reflect this change.

LSM

  • Add three new syscalls and a new kernel API structure, a first for the LSM layer. The new kernel API structure, struct lsm_ctx, is used to communicate LSM contexts across the kernel/userspace boundary.
    struct lsm_ctx {
      u64 id;
      u64 flags;
      u64 len;
      u64 ctx_len;
      u64 ctx[];
    };
    

    The id field is set to the associated LSM’s ID value (the kernel headers define a number of LSM_ID_XXX pre-processor macros for LSM IDs), the flags field is a LSM specific bitmap field that is only interpreted by the associated LSM, the len field is the total length of the structure including the trailing ctx field and any padding, the ctx_len field is the length of ctx, and the ctx field contains the LSM context. If the LSM context is a string, it should be NUL terminated.

    The first syscall, lsm_list_modules(2), returns the number of LSMs enabled in the running kernel.

    int lsm_list_modules(u64 *ids, u32 size, u32 flags);
    

    The id parameter points to an array of LSM IDs, the size parameter is set to the maximum size of the id array in bytes when invoked and on return it is set to the size of the populated id array in bytes, the flags parameter is currently unused and must be set to zero. The syscall returns zero on success and negative error codes on failure; if -E2BIG is returned the id parameter is not large enough, see the size parameter for the minimum required size.

    The second syscall, lsm_get_self_attr(2), returns the current running task’s LSM attributes from all of the enabled LSMs.

    int lsm_get_self_attr(unsigned int attr, struct lsm_ctx *ctx, u32 size, u32 flags);
    

    The attr parameter is set to the LSM attribute being requested (the kernel headers define a number of LSM_ATTR_XXX pre-processor macros for LSM attributes), the ctx parameter points to an array of lsm_ctx structures, the size parameter is set to the maximum size of the ctx array in bytes when invoked and on return it is set to the size of the populated ctx array in bytes, the flags parameter can be set to zero or LSM_FLAG_SINGLE. If flags is set to LSM_FLAG_SINGLE then only a single LSM, as specified in the ctx[0]::id field, is queried for the attribute in attr. The syscall returns the number of LSM contexts in ctx, with zero indicating no contexts are available, and negative error codes on failure; if -E2BIG is returned the ctx parameter is not large enough, see the size parameter for the minimum required size.

    The third syscall, lsm_set_self_attr(2), sets a LSM attribute in the current running task.

    int lsm_set_self_attr(unsigned int attr, struct lsm_ctx *ctx, u32 size, u32 flags);
    

    The attr parameter is set to the LSM attribute being set (the kernel headers define a number of LSM_ATTR_XXX pre-processor macros for LSM attributes), the ctx parameter points to an lsm_ctx structure, the size parameter is set to the size of the ctx structure in bytes, the flags parameter is currently unused and must be set to zero. The syscall returns zero on success, negative error codes on failure.

  • Add a new security_file_ioctl_compat() LSM hook to properly handle 32-bit ioctls on 64-bit systems.

  • Add an explicit entry in the MAINTAINERS file for the Lockdown LSM. The Lockdown LSM does not currently have a dedicated maintainer, but I will continue to maintain it on an as-needed basis until an appropriate volunteer steps forward to serve as a dedicated maintainer.

  • While not strictly LSM related, the Linux v6.8 LSM pull request did also include a small fix to the CALIPSO code that resolves a memory leak which could occur when disabling IPv6 on the kernel command line and attempting to configure CALIPSO, an IPv6 labeling protocol.

SELinux

  • Drop Eric Paris as a SELinux maintainer. Eric is an important part of SELinux history and I’m thankful not only for his stint as maintainer, but his numerous contributions over the years. Unfortunately, Eric has moved on to other things and hasn’t contributed to the SELinux community in several years (his last SELinux kernel commit was in 2013) making it time to officially drop Eric as a maintainer.

  • Added Ondrej Mosnacek as an official SELinux kernel subsystem reviewer. Ondrej has a long history of providing quality SELinux kernel patches and I’m looking forward to his help as an official reviewer.

  • Add a new SELinux initial SID, “init”, to represent userspace processes started before the SELinux policy is loaded in early boot. Prior to this all processes were marked with the “kernel” initial SID before the SELinux policy was loaded, making it difficult to distinguish early boot userspace processes from the kernel in the SELinux policy. For most users this will be a non-issue as the policy is loaded early enough during boot, but for users who load their SELinux policy relatively late, this should make it easier to construct meaningful security policies.

  • Internal improvements to the SELinux management filesystem, selinuxfs, that is mounted at “/sys/fs/selinux” on SELinux enabled systems. In addition to locking changes, there is a minor change in how the selinuxfs “boolean” and “class” directories are managed during a policy reload. With this change a new directory, “.swapover”, is created to temporarily contain the new “boolean” and “class” directories while they are being built. Once the new policy directories are fully populated they are swapped with the existing policy directories and the old directories are cleaned up. The “.swapover” directory, is not accessible by even privileged users on the system.

  • Fix an issue where the input sanity checking on socket bind(2) operations was slightly different depending on the presence of SELinux. This is caused by the placement of the LSM hooks in the generic socket layer as opposed to the protocol specific handler where the protocol specific sanity checks are performed.

  • Consolidate multiple open coded SELinux access vector comparisons into a single new helper function and use that instead. While this should not change the behavior of the code, it is an improvement to both the code quality and maintainability.

  • Apply the Linux kernel coding style to the SELinux kernel header files in the “security/selinux/include” directory. In the future I expect to introduce code verification tools to help developers improve initial code quality, and an important part of that is ensuring that the existing sources meets a minimum quality standard. This is a work in progress, with many files still in need of style fixes.

  • Minor improvements to the hashing function used in the filename transition code.

  • Minor fixes to synchronize function prototypes with the function definition.

  • Remove old and outdated source code comments.

Audit

  • Rework the audit command acknowledgement code in the kernel to allow for more immediate acknowledgments of audit daemon registrations. This should help improve responsiveness and reliability on heavily loaded systems with large audit backlogs.