Re: [PATCH v2] selinux: add permission checks for loading other kinds of kernel files

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Feb 21, 2025 at 9:12 AM Daniel Burgener
<dburgener@xxxxxxxxxxxxxxxxxxx> wrote:
>
> On 2/21/2025 8:52 AM, Stephen Smalley wrote:
> > On Thu, Feb 20, 2025 at 3:24 PM Stephen Smalley
> > <stephen.smalley.work@xxxxxxxxx> wrote:
> >>
> >> On Thu, Feb 20, 2025 at 3:23 PM Stephen Smalley
> >> <stephen.smalley.work@xxxxxxxxx> wrote:
> >>>
> >>> On Mon, Feb 17, 2025 at 3:58 PM Christian Göttsche
> >>> <cgzones@xxxxxxxxxxxxxx> wrote:
> >>>>
> >>>> On Tue, 11 Feb 2025 at 19:22, <kippndavis.work@xxxxxxx> wrote:
> >>>>>
> >>>>> From: "Kipp N. Davis" <kippndavis.work@xxxxxxx>
> >>>>>
> >>>>> Although the LSM hooks for loading kernel modules were later generalized
> >>>>> to cover loading other kinds of files, SELinux didn't implement
> >>>>> corresponding permission checks, leaving only the module case covered.
> >>>>> Define and add new permission checks for these other cases.
> >>>>>
> >>>>> Signed-off-by: Cameron K. Williams <ckwilliams.work@xxxxxxxxx>
> >>>>> Signed-off-by: Kipp N. Davis <kippndavis.work@xxxxxxx>
> >>>>>
> >>>>> ---
> >>>>> Changes in v2:
> >>>>>    - Removed the `-EACCES` return in default case in
> >>>>>      selinux_kernel_read_file() and selinux_kernel_load_from_file(),
> >>>>>      reverting previous fallback behavior.
> >>>>>    - Added a compile-time check in these functions to catch new
> >>>>>      READING/LOADING_XXX entries.
> >>>>>
> >>>>> Thanks for your review! I've adjusted the default case so as to not
> >>>>> return an error and depart from pre-existing logic. I first tried to use
> >>>>> the pre-processor #errors but failed with the READING/LOADING_MAX_ID
> >>>>> enums, so I opted for BUILD_BUG_ON_MSG as a compile-time check with
> >>>>> those same enums instead to catch new entries.
> >>>>> ---
> >>>>>   security/selinux/hooks.c            | 56 +++++++++++++++++++++++------
> >>>>>   security/selinux/include/classmap.h |  4 ++-
> >>>>>   2 files changed, 49 insertions(+), 11 deletions(-)
> >>>>>
> >>>>> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> >>>>> index 7b867dfec88b..67bf37693cd7 100644
> >>>>> --- a/security/selinux/hooks.c
> >>>>> +++ b/security/selinux/hooks.c
> >>>>> @@ -4096,7 +4096,7 @@ static int selinux_kernel_module_request(char *kmod_name)
> >>>>>                              SYSTEM__MODULE_REQUEST, &ad);
> >>>>>   }
> >>>>>
> >>>>> -static int selinux_kernel_module_from_file(struct file *file)
> >>>>> +static int selinux_kernel_load_from_file(struct file *file, u32 requested)
> >>>>>   {
> >>>>>          struct common_audit_data ad;
> >>>>>          struct inode_security_struct *isec;
> >>>>> @@ -4104,12 +4104,9 @@ static int selinux_kernel_module_from_file(struct file *file)
> >>>>>          u32 sid = current_sid();
> >>>>>          int rc;
> >>>>>
> >>>>> -       /* init_module */
> >>>>>          if (file == NULL)
> >>>>>                  return avc_has_perm(sid, sid, SECCLASS_SYSTEM,
> >>>>> -                                       SYSTEM__MODULE_LOAD, NULL);
> >>>>> -
> >>>>> -       /* finit_module */
> >>>>> +                                       requested, NULL);
> >>>>>
> >>>>>          ad.type = LSM_AUDIT_DATA_FILE;
> >>>>>          ad.u.file = file;
> >>>>> @@ -4123,7 +4120,7 @@ static int selinux_kernel_module_from_file(struct file *file)
> >>>>>
> >>>>>          isec = inode_security(file_inode(file));
> >>>>>          return avc_has_perm(sid, isec->sid, SECCLASS_SYSTEM,
> >>>>> -                               SYSTEM__MODULE_LOAD, &ad);
> >>>>> +                               requested, &ad);
> >>>>>   }
> >>>>>
> >>>>>   static int selinux_kernel_read_file(struct file *file,
> >>>>> @@ -4131,10 +4128,32 @@ static int selinux_kernel_read_file(struct file *file,
> >>>>>                                      bool contents)
> >>>>>   {
> >>>>>          int rc = 0;
> >>>>> -
> >>>>> +       BUILD_BUG_ON_MSG(READING_MAX_ID > 7,
> >>>>> +                 "New kernel_read_file_id introduced; update SELinux!");
> >>>>>          switch (id) {
> >>>>
> >>>> Should READING_UNKNOWN be handled?
> >>>> It seems not to be used currently in-tree, but maybe stay on the safe side?
> >>>
> >>> IMHO, no. READING_UNKNOWN/LOADING_UNKNOWN aren't intended to be used
> >>> and would be a bug elsewhere in the kernel.
> >>>
> >>>>
> >>>>> +       case READING_FIRMWARE:
> >>>>> +               rc = selinux_kernel_load_from_file(contents ? file : NULL,
> >>>>> +                               SYSTEM__FIRMWARE_LOAD);
> >>>>> +               break;
> >>>>>          case READING_MODULE:
> >>>>> -               rc = selinux_kernel_module_from_file(contents ? file : NULL);
> >>>>> +               rc = selinux_kernel_load_from_file(contents ? file : NULL,
> >>>>> +                               SYSTEM__MODULE_LOAD);
> >>>>> +               break;
> >>>>> +       case READING_KEXEC_IMAGE:
> >>>>> +               rc = selinux_kernel_load_from_file(contents ? file : NULL,
> >>>>> +                               SYSTEM__KEXEC_IMAGE_LOAD);
> >>>>> +               break;
> >>>>> +       case READING_KEXEC_INITRAMFS:
> >>>>> +               rc = selinux_kernel_load_from_file(contents ? file : NULL,
> >>>>> +                               SYSTEM__KEXEC_INITRAMFS_LOAD);
> >>>>> +               break;
> >>>>> +       case READING_POLICY:
> >>>>> +               rc = selinux_kernel_load_from_file(contents ? file : NULL,
> >>>>> +                               SYSTEM__POLICY_LOAD);
> >>>>> +               break;
> >>>>> +       case READING_X509_CERTIFICATE:
> >>>>> +               rc = selinux_kernel_load_from_file(contents ? file : NULL,
> >>>>> +                               SYSTEM__X509_CERTIFICATE_LOAD);
> >>>>>                  break;
> >>>>>          default:
> >>>>>                  break;
> >>>>> @@ -4146,10 +4165,27 @@ static int selinux_kernel_read_file(struct file *file,
> >>>>>   static int selinux_kernel_load_data(enum kernel_load_data_id id, bool contents)
> >>>>>   {
> >>>>>          int rc = 0;
> >>>>> -
> >>>>> +       BUILD_BUG_ON_MSG(LOADING_MAX_ID > 7,
> >>>>> +        "New kernel_load_data_id introduced; update SELinux!");
> >>>>>          switch (id) {
> >>>>
> >>>> dito
> >>>>
> >>>>> +       case LOADING_FIRMWARE:
> >>>>> +               rc = selinux_kernel_load_from_file(NULL, SYSTEM__FIRMWARE_LOAD);
> >>>>> +               break;
> >>>>>          case LOADING_MODULE:
> >>>>> -               rc = selinux_kernel_module_from_file(NULL);
> >>>>> +               rc = selinux_kernel_load_from_file(NULL, SYSTEM__MODULE_LOAD);
> >>>>> +               break;
> >>>>> +       case LOADING_KEXEC_IMAGE:
> >>>>> +               rc = selinux_kernel_load_from_file(NULL, SYSTEM__KEXEC_IMAGE_LOAD);
> >>>>> +               break;
> >>>>> +       case LOADING_KEXEC_INITRAMFS:
> >>>>> +               rc = selinux_kernel_load_from_file(NULL, SYSTEM__KEXEC_INITRAMFS_LOAD);
> >>>>> +               break;
> >>>>> +       case LOADING_POLICY:
> >>>>> +               rc = selinux_kernel_load_from_file(NULL, SYSTEM__POLICY_LOAD);
> >>>>> +               break;
> >>>>> +       case LOADING_X509_CERTIFICATE:
> >>>>> +               rc = selinux_kernel_load_from_file(NULL,
> >>>>> +                               SYSTEM__X509_CERTIFICATE_LOAD);
> >>>>>                  break;
> >>>>>          default:
> >>>>>                  break;
> >>>>> diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
> >>>>> index 03e82477dce9..cfac41d12f7d 100644
> >>>>> --- a/security/selinux/include/classmap.h
> >>>>> +++ b/security/selinux/include/classmap.h
> >>>>> @@ -63,7 +63,9 @@ const struct security_class_mapping secclass_map[] = {
> >>>>>          { "process2", { "nnp_transition", "nosuid_transition", NULL } },
> >>>>>          { "system",
> >>>>>            { "ipc_info", "syslog_read", "syslog_mod", "syslog_console",
> >>>>> -           "module_request", "module_load", NULL } },
> >>>>> +           "module_request", "module_load", "firmware_load",
> >>>>> +           "kexec_image_load", "kexec_initramfs_load", "policy_load",
> >>>>
> >>>> In the SELinux world the word "policy" refers mostly to the SELinux policy.
> >>>> Maybe rename the permission verb "policy_load" to
> >>>> "security_policy_load" or similar? (it seems to be used by IMA,
> >>>> loadpin and zram currently)
> >>>
> >>> I don't really see how that is less ambiguous since SELinux policy is
> >>> a security policy too, but don't have any strong feelings either way.
> >>> We have the load_policy permission in the security class for loading
> >>> SELinux policy, so if we use security_policy_load here, then we'll end
> >>> up with SECURITY__LOAD_POLICY and SYSTEM__SECURITY_LOAD_POLICY.
> >>> What could go wrong?
> >>
> >> Sorry, that last one would be SYSTEM__SECURITY_POLICY_LOAD to be
> >> precise, but the point remains.
> >
> > Also, it appears that this policy_load is used by non-security code as
> > well, so that's another reason to not rename it.
>
> What about "kernel_policy_load"?  It's a little weird, since 1. SELinux
> policy is of course also a policy loaded into the kernel and 2. All of
> these permission names could be prefixed with kernel (eg
> "kernel_module_load").  But still, I sympathize with Christian's concern
> that "policy" in SELinux world refers to the SELinux policy, and
> system:policy_load vs security:load_policy is wildly confusing.

I'll defer to Paul to make the final call on naming so the patch
author doesn't need to re-spin the patches endlessly.





[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux