Re: [PATCH v2] libselinux: add lock callbacks

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

 



On Tue, Jul 13, 2021 at 12:30 AM Seth Moore <sethmo@xxxxxxxxxx> wrote:
>
> The old mechanism to initialize AVC, avc_init(3), is deprected. This
> leaves libselinux with no way of guarding the AVC cache when accessed
> from multiple threads. When applications call access check APIs from
> multiple threads, the AVC cache may become corrupted.
>
> This change adds new callback functions to selinux_set_callback(3).
> These new callbacks all correspond to the functions that used to be
> passed via avc_init(3). Multi-threaded applications may set these
> callbacks to guard the AVC cache against simultaneous access by
> multiple threads.
>
> This change adds the following callbacks:
>   - SELINUX_CB_ALLOC_LOCK
>       is invoked to allocate new locks
>   - SELINUX_CB_GET_LOCK
>       is invoked to acquire a lock
>   - SELINUX_CB_RELEASE_LOCK
>       is invoked to release a previously-acquired lock
>   - SELINUX_CB_FREE_LOCK
>       is invoked to free a previosly-allocated lock
>
> Signed-off-by: Seth Moore <sethmo@xxxxxxxxxx>

Acked-by: Nicolas Iooss <nicolas.iooss@xxxxxxx>

Thanks,
Nicolas

