18static int owner(
int fd, uid_t uid, gid_t gid) {
20 return fstat(fd, &st) || st.st_uid != uid || st.st_gid != gid || (st.st_mode & 0777) != 0600;
22static void* isolated_fs(
void* opaque) {
24 int failed = 0, fd = -1;
25 CHECK(setfsuid(-1) == 70001 && setfsgid(-1) == 70002 && geteuid() == 0 && getegid() == 0);
26 CHECK(setfsuid(70003) == 70001 && setfsgid(70004) == 70002);
27 CHECK(!pm_send(args->report,
'r') && !pm_receive(args->command,
'p'));
28 CHECK(setfsuid(-1) == 70003 && setfsgid(-1) == 70004 && geteuid() == 0);
30 fd = open(args->owned, O_RDONLY | O_CLOEXEC);
31 CHECK(fd == -1 && errno == EACCES);
32 fd = open(args->created, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0600);
33 CHECK(fd >= 0 && !owner(fd, 70003, 70004));
34 CHECK(!pm_send(args->report,
's') && !pm_receive(args->command,
'v'));
35 CHECK(setfsuid(-1) == 0 && setfsgid(-1) == 0);
39 return (
void*)(uintptr_t)failed;
41int pm_fs_exec(
int argc,
char** argv) {
45 uid_t r, e, s, wanted_r = strtoul(argv[2], NULL, 10), wanted_e = strtoul(argv[3], NULL, 10);
46 gid_t gr, ge, gs, wanted_gr = strtoul(argv[4], NULL, 10), wanted_ge = strtoul(argv[5], NULL, 10);
47 CHECK(!getresuid(&r, &e, &s) && r == wanted_r && e == wanted_e && s == wanted_e);
48 CHECK(!getresgid(&gr, &ge, &gs) && gr == wanted_gr && ge == wanted_ge && gs == wanted_ge);
49 CHECK((uid_t)setfsuid(-1) == e && (gid_t)setfsgid(-1) == ge);
50 CHECK(prctl(PR_GET_DUMPABLE, 0UL, 0UL, 0UL, 0UL) == atoi(argv[6]));
51 CHECK(getauxval(AT_UID) == r && getauxval(AT_EUID) == e && getauxval(AT_GID) == gr &&
52 getauxval(AT_EGID) == ge);
56static int backend(
int disk) {
57 int failed = 0, root_fd = -1, owned_fd = -1, probe = -1, live = 0;
58 int command[2] = {-1, -1}, report[2] = {-1, -1};
62 char directory[128], root_path[160], owned_path[160], worker_path[160], private_dir[160],
63 nested[192], own_dir[160];
64 snprintf(directory,
sizeof(directory),
"%s/process-memory-fs-%d", disk ?
"" :
"/tmp", getpid());
65 snprintf(root_path,
sizeof(root_path),
"%s/root", directory);
66 snprintf(owned_path,
sizeof(owned_path),
"%s/owned", directory);
67 snprintf(worker_path,
sizeof(worker_path),
"%s/thread", directory);
68 snprintf(private_dir,
sizeof(private_dir),
"%s/private", directory);
69 snprintf(nested,
sizeof(nested),
"%s/file", private_dir);
70 snprintf(own_dir,
sizeof(own_dir),
"%s/owned-dir", directory);
71 CHECK(getuid() == 0 && geteuid() == 0 && getgid() == 0 && getegid() == 0);
72 CHECK(!mkdir(directory, 0777) && !chmod(directory, 0777));
73 root_fd = open(root_path, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0600);
74 CHECK(root_fd >= 0 && !owner(root_fd, 0, 0));
75 CHECK(!mkdir(private_dir, 0700));
76 probe = open(nested, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0644);
77 CHECK(probe >= 0 && !close(probe));
79 CHECK(!pm_dumpable(1));
80 CHECK(setfsuid(70001) == 0 && setfsgid(70002) == 0);
81 CHECK(getuid() == 0 && geteuid() == 0 && getgid() == 0 && getegid() == 0);
82 CHECK(prctl(PR_GET_DUMPABLE, 0UL, 0UL, 0UL, 0UL) == 0);
84 probe = open(root_path, O_RDONLY | O_CLOEXEC);
85 CHECK(probe == -1 && errno == EACCES);
86 CHECK(!access(nested, R_OK));
87 CHECK(setfsuid(-1) == 70001 && setfsgid(-1) == 70002);
89 CHECK(faccessat(AT_FDCWD, nested, R_OK, AT_EACCESS) == -1 && errno == EACCES);
91 probe = open(nested, O_RDONLY | O_CLOEXEC);
92 CHECK(probe == -1 && errno == EACCES);
93 owned_fd = open(owned_path, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0600);
94 CHECK(owned_fd >= 0 && !owner(owned_fd, 70001, 70002));
95 CHECK(!mkdir(own_dir, 0700));
96 struct stat directory_stat;
97 CHECK(!stat(own_dir, &directory_stat) && S_ISDIR(directory_stat.st_mode) &&
98 directory_stat.st_uid == 70001 && directory_stat.st_gid == 70002 &&
99 (directory_stat.st_mode & 0777) == 0700);
100 CHECK(!pm_write(owned_fd,
"f", 1));
101 probe = open(owned_path, O_RDONLY | O_CLOEXEC);
102 CHECK(probe >= 0 && !close(probe));
104 CHECK(!fchmod(owned_fd, 0040) && setfsuid(70003) == 70001);
105 probe = open(owned_path, O_RDONLY | O_CLOEXEC);
106 CHECK(probe >= 0 && !close(probe));
108 CHECK(setfsgid(70004) == 70002);
110 probe = open(owned_path, O_RDONLY | O_CLOEXEC);
111 CHECK(probe == -1 && errno == EACCES);
112 CHECK(setfsuid(70001) == 70003 && setfsgid(70002) == 70004 && !fchmod(owned_fd, 0600));
113 CHECK(!pipe(command) && !pipe(report));
114 struct fs_thread arguments = {command[0], report[1], owned_path, worker_path};
115 CHECK(!pthread_create(&thread, NULL, isolated_fs, &arguments));
117 CHECK(!pm_receive(report[0],
'r'));
118 CHECK(setfsuid(-1) == 70001 && setfsgid(-1) == 70002);
119 probe = open(owned_path, O_RDONLY | O_CLOEXEC);
120 CHECK(probe >= 0 && !close(probe));
122 CHECK(setfsuid(70005) == 70001 && setfsgid(70006) == 70002);
123 CHECK(!pm_send(command[1],
'p') && !pm_receive(report[0],
's'));
125 CHECK(!seteuid(0) && !setegid(0) && setfsuid(-1) == 0 && setfsgid(-1) == 0);
126 CHECK(!pm_send(command[1],
'v') && !pthread_join(thread, &thread_result));
128 CHECK(thread_result == NULL && setfsuid(70005) == 0 && setfsgid(70006) == 0);
132 if (setfsuid(-1) != 70005 || setfsgid(-1) != 70006 || geteuid() != 0 || getegid() != 0)
134 execl(PM_APP, PM_APP,
"fs-exec",
"0",
"0",
"0",
"0",
"1", (
char*)NULL);
137 int status = pm_reap(child, 10000);
139 CHECK(status == 0 && setfsuid(-1) == 70005 && setfsgid(-1) == 70006);
140 CHECK(setfsuid(0) == 70005 && setfsgid(0) == 70006);
141 probe = open(worker_path, O_RDONLY | O_CLOEXEC);
142 CHECK(probe >= 0 && !owner(probe, 70003, 70004));
143 CHECK(!fsync(owned_fd));
146 pm_send(command[1],
'p');
147 pthread_join(thread, NULL);
153 for (
int n = 0; n < 2; ++n) {
174int pm_filesystem(
void) {
175 return backend(0) || backend(1);