[PATCH 08/11] libselinux: support huge passwd/group entries

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



getpwnam_r(3) and getgrnam_r(3) might return ERANGE in case the supplied
buffer was too short for the passwd/group entry.  Retry with a bigger
buffer.

Also use a fallback buffer size in case the libc returns -1 for
sysconf(3) of _SC_GETPW_R_SIZE_MAX or _SC_GETGR_R_SIZE_MAX, like musl.

Signed-off-by: Christian Göttsche <cgzones@xxxxxxxxxxxxxx>
---
 libselinux/src/seusers.c | 33 +++++++++++++++++++++++++--------
 1 file changed, 25 insertions(+), 8 deletions(-)

diff --git a/libselinux/src/seusers.c b/libselinux/src/seusers.c
index e5cfd510..16d69347 100644
--- a/libselinux/src/seusers.c
+++ b/libselinux/src/seusers.c
@@ -6,6 +6,8 @@
 #include <stdio_ext.h>
 #include <ctype.h>
 #include <errno.h>
+#include <limits.h>
+
 #include <selinux/selinux.h>
 #include <selinux/context.h>
 
@@ -99,15 +101,30 @@ static gid_t get_default_gid(const char *name) {
 	struct passwd pwstorage, *pwent = NULL;
 	gid_t gid = -1;
 	/* Allocate space for the getpwnam_r buffer */
+	char *rbuf = NULL;
 	long rbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
-	if (rbuflen <= 0) return -1;
-	char *rbuf = malloc(rbuflen);
-	if (rbuf == NULL) return -1;
+	if (rbuflen <= 0)
+		rbuflen = 1024;
+
+	for (;;) {
+		int rc;
+
+		rbuf = malloc(rbuflen);
+		if (rbuf == NULL)
+			break;
 
-	int retval = getpwnam_r(name, &pwstorage, rbuf, rbuflen, &pwent);
-	if (retval == 0 && pwent) {
-		gid = pwent->pw_gid;
+		rc = getpwnam_r(name, &pwstorage, rbuf, rbuflen, &pwent);
+		if (rc == ERANGE && rbuflen < LONG_MAX / 2) {
+			free(rbuf);
+			rbuflen *= 2;
+			continue;
+		}
+		if (rc == 0 && pwent)
+			gid = pwent->pw_gid;
+
+		break;
 	}
+
 	free(rbuf);
 	return gid;
 }
@@ -120,7 +137,7 @@ static int check_group(const char *group, const char *name, const gid_t gid) {
 
 	long rbuflen = sysconf(_SC_GETGR_R_SIZE_MAX);
 	if (rbuflen <= 0)
-		return 0;
+		rbuflen = 1024;
 	char *rbuf;
 
 	while(1) {
@@ -129,7 +146,7 @@ static int check_group(const char *group, const char *name, const gid_t gid) {
 			return 0;
 		int retval = getgrnam_r(group, &gbuf, rbuf, 
 				rbuflen, &grent);
-		if ( retval == ERANGE )
+		if (retval == ERANGE && rbuflen < LONG_MAX / 2)
 		{
 			free(rbuf);
 			rbuflen = rbuflen * 2;
-- 
2.43.0





[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux