]> git.puffer.fish Git - mirror/frr.git/commitdiff
libs: make privilege escalation thread-safe 3911/head
authorMark Stapp <mjs@voltanet.io>
Tue, 5 Mar 2019 20:28:26 +0000 (15:28 -0500)
committerMark Stapp <mjs@voltanet.io>
Tue, 5 Mar 2019 16:08:31 +0000 (11:08 -0500)
Privs escalation is process-wide, and a multi-threaded process
can deadlock. This adds a mutex and a counter to the privs
object, preventing multiple threads from making the privs
escalation system call.

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

index 2932800070cce1f5143807ec014ee75caf5651a3..3ce8e0d57a4b7239a5dc4b64636ca5a36ab28cc5 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 1fee423a95e35dff57d1e332aac9fc73afab6f5a..01ddba46223e207a7eecca88a867dddce71e96af 100644 (file)
@@ -23,6 +23,8 @@
 #ifndef _ZEBRA_PRIVS_H
 #define _ZEBRA_PRIVS_H
 
+#include <pthread.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -59,6 +61,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 */