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 /lib/privs.c | |
| 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>
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 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. */  | 
