diff options
author | David Lamparter <equinox@diac24.net> | 2019-03-06 15:58:20 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-06 15:58:20 +0100 |
commit | cd92ac05f83a82b13e69cd2d230155f6cd332eae (patch) | |
tree | 83433f56c3d167513e98abff2aa0d498194e8203 /lib | |
parent | Merge pull request #3869 from qlyoung/cocci-fixes (diff) | |
parent | libs: make privilege escalation thread-safe (diff) | |
download | frr-cd92ac05f83a82b13e69cd2d230155f6cd332eae.tar.xz frr-cd92ac05f83a82b13e69cd2d230155f6cd332eae.zip |
Merge pull request #3911 from mjstapp/fix_privs_deadlock
libs: make privilege elevation thread-safe
Diffstat (limited to 'lib')
-rw-r--r-- | lib/privs.c | 19 | ||||
-rw-r--r-- | lib/privs.h | 10 |
2 files changed, 29 insertions, 0 deletions
diff --git a/lib/privs.c b/lib/privs.c index 293280007..3ce8e0d57 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -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. */ diff --git a/lib/privs.h b/lib/privs.h index 1fee423a9..01ddba462 100644 --- a/lib/privs.h +++ b/lib/privs.h @@ -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 */ |