[Toybox] [PATCH] Correct Setting of uid and gid when extracting CPIO archive
Mike Moreton
Mike.Moreton at frontier-silicon.com
Mon Dec 7 02:14:40 PST 2015
Hi Rob,
> 2) I don't understand this bit:
On the Linux I'm running O_WRONLY failed ("Is a directory") and O_RDONLY worked, and I admit I didn't dig too deeply...
I don't have any problem opening a directory with mode 0000 O_RDONLY as root - I've attached a test program that can be run with:
cc -o testit -Wall testit.c && sudo ./testit O_RDONLY 0000
Could it be this was only a problem before the getpid/geteuid change?
> I try to keep the code within 80 chars. Code style thing. This goes way off the right edge without rewrapping.
Sorry - other stuff I'm working on uses longer lines - I'll try to remember!
> I generally put the local variable tests _before_ the tests that potentially generate system calls, because && preserves side effects so the left side does get evaluated even if the right will always fail.
Sounds eminently sensible!
Mike.
-----Original Message-----
From: Rob Landley [mailto:rob at landley.net]
Sent: 06 December 2015 22:04
To: Mike Moreton <Mike.Moreton at frontier-silicon.com>; toybox at lists.landley.net
Subject: Re: [Toybox] [PATCH] Correct Setting of uid and gid when extracting CPIO archive
On 12/02/2015 07:39 AM, Mike Moreton wrote:
> Hi, I've fixed a couple of bugs in cpio.
Thanks, I applied both patches. Several good fixes here in the "I don't know how this ever worked before" category, but:
1) git am says it doesn't have a valid email address. (I fixed that up to get it to apply.)
2) I don't understand this bit:
- if (!S_ISREG(mode) && !S_ISLNK(mode) && !getpid()) {
- int fd = open(name, O_WRONLY|O_NOFOLLOW);
+ if (!S_ISREG(mode) && !S_ISLNK(mode) && !geteuid()) {
+ int fd = open(name, O_RDONLY|O_NOFOLLOW);
The purpose of the filehandle is to call fchown() on it. Can we change ownership through a read only filehandle? (The kernel not only allows this now but will continue to allow this in future?)
The O_WRONLY was also there because you can create a node or directory without the read bit set, in which case attempting to open it for read access fails.
I'd really like to do this via O_PATH, but trying to gave me errno EBADF. And it turns out that the bionic workaround of doing:
fd = open("file", O_PATH)
sprintf(buf, "/proc/self/fd/%d");
fd2 = open(buf, O_RDONLY);
Does the proper permissions checks on the second open (good!) which means that using O_PATH to try to reliably affect the metadata of chmod
000 files STILL DOESN'T WORK. Grrr. I expect I have to create directories and nodes chmod u+w and then chmod them again to the final version later. I can presumably add some extra tests to make this only happen when necessary...
Minor comments on second patch:
I try to keep the code within 80 chars. Code style thing. This goes way off the right edge without rewrapping.
I generally put the local variable tests _before_ the tests that potentially generate system calls, because && preserves side effects so the left side does get evaluated even if the right will always fail.
(Fairly minor nitpick.)
Thanks,
Rob
-------------- next part --------------
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#define MY_TEST_DIR_NAME "my_test_dir"
#define MY_TEST_UID_1 42
#define MY_TEST_UID_2 43
#define MY_TEST_GROUP 2222
static void testDir(int flags)
{
system("ls -ld " MY_TEST_DIR_NAME);
/*
* Open the directory.
*/
int fd = open(MY_TEST_DIR_NAME, flags | O_NOFOLLOW);
if (fd < 0) {
fprintf(stderr, "Couldn't open directory (%s)\n", strerror(errno));
return;
}
system("ls -ld " MY_TEST_DIR_NAME);
/*
* Give it away.
*/
if (fchown(fd, MY_TEST_UID_1, MY_TEST_GROUP) != 0) {
fprintf(stderr, "Can't do first change of ownership (%s)\n",
strerror(errno));
close(fd);
return;
}
system("ls -ld " MY_TEST_DIR_NAME);
/*
* Give it away again.
*/
if (fchown(fd, MY_TEST_UID_2, MY_TEST_GROUP) != 0) {
fprintf(stderr, "Can't do second change of ownership (%s)\n",
strerror(errno));
close(fd);
return;
}
system("ls -ld " MY_TEST_DIR_NAME);
printf("All OK!\n");
close(fd);
}
int main(int argc, char ** argv)
{
/*
* Parse the args.
*/
if (argc != 3) {
fprintf(stderr, "Usage: %s [O_RDONLY|O_WRONLY] mode\n", argv[0]);
exit(1);
}
int flags;
if (strcmp(argv[1], "O_RDONLY") == 0) {
flags = O_RDONLY;
} else if (strcmp(argv[1], "O_WRONLY") == 0) {
flags = O_WRONLY;
} else {
fprintf(stderr, "Argument must be O_RDONLY or O_WRONLY\n");
exit(1);
}
int mode = (int)strtol(argv[2], NULL, 0);
/*
* Will only work as root.
*/
if (geteuid() != 0) {
fprintf(stderr, "Must run test as root.\n");
exit(1);
}
/*
* Create a directory.
*/
if (mkdir(MY_TEST_DIR_NAME, mode) < 0) {
fprintf(stderr, "Can't create directory(%s)\n", strerror(errno));
exit(1);
}
testDir(flags);
/*
* Delete the directory.
*/
if (rmdir(MY_TEST_DIR_NAME) < 0) {
fprintf(stderr, "Can't delete directory(%s)\n", strerror(errno));
exit(1);
}
exit(0);
}
More information about the Toybox
mailing list