11static int owner_checks(
struct xa_file* files,
int read_fd) {
13 const char* names[] = {
"user.keep"};
14 CHECK(!xa_unprivileged(60001, 60001, NULL, 0));
15 CHECK(fgetxattr(read_fd,
"user.keep", NULL, 0) == -1 && errno == EACCES);
16 struct xa_file readonly = files[0];
17 readonly.fd = read_fd;
18 CHECK(!xa_names(&readonly, XA_FD, names, 1));
19 CHECK(!fsetxattr(read_fd,
"user.keep",
"w", 1, XATTR_REPLACE));
20 CHECK(!fremovexattr(read_fd,
"user.keep"));
21 CHECK(!setxattr(files[0].path,
"user.path",
"p", 1, 0));
22 CHECK(!lremovexattr(files[0].path,
"user.path"));
23 CHECK(!xa_value(&files[1], XA_FD,
"user.keep",
"k", 1));
24 CHECK(fsetxattr(files[1].fd,
"user.keep",
"x", 1, 0) == -1 && errno == EACCES);
25 CHECK(removexattr(files[1].path,
"user.keep") == -1 && errno == EACCES);
26 CHECK(fgetxattr(files[2].fd,
"user.keep", NULL, 0) == -1 && errno == EACCES);
27 CHECK(fsetxattr(files[2].fd,
"user.keep",
"x", 1, 0) == -1 && errno == EACCES);
28 CHECK(!xa_names(&files[2], XA_FD, names, 1));
29 CHECK(!xa_names(&files[2], XA_PATH, names, 1));
34static int current_permissions(
int backend) {
35 int failed = 0, read_fd = -1;
37 struct xa_file files[3] = {{.fd = -1}, {.fd = -1}, {.fd = -1}};
38 const mode_t modes[] = {0200, 0400, 0000};
39 for (
int n = 0; n < 3; ++n) {
40 CHECK(!xa_create(&files[n], backend, 0));
41 CHECK(!fsetxattr(files[n].fd,
"user.keep",
"k", 1, 0));
43 CHECK((read_fd = open(files[n].path, O_RDONLY | O_CLOEXEC)) >= 0);
44 CHECK(!fchown(files[n].fd, 60001, 60001));
45 CHECK(!fchmod(files[n].fd, modes[n]));
47 CHECK(!fstat(files[n].fd, &status));
48 CHECK(status.st_uid == 60001 && status.st_gid == 60001 && (status.st_mode & 0777) == modes[n]);
50 CHECK((child = fork()) >= 0);
52 _exit(owner_checks(files, read_fd));
53 int result = xa_reap(child, 8000);
56 CHECK(fgetxattr(files[0].fd,
"user.keep", NULL, 0) == -1 && errno == ENODATA);
57 CHECK(!xa_value(&files[1], XA_FD,
"user.keep",
"k", 1));
65 for (
int n = 0; n < 3; ++n)
70static int group_checks(
struct xa_file* file,
int member) {
72 const gid_t group = 60003;
73 CHECK(!xa_unprivileged(60001, 60001, member ? &group : NULL, member ? 1 : 0));
75 CHECK(!xa_value(file, XA_FD,
"user.group",
"g", 1));
76 CHECK(!setxattr(file->path,
"user.group",
"G", 1, XATTR_REPLACE));
78 CHECK(fgetxattr(file->fd,
"user.group", NULL, 0) == -1 && errno == EACCES);
79 CHECK(fsetxattr(file->fd,
"user.group",
"x", 1, 0) == -1 && errno == EACCES);
80 CHECK(fremovexattr(file->fd,
"user.group") == -1 && errno == EACCES);
86static int supplementary_group(
int backend) {
89 struct xa_file file = {.fd = -1};
90 CHECK(!xa_create(&file, backend, 0));
91 CHECK(!fsetxattr(file.fd,
"user.group",
"g", 1, 0));
92 CHECK(!fchown(file.fd, 60002, 60003));
93 CHECK(!fchmod(file.fd, 0660));
94 for (
int member = 0; member < 2; ++member) {
95 CHECK((child = fork()) >= 0);
97 _exit(group_checks(&file, member));
98 int result = xa_reap(child, 8000);
102 CHECK(!xa_value(&file, XA_FD,
"user.group",
"G", 1));
105 kill(child, SIGKILL);
106 xa_reap(child, 1000);
114 const char* names[] = {
"user.directory"};
115 CHECK(!xa_unprivileged(60001, 60001, NULL, 0));
116 CHECK(!xa_value(sticky, XA_PATH,
"user.directory",
"d", 1));
117 CHECK(!xa_names(sticky, XA_LINK, names, 1));
118 CHECK(fsetxattr(sticky->fd,
"user.directory",
"x", 1, 0) == -1 && errno == EPERM);
119 CHECK(lremovexattr(sticky->path,
"user.directory") == -1 && errno == EPERM);
120 CHECK(!fsetxattr(owned->fd,
"user.owner",
"o", 1, 0));
121 CHECK(!xa_value(owned, XA_PATH,
"user.owner",
"o", 1));
122 CHECK(!lremovexattr(owned->path,
"user.owner"));
123 CHECK(getxattr(hidden->path,
"user.hidden", NULL, 0) == -1 && errno == EACCES);
124 CHECK(llistxattr(hidden->path, NULL, 0) == -1 && errno == EACCES);
125 CHECK(!xa_value(hidden, XA_FD,
"user.hidden",
"h", 1));
130static int directories(
int backend) {
133 struct xa_file sticky = {.fd = -1}, owned = {.fd = -1}, parent = {.fd = -1};
134 struct xa_file hidden = {.fd = -1};
135 CHECK(!xa_create(&sticky, backend, 1));
136 CHECK(!xa_create(&owned, backend, 1));
137 CHECK(!xa_create(&parent, backend, 1));
138 for (
int how = XA_PATH; how <= XA_FD; ++how) {
139 CHECK(!xa_set(&sticky, how,
"user.directory",
"d", 1, XATTR_CREATE));
140 CHECK(!xa_value(&sticky, how,
"user.directory",
"d", 1));
141 CHECK(!xa_remove(&sticky, how,
"user.directory"));
143 CHECK(!fsetxattr(sticky.fd,
"user.directory",
"d", 1, 0));
144 CHECK(!fchmod(sticky.fd, 01777));
145 CHECK(!fchown(owned.fd, 60001, 60001));
146 CHECK(!fchmod(owned.fd, 01777));
147 hidden.backend = backend;
148 CHECK(snprintf(hidden.path,
sizeof(hidden.path),
"%s/child", parent.path) <
149 (
int)
sizeof(hidden.path));
150 CHECK((hidden.fd = open(hidden.path, O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0600)) >= 0);
151 CHECK(!fchmod(hidden.fd, 0666));
152 CHECK(!fsetxattr(hidden.fd,
"user.hidden",
"h", 1, 0));
153 CHECK((child = fork()) >= 0);
155 _exit(directory_child(&sticky, &owned, &hidden));
156 int result = xa_reap(child, 8000);
161 kill(child, SIGKILL);
162 xa_reap(child, 1000);
171static int fifo_policy(
void) {
174 snprintf(path,
sizeof(path),
"/tmp/xattr-fifo-%ld", (
long)getpid());
175 CHECK(!mkfifo(path, 0600));
176 CHECK(getxattr(path,
"user.fifo", NULL, 0) == -1 && errno == ENODATA);
177 CHECK(setxattr(path,
"user.fifo",
"f", 1, 0) == -1 && errno == EPERM);
178 CHECK(lremovexattr(path,
"user.fifo") == -1 && errno == EPERM);
184int xa_permissions(
void) {
185 for (
int backend = XA_RAMFS; backend <= XA_EXT2; ++backend)
186 if (current_permissions(backend) || supplementary_group(backend) || directories(backend))
188 return fifo_policy();