summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@diac24.net>2019-03-06 15:58:20 +0100
committerGitHub <noreply@github.com>2019-03-06 15:58:20 +0100
commitcd92ac05f83a82b13e69cd2d230155f6cd332eae (patch)
tree83433f56c3d167513e98abff2aa0d498194e8203 /lib
parentMerge pull request #3869 from qlyoung/cocci-fixes (diff)
parentlibs: make privilege escalation thread-safe (diff)
downloadfrr-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.c19
-rw-r--r--lib/privs.h10
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 */