diff options
author | Mark Stapp <mjs@voltanet.io> | 2019-03-05 21:28:26 +0100 |
---|---|---|
committer | Mark Stapp <mjs@voltanet.io> | 2019-03-05 17:08:31 +0100 |
commit | c5c44d4b41717484f23e11882e85983585b59e95 (patch) | |
tree | 1e14b9dfc1bbc52639c679541dec156f586d6010 /lib/privs.c | |
parent | Revert "nhrpd: strncpy -> strlcpy" (diff) | |
download | frr-c5c44d4b41717484f23e11882e85983585b59e95.tar.xz frr-c5c44d4b41717484f23e11882e85983585b59e95.zip |
libs: make privilege escalation thread-safe
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>
Diffstat (limited to 'lib/privs.c')
-rw-r--r-- | lib/privs.c | 19 |
1 files changed, 19 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. */ |