Skip to content

Commit cb9e44d

Browse files
committed
test: add test case for recursive chown()ing
1 parent cd6b7d5 commit cb9e44d

File tree

2 files changed

+165
-0
lines changed

2 files changed

+165
-0
lines changed

src/test/meson.build

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ tests += [
6868
libshared],
6969
[]],
7070

71+
[['src/test/test-chown-rec.c'],
72+
[libcore,
73+
libshared],
74+
[]],
75+
7176
[['src/test/test-job-type.c'],
7277
[libcore,
7378
libshared],

src/test/test-chown-rec.c

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
/* SPDX-License-Identifier: LGPL-2.1+ */
2+
3+
#include <sys/xattr.h>
4+
5+
#include "alloc-util.h"
6+
#include "chown-recursive.h"
7+
#include "fileio.h"
8+
#include "log.h"
9+
#include "rm-rf.h"
10+
#include "string-util.h"
11+
#include "tests.h"
12+
13+
static const uint8_t acl[] = {
14+
0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00,
15+
0xff, 0xff, 0xff, 0xff, 0x02, 0x00, 0x07, 0x00,
16+
0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x07, 0x00,
17+
0xff, 0xff, 0xff, 0xff, 0x10, 0x00, 0x07, 0x00,
18+
0xff, 0xff, 0xff, 0xff, 0x20, 0x00, 0x05, 0x00,
19+
0xff, 0xff, 0xff, 0xff,
20+
};
21+
22+
static const uint8_t default_acl[] = {
23+
0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00,
24+
0xff, 0xff, 0xff, 0xff, 0x04, 0x00, 0x07, 0x00,
25+
0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x07, 0x00,
26+
0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x07, 0x00,
27+
0xff, 0xff, 0xff, 0xff, 0x20, 0x00, 0x05, 0x00,
28+
0xff, 0xff, 0xff, 0xff,
29+
};
30+
31+
static bool has_xattr(const char *p) {
32+
char buffer[sizeof(acl) * 4];
33+
34+
if (lgetxattr(p, "system.posix_acl_access", buffer, sizeof(buffer)) < 0) {
35+
if (IN_SET(errno, EOPNOTSUPP, ENOTTY, ENODATA, ENOSYS))
36+
return false;
37+
}
38+
39+
return true;
40+
}
41+
42+
static void test_chown_recursive(void) {
43+
_cleanup_(rm_rf_physical_and_freep) char *t = NULL;
44+
struct stat st;
45+
const char *p;
46+
47+
umask(022);
48+
assert_se(mkdtemp_malloc(NULL, &t) >= 0);
49+
50+
p = strjoina(t, "/dir");
51+
assert_se(mkdir(p, 0777) >= 0);
52+
assert_se(lstat(p, &st) >= 0);
53+
assert_se(S_ISDIR(st.st_mode));
54+
assert_se((st.st_mode & 07777) == 0755);
55+
assert_se(st.st_uid == 0);
56+
assert_se(st.st_gid == 0);
57+
assert_se(!has_xattr(p));
58+
59+
p = strjoina(t, "/dir/symlink");
60+
assert_se(symlink("../../", p) >= 0);
61+
assert_se(lstat(p, &st) >= 0);
62+
assert_se(S_ISLNK(st.st_mode));
63+
assert_se((st.st_mode & 07777) == 0777);
64+
assert_se(st.st_uid == 0);
65+
assert_se(st.st_gid == 0);
66+
assert_se(!has_xattr(p));
67+
68+
p = strjoina(t, "/dir/reg");
69+
assert_se(mknod(p, S_IFREG|0777, 0) >= 0);
70+
assert_se(lstat(p, &st) >= 0);
71+
assert_se(S_ISREG(st.st_mode));
72+
assert_se((st.st_mode & 07777) == 0755);
73+
assert_se(st.st_uid == 0);
74+
assert_se(st.st_gid == 0);
75+
assert_se(!has_xattr(p));
76+
77+
p = strjoina(t, "/dir/sock");
78+
assert_se(mknod(p, S_IFSOCK|0777, 0) >= 0);
79+
assert_se(lstat(p, &st) >= 0);
80+
assert_se(S_ISSOCK(st.st_mode));
81+
assert_se((st.st_mode & 07777) == 0755);
82+
assert_se(st.st_uid == 0);
83+
assert_se(st.st_gid == 0);
84+
assert_se(!has_xattr(p));
85+
86+
p = strjoina(t, "/dir/fifo");
87+
assert_se(mknod(p, S_IFIFO|0777, 0) >= 0);
88+
assert_se(lstat(p, &st) >= 0);
89+
assert_se(S_ISFIFO(st.st_mode));
90+
assert_se((st.st_mode & 07777) == 0755);
91+
assert_se(st.st_uid == 0);
92+
assert_se(st.st_gid == 0);
93+
assert_se(!has_xattr(p));
94+
95+
/* We now apply an xattr to the dir, and check it again */
96+
p = strjoina(t, "/dir");
97+
assert_se(setxattr(p, "system.posix_acl_access", acl, sizeof(acl), 0) >= 0);
98+
assert_se(setxattr(p, "system.posix_acl_default", default_acl, sizeof(default_acl), 0) >= 0);
99+
assert_se(lstat(p, &st) >= 0);
100+
assert_se(S_ISDIR(st.st_mode));
101+
assert_se((st.st_mode & 07777) == 0775); /* acl change changed the mode too */
102+
assert_se(st.st_uid == 0);
103+
assert_se(st.st_gid == 0);
104+
assert_se(has_xattr(p));
105+
106+
assert_se(path_chown_recursive(t, 1, 2) >= 0);
107+
108+
p = strjoina(t, "/dir");
109+
assert_se(lstat(p, &st) >= 0);
110+
assert_se(S_ISDIR(st.st_mode));
111+
assert_se((st.st_mode & 07777) == 0775);
112+
assert_se(st.st_uid == 1);
113+
assert_se(st.st_gid == 2);
114+
assert_se(!has_xattr(p));
115+
116+
p = strjoina(t, "/dir/symlink");
117+
assert_se(lstat(p, &st) >= 0);
118+
assert_se(S_ISLNK(st.st_mode));
119+
assert_se((st.st_mode & 07777) == 0777);
120+
assert_se(st.st_uid == 1);
121+
assert_se(st.st_gid == 2);
122+
assert_se(!has_xattr(p));
123+
124+
p = strjoina(t, "/dir/reg");
125+
assert_se(lstat(p, &st) >= 0);
126+
assert_se(S_ISREG(st.st_mode));
127+
assert_se((st.st_mode & 07777) == 0755);
128+
assert_se(st.st_uid == 1);
129+
assert_se(st.st_gid == 2);
130+
assert_se(!has_xattr(p));
131+
132+
p = strjoina(t, "/dir/sock");
133+
assert_se(lstat(p, &st) >= 0);
134+
assert_se(S_ISSOCK(st.st_mode));
135+
assert_se((st.st_mode & 07777) == 0755);
136+
assert_se(st.st_uid == 1);
137+
assert_se(st.st_gid == 2);
138+
assert_se(!has_xattr(p));
139+
140+
p = strjoina(t, "/dir/fifo");
141+
assert_se(lstat(p, &st) >= 0);
142+
assert_se(S_ISFIFO(st.st_mode));
143+
assert_se((st.st_mode & 07777) == 0755);
144+
assert_se(st.st_uid == 1);
145+
assert_se(st.st_gid == 2);
146+
assert_se(!has_xattr(p));
147+
}
148+
149+
int main(int argc, char *argv[]) {
150+
log_set_max_level(LOG_DEBUG);
151+
log_parse_environment();
152+
log_open();
153+
154+
if (geteuid() != 0)
155+
return log_tests_skipped("not running as root");
156+
157+
test_chown_recursive();
158+
159+
return EXIT_SUCCESS;
160+
}

0 commit comments

Comments
 (0)