aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Eriksson <pen_lysator.liu.se>2026-07-06 19:33:22 +0000
committerRick Macklem <rmacklem@FreeBSD.org>2026-07-06 19:33:22 +0000
commitd7d71341ae7d79886143a9ce427dca0e858eda97 (patch)
tree5c7293968cbf27d3be3dc2fea0ed7a06de357c37
parentbf142ea4760bd4391092d9cc0038a0870cf7e0b2 (diff)
acl_from_text.c: Allow negative uid/gid numbers to be handled
getfacl / acl_to_text() incorrectly prints uid/gid numbers as signed integers. This causes uid / gid numbers larger than 2G (2147483648) to print as negative numbers. The libc acl_from_text() function does not handle negative numbers. This diff adds a backwards compatiblity fix to allow negative numbers... Reviewed by: rmacklem MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D57180
-rw-r--r--lib/libc/posix1e/acl_from_text.c41
1 files changed, 32 insertions, 9 deletions
diff --git a/lib/libc/posix1e/acl_from_text.c b/lib/libc/posix1e/acl_from_text.c
index 765b58290a04..746338b37f0c 100644
--- a/lib/libc/posix1e/acl_from_text.c
+++ b/lib/libc/posix1e/acl_from_text.c
@@ -39,6 +39,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <inttypes.h>
#include <assert.h>
#include "acl_support.h"
@@ -264,6 +265,24 @@ error_label:
}
/*
+ * Make sure the number given fits inside an uid_t or gid_t.
+ * Currently (2026-05-23) uid_t & gid_t is an uint32_t.
+ * Special case handle uid_t/gid_t numbers specified as negative numbers.
+ * Assumes that uid_t and gid_t are the same types.
+ */
+static int
+_invalid_uidgid(intmax_t v) {
+ if (v < 0) {
+ if ((-v) & ~(uintmax_t)((~(uid_t)0)>>1))
+ return (2); /* Underflow, does not fit into uid_t */
+ } else {
+ if (v & ~(uintmax_t)(~(uid_t)0))
+ return (1); /* Overflow, does not fit into uid_t */
+ }
+ return (0);
+}
+
+/*
* Given a username/groupname from a text form of an ACL, return the uid/gid
* XXX NOT THREAD SAFE, RELIES ON GETPWNAM, GETGRNAM
* XXX USES *PW* AND *GR* WHICH ARE STATEFUL AND THEREFORE THIS ROUTINE
@@ -274,19 +293,21 @@ _acl_name_to_id(acl_tag_t tag, char *name, uid_t *id)
{
struct group *g;
struct passwd *p;
- unsigned long l;
+ intmax_t v;
char *endp;
switch(tag) {
case ACL_USER:
p = getpwnam(name);
if (p == NULL) {
- l = strtoul(name, &endp, 0);
- if (*endp != '\0' || l != (unsigned long)(uid_t)l) {
- errno = EINVAL;
+ errno = 0;
+ v = strtoimax(name, &endp, 0);
+ if (name == endp || *endp != '\0' ||
+ errno == ERANGE || _invalid_uidgid(v) != 0) {
+ errno = EINVAL; /* No or invalid number */
return (-1);
}
- *id = (uid_t)l;
+ *id = v;
return (0);
}
*id = p->pw_uid;
@@ -295,12 +316,14 @@ _acl_name_to_id(acl_tag_t tag, char *name, uid_t *id)
case ACL_GROUP:
g = getgrnam(name);
if (g == NULL) {
- l = strtoul(name, &endp, 0);
- if (*endp != '\0' || l != (unsigned long)(gid_t)l) {
- errno = EINVAL;
+ errno = 0;
+ v = strtoimax(name, &endp, 0);
+ if (name == endp || *endp != '\0' ||
+ errno == ERANGE || _invalid_uidgid(v) != 0) {
+ errno = EINVAL; /* No or invalid number */
return (-1);
}
- *id = (gid_t)l;
+ *id = v;
return (0);
}
*id = g->gr_gid;