1*0f71241aSKees Cook // SPDX-License-Identifier: GPL-2.0+
2*0f71241aSKees Cook #include <errno.h>
3*0f71241aSKees Cook #include <fcntl.h>
4*0f71241aSKees Cook #include <stdio.h>
5*0f71241aSKees Cook #include <string.h>
6*0f71241aSKees Cook #include <unistd.h>
7*0f71241aSKees Cook #include <sys/socket.h>
8*0f71241aSKees Cook #include <sys/stat.h>
9*0f71241aSKees Cook #include <sys/sysmacros.h>
10*0f71241aSKees Cook #include <sys/types.h>
11*0f71241aSKees Cook
12*0f71241aSKees Cook #include "../kselftest_harness.h"
13*0f71241aSKees Cook
14*0f71241aSKees Cook /* Remove a file, ignoring the result if it didn't exist. */
rm(struct __test_metadata * _metadata,const char * pathname,int is_dir)15*0f71241aSKees Cook void rm(struct __test_metadata *_metadata, const char *pathname,
16*0f71241aSKees Cook int is_dir)
17*0f71241aSKees Cook {
18*0f71241aSKees Cook int rc;
19*0f71241aSKees Cook
20*0f71241aSKees Cook if (is_dir)
21*0f71241aSKees Cook rc = rmdir(pathname);
22*0f71241aSKees Cook else
23*0f71241aSKees Cook rc = unlink(pathname);
24*0f71241aSKees Cook
25*0f71241aSKees Cook if (rc < 0) {
26*0f71241aSKees Cook ASSERT_EQ(errno, ENOENT) {
27*0f71241aSKees Cook TH_LOG("Not ENOENT: %s", pathname);
28*0f71241aSKees Cook }
29*0f71241aSKees Cook } else {
30*0f71241aSKees Cook ASSERT_EQ(rc, 0) {
31*0f71241aSKees Cook TH_LOG("Failed to remove: %s", pathname);
32*0f71241aSKees Cook }
33*0f71241aSKees Cook }
34*0f71241aSKees Cook }
35*0f71241aSKees Cook
FIXTURE(file)36*0f71241aSKees Cook FIXTURE(file) {
37*0f71241aSKees Cook char *pathname;
38*0f71241aSKees Cook int is_dir;
39*0f71241aSKees Cook };
40*0f71241aSKees Cook
FIXTURE_VARIANT(file)41*0f71241aSKees Cook FIXTURE_VARIANT(file)
42*0f71241aSKees Cook {
43*0f71241aSKees Cook const char *name;
44*0f71241aSKees Cook int expected;
45*0f71241aSKees Cook int is_dir;
46*0f71241aSKees Cook void (*setup)(struct __test_metadata *_metadata,
47*0f71241aSKees Cook FIXTURE_DATA(file) *self,
48*0f71241aSKees Cook const FIXTURE_VARIANT(file) *variant);
49*0f71241aSKees Cook int major, minor, mode; /* for mknod() */
50*0f71241aSKees Cook };
51*0f71241aSKees Cook
setup_link(struct __test_metadata * _metadata,FIXTURE_DATA (file)* self,const FIXTURE_VARIANT (file)* variant)52*0f71241aSKees Cook void setup_link(struct __test_metadata *_metadata,
53*0f71241aSKees Cook FIXTURE_DATA(file) *self,
54*0f71241aSKees Cook const FIXTURE_VARIANT(file) *variant)
55*0f71241aSKees Cook {
56*0f71241aSKees Cook const char * const paths[] = {
57*0f71241aSKees Cook "/bin/true",
58*0f71241aSKees Cook "/usr/bin/true",
59*0f71241aSKees Cook };
60*0f71241aSKees Cook int i;
61*0f71241aSKees Cook
62*0f71241aSKees Cook for (i = 0; i < ARRAY_SIZE(paths); i++) {
63*0f71241aSKees Cook if (access(paths[i], X_OK) == 0) {
64*0f71241aSKees Cook ASSERT_EQ(symlink(paths[i], self->pathname), 0);
65*0f71241aSKees Cook return;
66*0f71241aSKees Cook }
67*0f71241aSKees Cook }
68*0f71241aSKees Cook ASSERT_EQ(1, 0) {
69*0f71241aSKees Cook TH_LOG("Could not find viable 'true' binary");
70*0f71241aSKees Cook }
71*0f71241aSKees Cook }
72*0f71241aSKees Cook
FIXTURE_VARIANT_ADD(file,S_IFLNK)73*0f71241aSKees Cook FIXTURE_VARIANT_ADD(file, S_IFLNK)
74*0f71241aSKees Cook {
75*0f71241aSKees Cook .name = "S_IFLNK",
76*0f71241aSKees Cook .expected = ELOOP,
77*0f71241aSKees Cook .setup = setup_link,
78*0f71241aSKees Cook };
79*0f71241aSKees Cook
setup_dir(struct __test_metadata * _metadata,FIXTURE_DATA (file)* self,const FIXTURE_VARIANT (file)* variant)80*0f71241aSKees Cook void setup_dir(struct __test_metadata *_metadata,
81*0f71241aSKees Cook FIXTURE_DATA(file) *self,
82*0f71241aSKees Cook const FIXTURE_VARIANT(file) *variant)
83*0f71241aSKees Cook {
84*0f71241aSKees Cook ASSERT_EQ(mkdir(self->pathname, 0755), 0);
85*0f71241aSKees Cook }
86*0f71241aSKees Cook
FIXTURE_VARIANT_ADD(file,S_IFDIR)87*0f71241aSKees Cook FIXTURE_VARIANT_ADD(file, S_IFDIR)
88*0f71241aSKees Cook {
89*0f71241aSKees Cook .name = "S_IFDIR",
90*0f71241aSKees Cook .is_dir = 1,
91*0f71241aSKees Cook .expected = EACCES,
92*0f71241aSKees Cook .setup = setup_dir,
93*0f71241aSKees Cook };
94*0f71241aSKees Cook
setup_node(struct __test_metadata * _metadata,FIXTURE_DATA (file)* self,const FIXTURE_VARIANT (file)* variant)95*0f71241aSKees Cook void setup_node(struct __test_metadata *_metadata,
96*0f71241aSKees Cook FIXTURE_DATA(file) *self,
97*0f71241aSKees Cook const FIXTURE_VARIANT(file) *variant)
98*0f71241aSKees Cook {
99*0f71241aSKees Cook dev_t dev;
100*0f71241aSKees Cook int rc;
101*0f71241aSKees Cook
102*0f71241aSKees Cook dev = makedev(variant->major, variant->minor);
103*0f71241aSKees Cook rc = mknod(self->pathname, 0755 | variant->mode, dev);
104*0f71241aSKees Cook ASSERT_EQ(rc, 0) {
105*0f71241aSKees Cook if (errno == EPERM)
106*0f71241aSKees Cook SKIP(return, "Please run as root; cannot mknod(%s)",
107*0f71241aSKees Cook variant->name);
108*0f71241aSKees Cook }
109*0f71241aSKees Cook }
110*0f71241aSKees Cook
FIXTURE_VARIANT_ADD(file,S_IFBLK)111*0f71241aSKees Cook FIXTURE_VARIANT_ADD(file, S_IFBLK)
112*0f71241aSKees Cook {
113*0f71241aSKees Cook .name = "S_IFBLK",
114*0f71241aSKees Cook .expected = EACCES,
115*0f71241aSKees Cook .setup = setup_node,
116*0f71241aSKees Cook /* /dev/loop0 */
117*0f71241aSKees Cook .major = 7,
118*0f71241aSKees Cook .minor = 0,
119*0f71241aSKees Cook .mode = S_IFBLK,
120*0f71241aSKees Cook };
121*0f71241aSKees Cook
FIXTURE_VARIANT_ADD(file,S_IFCHR)122*0f71241aSKees Cook FIXTURE_VARIANT_ADD(file, S_IFCHR)
123*0f71241aSKees Cook {
124*0f71241aSKees Cook .name = "S_IFCHR",
125*0f71241aSKees Cook .expected = EACCES,
126*0f71241aSKees Cook .setup = setup_node,
127*0f71241aSKees Cook /* /dev/zero */
128*0f71241aSKees Cook .major = 1,
129*0f71241aSKees Cook .minor = 5,
130*0f71241aSKees Cook .mode = S_IFCHR,
131*0f71241aSKees Cook };
132*0f71241aSKees Cook
setup_fifo(struct __test_metadata * _metadata,FIXTURE_DATA (file)* self,const FIXTURE_VARIANT (file)* variant)133*0f71241aSKees Cook void setup_fifo(struct __test_metadata *_metadata,
134*0f71241aSKees Cook FIXTURE_DATA(file) *self,
135*0f71241aSKees Cook const FIXTURE_VARIANT(file) *variant)
136*0f71241aSKees Cook {
137*0f71241aSKees Cook ASSERT_EQ(mkfifo(self->pathname, 0755), 0);
138*0f71241aSKees Cook }
139*0f71241aSKees Cook
FIXTURE_VARIANT_ADD(file,S_IFIFO)140*0f71241aSKees Cook FIXTURE_VARIANT_ADD(file, S_IFIFO)
141*0f71241aSKees Cook {
142*0f71241aSKees Cook .name = "S_IFIFO",
143*0f71241aSKees Cook .expected = EACCES,
144*0f71241aSKees Cook .setup = setup_fifo,
145*0f71241aSKees Cook };
146*0f71241aSKees Cook
FIXTURE_SETUP(file)147*0f71241aSKees Cook FIXTURE_SETUP(file)
148*0f71241aSKees Cook {
149*0f71241aSKees Cook ASSERT_GT(asprintf(&self->pathname, "%s.test", variant->name), 6);
150*0f71241aSKees Cook self->is_dir = variant->is_dir;
151*0f71241aSKees Cook
152*0f71241aSKees Cook rm(_metadata, self->pathname, variant->is_dir);
153*0f71241aSKees Cook variant->setup(_metadata, self, variant);
154*0f71241aSKees Cook }
155*0f71241aSKees Cook
FIXTURE_TEARDOWN(file)156*0f71241aSKees Cook FIXTURE_TEARDOWN(file)
157*0f71241aSKees Cook {
158*0f71241aSKees Cook rm(_metadata, self->pathname, self->is_dir);
159*0f71241aSKees Cook }
160*0f71241aSKees Cook
TEST_F(file,exec_errno)161*0f71241aSKees Cook TEST_F(file, exec_errno)
162*0f71241aSKees Cook {
163*0f71241aSKees Cook char * const argv[2] = { (char * const)self->pathname, NULL };
164*0f71241aSKees Cook
165*0f71241aSKees Cook EXPECT_LT(execv(argv[0], argv), 0);
166*0f71241aSKees Cook EXPECT_EQ(errno, variant->expected);
167*0f71241aSKees Cook }
168*0f71241aSKees Cook
169*0f71241aSKees Cook /* S_IFSOCK */
FIXTURE(sock)170*0f71241aSKees Cook FIXTURE(sock)
171*0f71241aSKees Cook {
172*0f71241aSKees Cook int fd;
173*0f71241aSKees Cook };
174*0f71241aSKees Cook
FIXTURE_SETUP(sock)175*0f71241aSKees Cook FIXTURE_SETUP(sock)
176*0f71241aSKees Cook {
177*0f71241aSKees Cook self->fd = socket(AF_INET, SOCK_STREAM, 0);
178*0f71241aSKees Cook ASSERT_GE(self->fd, 0);
179*0f71241aSKees Cook }
180*0f71241aSKees Cook
FIXTURE_TEARDOWN(sock)181*0f71241aSKees Cook FIXTURE_TEARDOWN(sock)
182*0f71241aSKees Cook {
183*0f71241aSKees Cook if (self->fd >= 0)
184*0f71241aSKees Cook ASSERT_EQ(close(self->fd), 0);
185*0f71241aSKees Cook }
186*0f71241aSKees Cook
TEST_F(sock,exec_errno)187*0f71241aSKees Cook TEST_F(sock, exec_errno)
188*0f71241aSKees Cook {
189*0f71241aSKees Cook char * const argv[2] = { " magic socket ", NULL };
190*0f71241aSKees Cook char * const envp[1] = { NULL };
191*0f71241aSKees Cook
192*0f71241aSKees Cook EXPECT_LT(fexecve(self->fd, argv, envp), 0);
193*0f71241aSKees Cook EXPECT_EQ(errno, EACCES);
194*0f71241aSKees Cook }
195*0f71241aSKees Cook
196*0f71241aSKees Cook TEST_HARNESS_MAIN
197