> ---
>  libselinux/include/selinux/selinux.h       | 12 ++++++
>  libselinux/man/man3/selinux_set_callback.3 | 46 ++++++++++++++++++++++
>  libselinux/src/avc_internal.h              | 20 ++++++++--
>  libselinux/src/callbacks.c                 | 13 ++++++
>  4 files changed, 88 insertions(+), 3 deletions(-)
>
> diff --git a/libselinux/include/selinux/selinux.h b/libselinux/include/selinux/selinux.h
> index ae98a92e..c3c68b3a 100644
> --- a/libselinux/include/selinux/selinux.h
> +++ b/libselinux/include/selinux/selinux.h
> @@ -166,6 +166,14 @@ __attribute__ ((format(printf, 2, 3)))
>         int (*func_setenforce) (int enforcing);
>         /* netlink callback for policyload message */
>         int (*func_policyload) (int seqno);
> +       /* create a lock and return an opaque pointer to it */
> +       void *(*func_alloc_lock) (void);
> +       /* obtain a given lock, blocking if necessary */
> +       void (*func_get_lock) (void *lock);
> +       /* release a given lock */
> +       void (*func_release_lock) (void *lock);
> +       /* destroy a given lock */
> +       void (*func_free_lock) (void *lock);
>  };
>
>  #define SELINUX_CB_LOG         0
> @@ -173,6 +181,10 @@ __attribute__ ((format(printf, 2, 3)))
>  #define SELINUX_CB_VALIDATE    2
>  #define SELINUX_CB_SETENFORCE  3
>  #define SELINUX_CB_POLICYLOAD  4
> +#define SELINUX_CB_ALLOC_LOCK   5
> +#define SELINUX_CB_GET_LOCK     6
> +#define SELINUX_CB_RELEASE_LOCK 7
> +#define SELINUX_CB_FREE_LOCK    8
>
>  extern union selinux_callback selinux_get_callback(int type);
>  extern void selinux_set_callback(int type, union selinux_callback cb);
> diff --git a/libselinux/man/man3/selinux_set_callback.3 b/libselinux/man/man3/selinux_set_callback.3
> index 75f49b06..f7371504 100644
> --- a/libselinux/man/man3/selinux_set_callback.3
> +++ b/libselinux/man/man3/selinux_set_callback.3
> @@ -116,6 +116,52 @@ The
>  .I seqno
>  argument is the current sequential number of the policy generation in the system.
>  .
> +.TP
> +.B SELINUX_CB_ALLOC_LOCK
> +.BI "void *(*" alloc_lock ") ();"
> +
> +This callback is used to allocate a fresh lock for protecting critical sections.
> +Applications that call selinux library functions from multiple threads must either
> +perform their own locking or set each of the following:
> +
> +.B SELINUX_CB_ALLOC_LOCK
> +
> +.B SELINUX_CB_GET_LOCK
> +
> +.B SELINUX_CB_RELEASE_LOCK
> +
> +.B SELINUX_CB_FREE_LOCK
> +
> +.TP
> +.B SELINUX_CB_GET_LOCK
> +.BI "void (*" get_lock ") (void *" lock ");"
> +
> +This callback acquires the
> +.I lock
> +that was previously allocated with
> +.I alloc_lock.
> +This function must block until the
> +.I lock
> +can be acquired.
> +.
> +.TP
> +.B SELINUX_CB_RELEASE_LOCK
> +.BI "void (*" release_lock ") (void *" lock ");"
> +
> +This callback releases the
> +.I lock
> +that was previously acquired with
> +.I get_lock.
> +.
> +.TP
> +.B SELINUX_CB_FREE_LOCK
> +.BI "void (*" free_lock ") (void *" lock ");"
> +
> +This callback frees the
> +.I lock
> +that was previously allocated with
> +.I alloc_lock.
> +.
>  .SH "RETURN VALUE"
>  None.
>  .
> diff --git a/libselinux/src/avc_internal.h b/libselinux/src/avc_internal.h
> index a9a4aa0b..1f8e0102 100644
> --- a/libselinux/src/avc_internal.h
> +++ b/libselinux/src/avc_internal.h
> @@ -9,6 +9,7 @@
>  #ifndef _SELINUX_AVC_INTERNAL_H_
>  #define _SELINUX_AVC_INTERNAL_H_
>
> +#include <assert.h>
>  #include <stdio.h>
>  #include <stdlib.h>
>  #include <string.h>
> @@ -112,26 +113,39 @@ static inline void avc_stop_thread(void *thread)
>                 avc_func_stop_thread(thread);
>  }
>
> +static inline void check_lock_callbacks(void)
> +{
> +    if (avc_func_alloc_lock || avc_func_get_lock
> +            || avc_func_release_lock || avc_func_free_lock) {
> +        assert(avc_func_alloc_lock && avc_func_get_lock
> +                && avc_func_release_lock && avc_func_free_lock);
> +    }
> +}
> +
>  static inline void *avc_alloc_lock(void)
>  {
> +       check_lock_callbacks();
>         return avc_func_alloc_lock ? avc_func_alloc_lock() : NULL;
>  }
>
>  static inline void avc_get_lock(void *lock)
>  {
> -       if (avc_func_get_lock)
> +       check_lock_callbacks();
> +       if (avc_func_get_lock && lock)
>                 avc_func_get_lock(lock);
>  }
>
>  static inline void avc_release_lock(void *lock)
>  {
> -       if (avc_func_release_lock)
> +       check_lock_callbacks();
> +       if (avc_func_release_lock && lock)
>                 avc_func_release_lock(lock);
>  }
>
>  static inline void avc_free_lock(void *lock)
>  {
> -       if (avc_func_free_lock)
> +       check_lock_callbacks();
> +       if (avc_func_free_lock && lock)
>                 avc_func_free_lock(lock);
>  }
>
> diff --git a/libselinux/src/callbacks.c b/libselinux/src/callbacks.c
> index c18ccc54..b635c8d8 100644
> --- a/libselinux/src/callbacks.c
> +++ b/libselinux/src/callbacks.c
> @@ -9,6 +9,7 @@
>  #include <errno.h>
>  #include <selinux/selinux.h>
>  #include "callbacks.h"
> +#include "avc_internal.h"
>
>  /* default implementations */
>  static int __attribute__ ((format(printf, 2, 3)))
> @@ -95,6 +96,18 @@ selinux_set_callback(int type, union selinux_callback cb)
>         case SELINUX_CB_POLICYLOAD:
>                 selinux_netlink_policyload = cb.func_policyload;
>                 break;
> +       case SELINUX_CB_ALLOC_LOCK:
> +               avc_func_alloc_lock = cb.func_alloc_lock;
> +               break;
> +       case SELINUX_CB_GET_LOCK:
> +               avc_func_get_lock = cb.func_get_lock;
> +               break;
> +       case SELINUX_CB_RELEASE_LOCK:
> +               avc_func_release_lock = cb.func_release_lock;
> +               break;
> +       case SELINUX_CB_FREE_LOCK:
> +               avc_func_free_lock = cb.func_free_lock;
> +               break;
>         }
>  }
>
> --
> 2.32.0.93.g670b81a890-goog
>




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

  Powered by Linux