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

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

 



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>

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