Re: [RFC PATCH] libselinux: emulate O_PATH support in fgetfilecon/fsetfilecon

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

 



On Wed, May 11, 2022 at 3:09 PM James Carter <jwcart2@xxxxxxxxx> wrote:
>
> On Sun, May 8, 2022 at 3:19 PM Christian Göttsche
> <cgzones@xxxxxxxxxxxxxx> wrote:
> >
> > Operating on a file descriptor avoids TOCTOU issues and one opened via
> > O_PATH avoids the requirement of having read access to the file.  Since
> > Linux does not natively support file descriptors opened via O_PATH in
> > fgetxattr(2) and at least glibc and musl does not emulate O_PATH support
> > in their implementations, fgetfilecon(3) and fsetfilecon(3) also do not
> > currently support file descriptors opened with O_PATH.
> >
> > Inspired by CVE-2013-4392: https://github.com/systemd/systemd/pull/8583
> > Implementation adapted from: https://android.googlesource.com/platform/bionic/+/2825f10b7f61558c264231a536cf3affc0d84204%5E%21/
> >
> > Signed-off-by: Christian Göttsche <cgzones@xxxxxxxxxxxxxx>
>
> Works as advertised.
>
> Acked-by: James Carter <jwcart2@xxxxxxxxx>
>

Merged.
Thanks,
Jim

> > ---
> >  libselinux/man/man3/getfilecon.3 |  4 +++-
> >  libselinux/man/man3/setfilecon.3 |  4 +++-
> >  libselinux/src/fgetfilecon.c     | 28 +++++++++++++++++++++++++---
> >  libselinux/src/fsetfilecon.c     | 23 ++++++++++++++++++++++-
> >  4 files changed, 53 insertions(+), 6 deletions(-)
> >
> > diff --git a/libselinux/man/man3/getfilecon.3 b/libselinux/man/man3/getfilecon.3
> > index 5bb575b5..c3e92ba1 100644
> > --- a/libselinux/man/man3/getfilecon.3
> > +++ b/libselinux/man/man3/getfilecon.3
> > @@ -33,7 +33,9 @@ is identical to
> >  .BR getfilecon (),
> >  only the open file pointed to by filedes (as returned by
> >  .BR open (2))
> > -is interrogated in place of path.
> > +is interrogated in place of path.  Since libselinux 3.4 a file opened via
> > +.I O_PATH
> > +is supported.
> >
> >  .BR getfilecon_raw (),
> >  .BR lgetfilecon_raw ()
> > diff --git a/libselinux/man/man3/setfilecon.3 b/libselinux/man/man3/setfilecon.3
> > index 0e9a383f..61f9a806 100644
> > --- a/libselinux/man/man3/setfilecon.3
> > +++ b/libselinux/man/man3/setfilecon.3
> > @@ -29,7 +29,9 @@ link itself has it's context set, not the file that it refers to.
> >  is identical to setfilecon, only the open file pointed to by filedes (as
> >  returned by
> >  .BR open (2))
> > -has it's context set in place of path.
> > +has it's context set in place of path.  Since libselinux 3.4 a file opened via
> > +.I O_PATH
> > +is supported.
> >
> >  .BR setfilecon_raw (),
> >  .BR lsetfilecon_raw (),
> > diff --git a/libselinux/src/fgetfilecon.c b/libselinux/src/fgetfilecon.c
> > index 8c748f8a..baf38ec1 100644
> > --- a/libselinux/src/fgetfilecon.c
> > +++ b/libselinux/src/fgetfilecon.c
> > @@ -3,10 +3,32 @@
> >  #include <string.h>
> >  #include <stdlib.h>
> >  #include <errno.h>
> > +#include <stdio.h>
> >  #include <sys/xattr.h>
> >  #include "selinux_internal.h"
> >  #include "policy.h"
> >
> > +static ssize_t fgetxattr_wrapper(int fd, const char *name, void *value, size_t size) {
> > +       char buf[40];
> > +       int fd_flag, saved_errno = errno;
> > +       ssize_t ret;
> > +
> > +       ret = fgetxattr(fd, name, value, size);
> > +       if (ret != -1 || errno != EBADF)
> > +               return ret;
> > +
> > +       /* Emulate O_PATH support */
> > +       fd_flag = fcntl(fd, F_GETFL);
> > +       if (fd_flag == -1 || (fd_flag & O_PATH) == 0) {
> > +               errno = EBADF;
> > +               return -1;
> > +       }
> > +
> > +       snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
> > +       errno = saved_errno;
> > +       return getxattr(buf, name, value, size);
> > +}
> > +
> >  int fgetfilecon_raw(int fd, char ** context)
> >  {
> >         char *buf;
> > @@ -19,11 +41,11 @@ int fgetfilecon_raw(int fd, char ** context)
> >                 return -1;
> >         memset(buf, 0, size);
> >
> > -       ret = fgetxattr(fd, XATTR_NAME_SELINUX, buf, size - 1);
> > +       ret = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, buf, size - 1);
> >         if (ret < 0 && errno == ERANGE) {
> >                 char *newbuf;
> >
> > -               size = fgetxattr(fd, XATTR_NAME_SELINUX, NULL, 0);
> > +               size = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, NULL, 0);
> >                 if (size < 0)
> >                         goto out;
> >
> > @@ -34,7 +56,7 @@ int fgetfilecon_raw(int fd, char ** context)
> >
> >                 buf = newbuf;
> >                 memset(buf, 0, size);
> > -               ret = fgetxattr(fd, XATTR_NAME_SELINUX, buf, size - 1);
> > +               ret = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, buf, size - 1);
> >         }
> >        out:
> >         if (ret == 0) {
> > diff --git a/libselinux/src/fsetfilecon.c b/libselinux/src/fsetfilecon.c
> > index 5cf34e3f..be821c7a 100644
> > --- a/libselinux/src/fsetfilecon.c
> > +++ b/libselinux/src/fsetfilecon.c
> > @@ -3,13 +3,34 @@
> >  #include <string.h>
> >  #include <stdlib.h>
> >  #include <errno.h>
> > +#include <stdio.h>
> >  #include <sys/xattr.h>
> >  #include "selinux_internal.h"
> >  #include "policy.h"
> >
> > +static int fsetxattr_wrapper(int fd, const char* name, const void* value, size_t size, int flags) {
> > +       char buf[40];
> > +       int rc, fd_flag, saved_errno = errno;
> > +
> > +       rc = fsetxattr(fd, name, value, size, flags);
> > +       if (rc == 0 || errno != EBADF)
> > +               return rc;
> > +
> > +       /* Emulate O_PATH support */
> > +       fd_flag = fcntl(fd, F_GETFL);
> > +       if (fd_flag == -1 || (fd_flag & O_PATH) == 0) {
> > +               errno = EBADF;
> > +               return -1;
> > +       }
> > +
> > +       snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
> > +       errno = saved_errno;
> > +       return setxattr(buf, name, value, size, flags);
> > +}
> > +
> >  int fsetfilecon_raw(int fd, const char * context)
> >  {
> > -       int rc = fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1,
> > +       int rc = fsetxattr_wrapper(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1,
> >                          0);
> >         if (rc < 0 && errno == ENOTSUP) {
> >                 char * ccontext = NULL;
> > --
> > 2.36.0
> >




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

  Powered by Linux