Re: [PATCH 1/1] libselinux: do not return the cached prev_current value when using getpidcon()

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

 



On Mon, May 30, 2022 at 3:09 AM Nicolas Iooss <nicolas.iooss@xxxxxxx> wrote:
>
> libselinux implements a cache mechanism for get*con() functions, such
> that when a thread calls setcon(...) then getcon(...), the context is
> directly returned. Unfortunately, getpidcon(pid, &context) uses the same
> cached variable, so when a program uses setcon("something"), all later
> calls to getpidcon(pid, ...) returns "something". This is a bug.
>
> Here is a program which illustrates this bug:
>
>     #include <stdio.h>
>     #include <selinux/selinux.h>
>
>     int main() {
>         char *context = "";
>         if (getpidcon(1, &context) < 0) {
>             perror("getpidcon(1)");
>         }
>         printf("getpidcon(1) = %s\n", context);
>
>         if (getcon(&context) < 0) {
>             perror("getcon()");
>         }
>         printf("getcon() = %s\n", context);
>         if (setcon(context) < 0) {
>             perror("setcon()");
>         }
>         if (getpidcon(1, &context) < 0) {
>             perror("getpidcon(1)");
>         }
>         printf("getpidcon(1) = %s\n", context);
>
>         return 0;
>     }
>
> On an Arch Linux system using unconfined user, this program displays:
>
>     getpidcon(1) = system_u:system_r:init_t
>     getcon() = unconfined_u:unconfined_r:unconfined_t
>     getpidcon(1) = unconfined_u:unconfined_r:unconfined_t
>
> With this commit, this program displays:
>
>     getpidcon(1) = system_u:system_r:init_t
>     getcon() = unconfined_u:unconfined_r:unconfined_t
>     getpidcon(1) = system_u:system_r:init_t
>
> This bug was present in the first commit of
> https://github.com/SELinuxProject/selinux git history. It was reported
> in https://lore.kernel.org/selinux/20220121084012.GS7643@xxxxxxxx/ and a
> patch to fix it was sent in
> https://patchwork.kernel.org/project/selinux/patch/20220127130741.31940-1-jsegitz@xxxxxxx/
> without a clear explanation. This patch added pid checks, which made
> sense but were difficult to read. Instead, it is possible to change the
> way the functions are called so that they directly know which cache
> variable to use.
>
> Moreover, as the code is not clear at all (I spent too much time trying
> to understand what the switch did and what the thread-local variable
> contained), this commit also reworks libselinux/src/procattr.c to:
> - not use hard-to-understand switch/case constructions on strings (they
>   are replaced by a new argument filled by macros)
> - remove getpidattr_def macro (it was only used once, for pidcon, and
>   the code is clearer with one less macro)
> - remove the pid parameter of setprocattrcon() and setprocattrcon_raw()
>   (it is always zero)
>
> Signed-off-by: Nicolas Iooss <nicolas.iooss@xxxxxxx>
> Cc: Johannes Segitz <jsegitz@xxxxxxx>

Acked-by: James Carter <jwcart2@xxxxxxxxx>

