]> git.puffer.fish Git - matthieu/frr.git/commitdiff
libs: make privs elevation thread-safe
authorMark Stapp <mjs@voltanet.io>
Wed, 6 Mar 2019 15:41:47 +0000 (10:41 -0500)
committerMark Stapp <mjs@voltanet.io>
Wed, 6 Mar 2019 15:41:47 +0000 (10:41 -0500)
[Double-commit PR 3911 to 7.0] Privs elevation is per-process,
and can deadlock if a multiple threads drive into the uid system
call. Add a refcount and a mutex to avoid reentrant calls to
the OS.

Signed-off-by: Mark Stapp <mjs@voltanet.io>
lib/privs.c
lib/privs.h

index 838ff8fc928fae844c6cfad3a9401baf0a45c403..577e8ba6c4c79d6c0dc195f5d69bb741ffb19e04 100644 (file)
@@ -706,6 +706,14 @@ struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
        if (!privs)
                return NULL;
 
+       /* If we're already elevated, just return */
+       pthread_mutex_lock(&(privs->mutex));
+       if (++privs->refcount > 1) {
+               pthread_mutex_unlock(&(privs->mutex));
+               return privs;
+       }
+       pthread_mutex_unlock(&(privs->mutex));
+
        errno = 0;
        if (privs->change(ZPRIVS_RAISE)) {
                zlog_err("%s: Failed to raise privileges (%s)",
@@ -723,6 +731,14 @@ void _zprivs_lower(struct zebra_privs_t **privs)
        if (!*privs)
                return;
 
+       /* Don't lower privs if there's another caller */
+       pthread_mutex_lock(&(*privs)->mutex);
+       if (--((*privs)->refcount) > 0) {
+               pthread_mutex_unlock(&(*privs)->mutex);
+               return;
+       }
+       pthread_mutex_unlock(&(*privs)->mutex);
+
        errno = 0;
        if ((*privs)->change(ZPRIVS_LOWER)) {
                zlog_err("%s: Failed to lower privileges (%s)",
@@ -743,6 +759,9 @@ void zprivs_preinit(struct zebra_privs_t *zprivs)
                exit(1);
        }
 
+       pthread_mutex_init(&(zprivs->mutex), NULL);
+       zprivs->refcount = 0;
+
        if (zprivs->vty_group) {
                /* in a "NULL" setup, this is allowed to fail too, but still
                 * try. */
index b061370b753d2ce2bc88b39699ede003175cb645..c7f5dc249c7b34d9df7532fd9b1a23bc71cf4c8d 100644 (file)
@@ -23,6 +23,8 @@
 #ifndef _ZEBRA_PRIVS_H
 #define _ZEBRA_PRIVS_H
 
+#include <pthread.h>
+
 /* list of zebra capabilities */
 typedef enum {
        ZCAP_SETID,
@@ -55,6 +57,14 @@ struct zebra_privs_t {
        zebra_capabilities_t *caps_i; /* caps to allow inheritance of */
        int cap_num_p;                /* number of caps in arrays */
        int cap_num_i;
+
+       /* Mutex and counter used to avoid race conditions in multi-threaded
+        * processes. The privs elevation is process-wide, so we need to
+        * avoid changing the privilege status across threads.
+        */
+       pthread_mutex_t mutex;
+       uint32_t refcount;
+
        const char *user; /* user and group to run as */
        const char *group;
        const char *vty_group; /* group to chown vty socket to */