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 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.





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

  Powered by Linux