diff mbox series

nfs-utils: use getpwuid_r() and getpwnam_r() in gssd

Message ID 20241019052340.28225-1-raven@themaw.net (mailing list archive)
State New
Headers show
Series nfs-utils: use getpwuid_r() and getpwnam_r() in gssd | expand

Commit Message

Ian Kent Oct. 19, 2024, 5:23 a.m. UTC
gssd uses getpwuid(3) and getpwnam(3) in a pthreads context but
these functions are not thread safe.

Signed-off-by: Ian Kent <raven@themaw.net>
---
 utils/gssd/gssd_proc.c | 34 ++++++++++++++++++++++++----------
 1 file changed, 24 insertions(+), 10 deletions(-)

Comments

Steve Dickson Oct. 19, 2024, 12:26 p.m. UTC | #1
On 10/19/24 1:23 AM, Ian Kent wrote:
> gssd uses getpwuid(3) and getpwnam(3) in a pthreads context but
> these functions are not thread safe.
> 
> Signed-off-by: Ian Kent <raven@themaw.net>
Committed... Thanks for the quick turn around.

steved.
> ---
>   utils/gssd/gssd_proc.c | 34 ++++++++++++++++++++++++----------
>   1 file changed, 24 insertions(+), 10 deletions(-)
> 
> diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
> index 2ad84c59..01331485 100644
> --- a/utils/gssd/gssd_proc.c
> +++ b/utils/gssd/gssd_proc.c
> @@ -489,7 +489,10 @@ success:
>   static int
>   change_identity(uid_t uid)
>   {
> -	struct passwd	*pw;
> +	struct passwd  pw;
> +	struct passwd *ppw;
> +	char *pw_tmp;
> +	long tmplen;
>   	int res;
>   
>   	/* drop list of supplimentary groups first */
> @@ -502,15 +505,25 @@ change_identity(uid_t uid)
>   		return errno;
>   	}
>   
> +	tmplen = sysconf(_SC_GETPW_R_SIZE_MAX);
> +	if (tmplen < 0)
> +		tmplen = 16384;
> +
> +	pw_tmp = malloc(tmplen);
> +	if (!pw_tmp) {
> +		printerr(0, "WARNING: unable to allocate passwd buffer\n");
> +		return errno ? errno : ENOMEM;
> +	}
> +
>   	/* try to get pwent for user */
> -	pw = getpwuid(uid);
> -	if (!pw) {
> +	res = getpwuid_r(uid, &pw, pw_tmp, tmplen, &ppw);
> +	if (!ppw) {
>   		/* if that doesn't work, try to get one for "nobody" */
> -		errno = 0;
> -		pw = getpwnam("nobody");
> -		if (!pw) {
> +		res = getpwnam_r("nobody", &pw, pw_tmp, tmplen, &ppw);
> +		if (!ppw) {
>   			printerr(0, "WARNING: unable to determine gid for uid %u\n", uid);
> -			return errno ? errno : ENOENT;
> +			free(pw_tmp);
> +			return res ? res : ENOENT;
>   		}
>   	}
>   
> @@ -521,12 +534,13 @@ change_identity(uid_t uid)
>   	 * other threads. To bypass this, we have to call syscall() directly.
>   	 */
>   #ifdef __NR_setresgid32
> -	res = syscall(SYS_setresgid32, pw->pw_gid, pw->pw_gid, pw->pw_gid);
> +	res = syscall(SYS_setresgid32, pw.pw_gid, pw.pw_gid, pw.pw_gid);
>   #else
> -	res = syscall(SYS_setresgid, pw->pw_gid, pw->pw_gid, pw->pw_gid);
> +	res = syscall(SYS_setresgid, pw.pw_gid, pw.pw_gid, pw.pw_gid);
>   #endif
> +	free(pw_tmp);
>   	if (res != 0) {
> -		printerr(0, "WARNING: failed to set gid to %u!\n", pw->pw_gid);
> +		printerr(0, "WARNING: failed to set gid to %u!\n", pw.pw_gid);
>   		return errno;
>   	}
>
diff mbox series

Patch

diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
index 2ad84c59..01331485 100644
--- a/utils/gssd/gssd_proc.c
+++ b/utils/gssd/gssd_proc.c
@@ -489,7 +489,10 @@  success:
 static int
 change_identity(uid_t uid)
 {
-	struct passwd	*pw;
+	struct passwd  pw;
+	struct passwd *ppw;
+	char *pw_tmp;
+	long tmplen;
 	int res;
 
 	/* drop list of supplimentary groups first */
@@ -502,15 +505,25 @@  change_identity(uid_t uid)
 		return errno;
 	}
 
+	tmplen = sysconf(_SC_GETPW_R_SIZE_MAX);
+	if (tmplen < 0)
+		tmplen = 16384;
+
+	pw_tmp = malloc(tmplen);
+	if (!pw_tmp) {
+		printerr(0, "WARNING: unable to allocate passwd buffer\n");
+		return errno ? errno : ENOMEM;
+	}
+
 	/* try to get pwent for user */
-	pw = getpwuid(uid);
-	if (!pw) {
+	res = getpwuid_r(uid, &pw, pw_tmp, tmplen, &ppw);
+	if (!ppw) {
 		/* if that doesn't work, try to get one for "nobody" */
-		errno = 0;
-		pw = getpwnam("nobody");
-		if (!pw) {
+		res = getpwnam_r("nobody", &pw, pw_tmp, tmplen, &ppw);
+		if (!ppw) {
 			printerr(0, "WARNING: unable to determine gid for uid %u\n", uid);
-			return errno ? errno : ENOENT;
+			free(pw_tmp);
+			return res ? res : ENOENT;
 		}
 	}
 
@@ -521,12 +534,13 @@  change_identity(uid_t uid)
 	 * other threads. To bypass this, we have to call syscall() directly.
 	 */
 #ifdef __NR_setresgid32
-	res = syscall(SYS_setresgid32, pw->pw_gid, pw->pw_gid, pw->pw_gid);
+	res = syscall(SYS_setresgid32, pw.pw_gid, pw.pw_gid, pw.pw_gid);
 #else 
-	res = syscall(SYS_setresgid, pw->pw_gid, pw->pw_gid, pw->pw_gid);
+	res = syscall(SYS_setresgid, pw.pw_gid, pw.pw_gid, pw.pw_gid);
 #endif
+	free(pw_tmp);
 	if (res != 0) {
-		printerr(0, "WARNING: failed to set gid to %u!\n", pw->pw_gid);
+		printerr(0, "WARNING: failed to set gid to %u!\n", pw.pw_gid);
 		return errno;
 	}