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...
Details
- Reviewers
rmacklem
Make sure this works:
# mkdir testdir # setfacl -a0 group:-1294967291:rwxpDdaARWcCos:fd-----:allow testdir
Diff Detail
- Lint
Lint Skipped - Unit
Tests Skipped
Event Timeline
| lib/libc/posix1e/acl_from_text.c | ||
|---|---|---|
| 285 | Although this does the trick, I don't see any Another words, just replace line#284 in the old | |
| 302 | Same as above. | |
Oh, and I'd leave the comment (or something like it)
in the code, so that it is obvious why the cast'ng is done.
Thanks, rick
| lib/libc/posix1e/acl_from_text.c | ||
|---|---|---|
| 288 | The second part of the conditional I cannot see why "-" ids shouldn't be | |
Hmm.. Yeah, I didn't want to change that part of the code. But now when I read the fine print in the man page for strtoul() and strtol() I think we should just get rid of that extra check and just use "*endp != '\0'"...
Hmm.. Shouldn't we use strtoumax() and strtoimax() while we're at it...? Perhaps something like:
intmax_t iv;
uintmax_t uv;
uid_t id;
...
if (*name == -) {
iv = strtoimax(name,&endp,0);
} else {
uv = strtoumax(name,&endp,0);
}
if (name == endp || *endp != '\0') {
errno = EINVAL; /* No or invalid number */
return (-1);
}
if (*name == '-') {
id = iv;
if (int32_t) id != iv) {
errno = EINVAL; /* Overflow */
return (-1);
}
} else {
id = uv;
if (id != uv) {
errno = EINVAL; /* Overflow */
return (-1);
}
}Hmm.. Not sure (or I'm too tired right now) how to write a better and fully portably check for under/overflow in the negative case that works if we get 64 bit uid_t/gid_t. :-)
Since "long" is already 64bits on most arches (except armv7?),
I think leaving it as "long" is fine.
As for allowing a negative value, but catching overflows,
I think the easiest way is to define a long variable,
such as l0 and then changing the code to:
long l0; /* added for range check */
l = l0 = strtoul(name, &endp, 0);
if (*endp != '\0' || l0 < INT32_MIN || l0 > UID_MAX)
This seems to work for a small test program.
(I'll admit I came up with a couple of incorrect ones
before I tried this straightforward version.)
There isn't any UID_MIN defined, but limiting it
to INT32_MIN seems reasonable to me?
| lib/libc/posix1e/acl_from_text.c | ||
|---|---|---|
| 288 |
Yea, ignore my above comment. I now realize the | |
| lib/libc/posix1e/acl_from_text.c | ||
|---|---|---|
| 272 | You could make this a "static bool", I think? | |