> ---
>  libselinux/src/procattr.c | 147 +++++++++++++-------------------------
>  1 file changed, 50 insertions(+), 97 deletions(-)
>
> diff --git a/libselinux/src/procattr.c b/libselinux/src/procattr.c
> index 142fbf3a80e0..6f4cfb82479d 100644
> --- a/libselinux/src/procattr.c
> +++ b/libselinux/src/procattr.c
> @@ -11,11 +11,14 @@
>
>  #define UNSET (char *) -1
>
> +/* Cached values so that when a thread calls set*con() then gen*con(), the value
> + * which was set is directly returned.
> + */
>  static __thread char *prev_current = UNSET;
> -static __thread char * prev_exec = UNSET;
> -static __thread char * prev_fscreate = UNSET;
> -static __thread char * prev_keycreate = UNSET;
> -static __thread char * prev_sockcreate = UNSET;
> +static __thread char *prev_exec = UNSET;
> +static __thread char *prev_fscreate = UNSET;
> +static __thread char *prev_keycreate = UNSET;
> +static __thread char *prev_sockcreate = UNSET;
>
>  static pthread_once_t once = PTHREAD_ONCE_INIT;
>  static pthread_key_t destructor_key;
> @@ -111,43 +114,18 @@ out:
>         return fd;
>  }
>
> -static int getprocattrcon_raw(char ** context,
> -                             pid_t pid, const char *attr)
> +static int getprocattrcon_raw(char **context, pid_t pid, const char *attr,
> +                             const char *prev_context)
>  {
>         char *buf;
>         size_t size;
>         int fd;
>         ssize_t ret;
>         int errno_hold;
> -       char * prev_context;
>
>         __selinux_once(once, init_procattr);
>         init_thread_destructor();
>
> -       switch (attr[0]) {
> -               case 'c':
> -                       prev_context = prev_current;
> -                       break;
> -               case 'e':
> -                       prev_context = prev_exec;
> -                       break;
> -               case 'f':
> -                       prev_context = prev_fscreate;
> -                       break;
> -               case 'k':
> -                       prev_context = prev_keycreate;
> -                       break;
> -               case 's':
> -                       prev_context = prev_sockcreate;
> -                       break;
> -               case 'p':
> -                       prev_context = NULL;
> -                       break;
> -               default:
> -                       errno = ENOENT;
> -                       return -1;
> -       }
> -
>         if (prev_context && prev_context != UNSET) {
>                 *context = strdup(prev_context);
>                 if (!(*context)) {
> @@ -194,13 +172,13 @@ static int getprocattrcon_raw(char ** context,
>         return ret;
>  }
>
> -static int getprocattrcon(char ** context,
> -                         pid_t pid, const char *attr)
> +static int getprocattrcon(char **context, pid_t pid, const char *attr,
> +                         const char *prev_context)
>  {
>         int ret;
>         char * rcontext;
>
> -       ret = getprocattrcon_raw(&rcontext, pid, attr);
> +       ret = getprocattrcon_raw(&rcontext, pid, attr, prev_context);
>
>         if (!ret) {
>                 ret = selinux_raw_to_trans_context(rcontext, context);
> @@ -210,45 +188,24 @@ static int getprocattrcon(char ** context,
>         return ret;
>  }
>
> -static int setprocattrcon_raw(const char * context,
> -                             pid_t pid, const char *attr)
> +static int setprocattrcon_raw(const char *context, const char *attr,
> +                             char **prev_context)
>  {
>         int fd;
>         ssize_t ret;
>         int errno_hold;
> -       char **prev_context, *context2 = NULL;
> +       char *context2 = NULL;
>
>         __selinux_once(once, init_procattr);
>         init_thread_destructor();
>
> -       switch (attr[0]) {
> -               case 'c':
> -                       prev_context = &prev_current;
> -                       break;
> -               case 'e':
> -                       prev_context = &prev_exec;
> -                       break;
> -               case 'f':
> -                       prev_context = &prev_fscreate;
> -                       break;
> -               case 'k':
> -                       prev_context = &prev_keycreate;
> -                       break;
> -               case 's':
> -                       prev_context = &prev_sockcreate;
> -                       break;
> -               default:
> -                       errno = ENOENT;
> -                       return -1;
> -       }
> -
>         if (!context && !*prev_context)
>                 return 0;
>         if (context && *prev_context && *prev_context != UNSET
>             && !strcmp(context, *prev_context))
>                 return 0;
>
> -       fd = openattr(pid, attr, O_RDWR | O_CLOEXEC);
> +       fd = openattr(0, attr, O_RDWR | O_CLOEXEC);
>         if (fd < 0)
>                 return -1;
>         if (context) {
> @@ -279,8 +236,8 @@ out:
>         }
>  }
>
> -static int setprocattrcon(const char * context,
> -                         pid_t pid, const char *attr)
> +static int setprocattrcon(const char *context, const char *attr,
> +                         char **prev_context)
>  {
>         int ret;
>         char * rcontext;
> @@ -288,62 +245,58 @@ static int setprocattrcon(const char * context,
>         if (selinux_trans_to_raw_context(context, &rcontext))
>                 return -1;
>
> -       ret = setprocattrcon_raw(rcontext, pid, attr);
> +       ret = setprocattrcon_raw(rcontext, attr, prev_context);
>
>         freecon(rcontext);
>
>         return ret;
>  }
>
> -#define getselfattr_def(fn, attr) \
> +#define getselfattr_def(fn, attr, prev_context) \
>         int get##fn##_raw(char **c) \
>         { \
> -               return getprocattrcon_raw(c, 0, #attr); \
> +               return getprocattrcon_raw(c, 0, attr, prev_context); \
>         } \
>         int get##fn(char **c) \
>         { \
> -               return getprocattrcon(c, 0, #attr); \
> +               return getprocattrcon(c, 0, attr, prev_context); \
>         }
>
> -#define setselfattr_def(fn, attr) \
> +#define setselfattr_def(fn, attr, prev_context) \
>         int set##fn##_raw(const char * c) \
>         { \
> -               return setprocattrcon_raw(c, 0, #attr); \
> +               return setprocattrcon_raw(c, attr, &prev_context); \
>         } \
>         int set##fn(const char * c) \
>         { \
> -               return setprocattrcon(c, 0, #attr); \
> +               return setprocattrcon(c, attr, &prev_context); \
>         }
>
> -#define all_selfattr_def(fn, attr) \
> -       getselfattr_def(fn, attr)        \
> -       setselfattr_def(fn, attr)
> +#define all_selfattr_def(fn, attr, prev_context) \
> +       getselfattr_def(fn, attr, prev_context)  \
> +       setselfattr_def(fn, attr, prev_context)
>
> -#define getpidattr_def(fn, attr) \
> -       int get##fn##_raw(pid_t pid, char **c)  \
> -       { \
> -               if (pid <= 0) { \
> -                       errno = EINVAL; \
> -                       return -1; \
> -               } else { \
> -                       return getprocattrcon_raw(c, pid, #attr); \
> -               } \
> -       } \
> -       int get##fn(pid_t pid, char **c)        \
> -       { \
> -               if (pid <= 0) { \
> -                       errno = EINVAL; \
> -                       return -1; \
> -               } else { \
> -                       return getprocattrcon(c, pid, #attr); \
> -               } \
> -       }
> +all_selfattr_def(con, "current", prev_current)
> +    getselfattr_def(prevcon, "prev", NULL)
> +    all_selfattr_def(execcon, "exec", prev_exec)
> +    all_selfattr_def(fscreatecon, "fscreate", prev_fscreate)
> +    all_selfattr_def(sockcreatecon, "sockcreate", prev_sockcreate)
> +    all_selfattr_def(keycreatecon, "keycreate", prev_keycreate)
>
> -all_selfattr_def(con, current)
> -    getpidattr_def(pidcon, current)
> -    getselfattr_def(prevcon, prev)
> -    all_selfattr_def(execcon, exec)
> -    all_selfattr_def(fscreatecon, fscreate)
> -    all_selfattr_def(sockcreatecon, sockcreate)
> -    all_selfattr_def(keycreatecon, keycreate)
> +int getpidcon_raw(pid_t pid, char **c)
> +{
> +       if (pid <= 0) {
> +               errno = EINVAL;
> +               return -1;
> +       }
> +       return getprocattrcon_raw(c, pid, "current", NULL);
> +}
>
> +int getpidcon(pid_t pid, char **c)
> +{
> +       if (pid <= 0) {
> +               errno = EINVAL;
> +               return -1;
> +       }
> +       return getprocattrcon(c, pid, "current", NULL);
> +}
> --
> 2.36.1
>



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

  Powered by Linux