summaryrefslogtreecommitdiffstats
path: root/lib/privs.c
diff options
context:
space:
mode:
authorMark Stapp <mjs@voltanet.io>2019-03-05 21:28:26 +0100
committerMark Stapp <mjs@voltanet.io>2019-03-05 17:08:31 +0100
commitc5c44d4b41717484f23e11882e85983585b59e95 (patch)
tree1e14b9dfc1bbc52639c679541dec156f586d6010 /lib/privs.c
parentRevert "nhrpd: strncpy -> strlcpy" (diff)
downloadfrr-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.c19
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. */