diff options
| author | Mark Stapp <mjs@voltanet.io> | 2019-03-05 15:28:26 -0500 | 
|---|---|---|
| committer | Mark Stapp <mjs@voltanet.io> | 2019-03-05 11:08:31 -0500 | 
| commit | c5c44d4b41717484f23e11882e85983585b59e95 (patch) | |
| tree | 1e14b9dfc1bbc52639c679541dec156f586d6010 | |
| parent | b19abe1131daa38d1d0e31c4793925bb89f11c07 (diff) | |
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>
| -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 2932800070..3ce8e0d57a 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 1fee423a95..01ddba4622 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 */  | 
