1*053f45beSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-only
2*053f45beSAndroid Build Coastguard Worker /*
3*053f45beSAndroid Build Coastguard Worker * Copyright (c) 2014 Google, Inc.
4*053f45beSAndroid Build Coastguard Worker *
5*053f45beSAndroid Build Coastguard Worker * Selftests for execveat(2).
6*053f45beSAndroid Build Coastguard Worker */
7*053f45beSAndroid Build Coastguard Worker
8*053f45beSAndroid Build Coastguard Worker #ifndef _GNU_SOURCE
9*053f45beSAndroid Build Coastguard Worker #define _GNU_SOURCE /* to get O_PATH, AT_EMPTY_PATH */
10*053f45beSAndroid Build Coastguard Worker #endif
11*053f45beSAndroid Build Coastguard Worker #include <sys/sendfile.h>
12*053f45beSAndroid Build Coastguard Worker #include <sys/stat.h>
13*053f45beSAndroid Build Coastguard Worker #include <sys/syscall.h>
14*053f45beSAndroid Build Coastguard Worker #include <sys/types.h>
15*053f45beSAndroid Build Coastguard Worker #include <sys/wait.h>
16*053f45beSAndroid Build Coastguard Worker #include <errno.h>
17*053f45beSAndroid Build Coastguard Worker #include <fcntl.h>
18*053f45beSAndroid Build Coastguard Worker #include <limits.h>
19*053f45beSAndroid Build Coastguard Worker #include <stdio.h>
20*053f45beSAndroid Build Coastguard Worker #include <stdlib.h>
21*053f45beSAndroid Build Coastguard Worker #include <string.h>
22*053f45beSAndroid Build Coastguard Worker #include <unistd.h>
23*053f45beSAndroid Build Coastguard Worker
24*053f45beSAndroid Build Coastguard Worker #include "../kselftest.h"
25*053f45beSAndroid Build Coastguard Worker
26*053f45beSAndroid Build Coastguard Worker static char longpath[2 * PATH_MAX] = "";
27*053f45beSAndroid Build Coastguard Worker static char *envp[] = { "IN_TEST=yes", NULL, NULL };
28*053f45beSAndroid Build Coastguard Worker static char *argv[] = { "execveat", "99", NULL };
29*053f45beSAndroid Build Coastguard Worker
execveat_(int fd,const char * path,char ** argv,char ** envp,int flags)30*053f45beSAndroid Build Coastguard Worker static int execveat_(int fd, const char *path, char **argv, char **envp,
31*053f45beSAndroid Build Coastguard Worker int flags)
32*053f45beSAndroid Build Coastguard Worker {
33*053f45beSAndroid Build Coastguard Worker #ifdef __NR_execveat
34*053f45beSAndroid Build Coastguard Worker return syscall(__NR_execveat, fd, path, argv, envp, flags);
35*053f45beSAndroid Build Coastguard Worker #else
36*053f45beSAndroid Build Coastguard Worker errno = ENOSYS;
37*053f45beSAndroid Build Coastguard Worker return -1;
38*053f45beSAndroid Build Coastguard Worker #endif
39*053f45beSAndroid Build Coastguard Worker }
40*053f45beSAndroid Build Coastguard Worker
41*053f45beSAndroid Build Coastguard Worker #define check_execveat_fail(fd, path, flags, errno) \
42*053f45beSAndroid Build Coastguard Worker _check_execveat_fail(fd, path, flags, errno, #errno)
_check_execveat_fail(int fd,const char * path,int flags,int expected_errno,const char * errno_str)43*053f45beSAndroid Build Coastguard Worker static int _check_execveat_fail(int fd, const char *path, int flags,
44*053f45beSAndroid Build Coastguard Worker int expected_errno, const char *errno_str)
45*053f45beSAndroid Build Coastguard Worker {
46*053f45beSAndroid Build Coastguard Worker int rc;
47*053f45beSAndroid Build Coastguard Worker
48*053f45beSAndroid Build Coastguard Worker errno = 0;
49*053f45beSAndroid Build Coastguard Worker printf("Check failure of execveat(%d, '%s', %d) with %s... ",
50*053f45beSAndroid Build Coastguard Worker fd, path?:"(null)", flags, errno_str);
51*053f45beSAndroid Build Coastguard Worker rc = execveat_(fd, path, argv, envp, flags);
52*053f45beSAndroid Build Coastguard Worker
53*053f45beSAndroid Build Coastguard Worker if (rc > 0) {
54*053f45beSAndroid Build Coastguard Worker printf("[FAIL] (unexpected success from execveat(2))\n");
55*053f45beSAndroid Build Coastguard Worker return 1;
56*053f45beSAndroid Build Coastguard Worker }
57*053f45beSAndroid Build Coastguard Worker if (errno != expected_errno) {
58*053f45beSAndroid Build Coastguard Worker printf("[FAIL] (expected errno %d (%s) not %d (%s)\n",
59*053f45beSAndroid Build Coastguard Worker expected_errno, strerror(expected_errno),
60*053f45beSAndroid Build Coastguard Worker errno, strerror(errno));
61*053f45beSAndroid Build Coastguard Worker return 1;
62*053f45beSAndroid Build Coastguard Worker }
63*053f45beSAndroid Build Coastguard Worker printf("[OK]\n");
64*053f45beSAndroid Build Coastguard Worker return 0;
65*053f45beSAndroid Build Coastguard Worker }
66*053f45beSAndroid Build Coastguard Worker
check_execveat_invoked_rc(int fd,const char * path,int flags,int expected_rc,int expected_rc2)67*053f45beSAndroid Build Coastguard Worker static int check_execveat_invoked_rc(int fd, const char *path, int flags,
68*053f45beSAndroid Build Coastguard Worker int expected_rc, int expected_rc2)
69*053f45beSAndroid Build Coastguard Worker {
70*053f45beSAndroid Build Coastguard Worker int status;
71*053f45beSAndroid Build Coastguard Worker int rc;
72*053f45beSAndroid Build Coastguard Worker pid_t child;
73*053f45beSAndroid Build Coastguard Worker int pathlen = path ? strlen(path) : 0;
74*053f45beSAndroid Build Coastguard Worker
75*053f45beSAndroid Build Coastguard Worker if (pathlen > 40)
76*053f45beSAndroid Build Coastguard Worker printf("Check success of execveat(%d, '%.20s...%s', %d)... ",
77*053f45beSAndroid Build Coastguard Worker fd, path, (path + pathlen - 20), flags);
78*053f45beSAndroid Build Coastguard Worker else
79*053f45beSAndroid Build Coastguard Worker printf("Check success of execveat(%d, '%s', %d)... ",
80*053f45beSAndroid Build Coastguard Worker fd, path?:"(null)", flags);
81*053f45beSAndroid Build Coastguard Worker child = fork();
82*053f45beSAndroid Build Coastguard Worker if (child < 0) {
83*053f45beSAndroid Build Coastguard Worker printf("[FAIL] (fork() failed)\n");
84*053f45beSAndroid Build Coastguard Worker return 1;
85*053f45beSAndroid Build Coastguard Worker }
86*053f45beSAndroid Build Coastguard Worker if (child == 0) {
87*053f45beSAndroid Build Coastguard Worker /* Child: do execveat(). */
88*053f45beSAndroid Build Coastguard Worker rc = execveat_(fd, path, argv, envp, flags);
89*053f45beSAndroid Build Coastguard Worker printf("[FAIL]: execveat() failed, rc=%d errno=%d (%s)\n",
90*053f45beSAndroid Build Coastguard Worker rc, errno, strerror(errno));
91*053f45beSAndroid Build Coastguard Worker exit(1); /* should not reach here */
92*053f45beSAndroid Build Coastguard Worker }
93*053f45beSAndroid Build Coastguard Worker /* Parent: wait for & check child's exit status. */
94*053f45beSAndroid Build Coastguard Worker rc = waitpid(child, &status, 0);
95*053f45beSAndroid Build Coastguard Worker if (rc != child) {
96*053f45beSAndroid Build Coastguard Worker printf("[FAIL] (waitpid(%d,...) returned %d)\n", child, rc);
97*053f45beSAndroid Build Coastguard Worker return 1;
98*053f45beSAndroid Build Coastguard Worker }
99*053f45beSAndroid Build Coastguard Worker if (!WIFEXITED(status)) {
100*053f45beSAndroid Build Coastguard Worker printf("[FAIL] (child %d did not exit cleanly, status=%08x)\n",
101*053f45beSAndroid Build Coastguard Worker child, status);
102*053f45beSAndroid Build Coastguard Worker return 1;
103*053f45beSAndroid Build Coastguard Worker }
104*053f45beSAndroid Build Coastguard Worker if ((WEXITSTATUS(status) != expected_rc) &&
105*053f45beSAndroid Build Coastguard Worker (WEXITSTATUS(status) != expected_rc2)) {
106*053f45beSAndroid Build Coastguard Worker printf("[FAIL] (child %d exited with %d not %d nor %d)\n",
107*053f45beSAndroid Build Coastguard Worker child, WEXITSTATUS(status), expected_rc, expected_rc2);
108*053f45beSAndroid Build Coastguard Worker return 1;
109*053f45beSAndroid Build Coastguard Worker }
110*053f45beSAndroid Build Coastguard Worker printf("[OK]\n");
111*053f45beSAndroid Build Coastguard Worker return 0;
112*053f45beSAndroid Build Coastguard Worker }
113*053f45beSAndroid Build Coastguard Worker
check_execveat(int fd,const char * path,int flags)114*053f45beSAndroid Build Coastguard Worker static int check_execveat(int fd, const char *path, int flags)
115*053f45beSAndroid Build Coastguard Worker {
116*053f45beSAndroid Build Coastguard Worker return check_execveat_invoked_rc(fd, path, flags, 99, 99);
117*053f45beSAndroid Build Coastguard Worker }
118*053f45beSAndroid Build Coastguard Worker
concat(const char * left,const char * right)119*053f45beSAndroid Build Coastguard Worker static char *concat(const char *left, const char *right)
120*053f45beSAndroid Build Coastguard Worker {
121*053f45beSAndroid Build Coastguard Worker char *result = malloc(strlen(left) + strlen(right) + 1);
122*053f45beSAndroid Build Coastguard Worker
123*053f45beSAndroid Build Coastguard Worker strcpy(result, left);
124*053f45beSAndroid Build Coastguard Worker strcat(result, right);
125*053f45beSAndroid Build Coastguard Worker return result;
126*053f45beSAndroid Build Coastguard Worker }
127*053f45beSAndroid Build Coastguard Worker
open_or_die(const char * filename,int flags)128*053f45beSAndroid Build Coastguard Worker static int open_or_die(const char *filename, int flags)
129*053f45beSAndroid Build Coastguard Worker {
130*053f45beSAndroid Build Coastguard Worker int fd = open(filename, flags);
131*053f45beSAndroid Build Coastguard Worker
132*053f45beSAndroid Build Coastguard Worker if (fd < 0) {
133*053f45beSAndroid Build Coastguard Worker printf("Failed to open '%s'; "
134*053f45beSAndroid Build Coastguard Worker "check prerequisites are available\n", filename);
135*053f45beSAndroid Build Coastguard Worker exit(1);
136*053f45beSAndroid Build Coastguard Worker }
137*053f45beSAndroid Build Coastguard Worker return fd;
138*053f45beSAndroid Build Coastguard Worker }
139*053f45beSAndroid Build Coastguard Worker
exe_cp(const char * src,const char * dest)140*053f45beSAndroid Build Coastguard Worker static void exe_cp(const char *src, const char *dest)
141*053f45beSAndroid Build Coastguard Worker {
142*053f45beSAndroid Build Coastguard Worker int in_fd = open_or_die(src, O_RDONLY);
143*053f45beSAndroid Build Coastguard Worker int out_fd = open(dest, O_RDWR|O_CREAT|O_TRUNC, 0755);
144*053f45beSAndroid Build Coastguard Worker struct stat info;
145*053f45beSAndroid Build Coastguard Worker
146*053f45beSAndroid Build Coastguard Worker fstat(in_fd, &info);
147*053f45beSAndroid Build Coastguard Worker sendfile(out_fd, in_fd, NULL, info.st_size);
148*053f45beSAndroid Build Coastguard Worker close(in_fd);
149*053f45beSAndroid Build Coastguard Worker close(out_fd);
150*053f45beSAndroid Build Coastguard Worker }
151*053f45beSAndroid Build Coastguard Worker
152*053f45beSAndroid Build Coastguard Worker #define XX_DIR_LEN 200
check_execveat_pathmax(int root_dfd,const char * src,int is_script)153*053f45beSAndroid Build Coastguard Worker static int check_execveat_pathmax(int root_dfd, const char *src, int is_script)
154*053f45beSAndroid Build Coastguard Worker {
155*053f45beSAndroid Build Coastguard Worker int fail = 0;
156*053f45beSAndroid Build Coastguard Worker int ii, count, len;
157*053f45beSAndroid Build Coastguard Worker char longname[XX_DIR_LEN + 1];
158*053f45beSAndroid Build Coastguard Worker int fd;
159*053f45beSAndroid Build Coastguard Worker
160*053f45beSAndroid Build Coastguard Worker if (*longpath == '\0') {
161*053f45beSAndroid Build Coastguard Worker /* Create a filename close to PATH_MAX in length */
162*053f45beSAndroid Build Coastguard Worker char *cwd = getcwd(NULL, 0);
163*053f45beSAndroid Build Coastguard Worker
164*053f45beSAndroid Build Coastguard Worker if (!cwd) {
165*053f45beSAndroid Build Coastguard Worker printf("Failed to getcwd(), errno=%d (%s)\n",
166*053f45beSAndroid Build Coastguard Worker errno, strerror(errno));
167*053f45beSAndroid Build Coastguard Worker return 2;
168*053f45beSAndroid Build Coastguard Worker }
169*053f45beSAndroid Build Coastguard Worker strcpy(longpath, cwd);
170*053f45beSAndroid Build Coastguard Worker strcat(longpath, "/");
171*053f45beSAndroid Build Coastguard Worker memset(longname, 'x', XX_DIR_LEN - 1);
172*053f45beSAndroid Build Coastguard Worker longname[XX_DIR_LEN - 1] = '/';
173*053f45beSAndroid Build Coastguard Worker longname[XX_DIR_LEN] = '\0';
174*053f45beSAndroid Build Coastguard Worker count = (PATH_MAX - 3 - strlen(cwd)) / XX_DIR_LEN;
175*053f45beSAndroid Build Coastguard Worker for (ii = 0; ii < count; ii++) {
176*053f45beSAndroid Build Coastguard Worker strcat(longpath, longname);
177*053f45beSAndroid Build Coastguard Worker mkdir(longpath, 0755);
178*053f45beSAndroid Build Coastguard Worker }
179*053f45beSAndroid Build Coastguard Worker len = (PATH_MAX - 3 - strlen(cwd)) - (count * XX_DIR_LEN);
180*053f45beSAndroid Build Coastguard Worker if (len <= 0)
181*053f45beSAndroid Build Coastguard Worker len = 1;
182*053f45beSAndroid Build Coastguard Worker memset(longname, 'y', len);
183*053f45beSAndroid Build Coastguard Worker longname[len] = '\0';
184*053f45beSAndroid Build Coastguard Worker strcat(longpath, longname);
185*053f45beSAndroid Build Coastguard Worker free(cwd);
186*053f45beSAndroid Build Coastguard Worker }
187*053f45beSAndroid Build Coastguard Worker exe_cp(src, longpath);
188*053f45beSAndroid Build Coastguard Worker
189*053f45beSAndroid Build Coastguard Worker /*
190*053f45beSAndroid Build Coastguard Worker * Execute as a pre-opened file descriptor, which works whether this is
191*053f45beSAndroid Build Coastguard Worker * a script or not (because the interpreter sees a filename like
192*053f45beSAndroid Build Coastguard Worker * "/dev/fd/20").
193*053f45beSAndroid Build Coastguard Worker */
194*053f45beSAndroid Build Coastguard Worker fd = open(longpath, O_RDONLY);
195*053f45beSAndroid Build Coastguard Worker if (fd > 0) {
196*053f45beSAndroid Build Coastguard Worker printf("Invoke copy of '%s' via filename of length %zu:\n",
197*053f45beSAndroid Build Coastguard Worker src, strlen(longpath));
198*053f45beSAndroid Build Coastguard Worker fail += check_execveat(fd, "", AT_EMPTY_PATH);
199*053f45beSAndroid Build Coastguard Worker } else {
200*053f45beSAndroid Build Coastguard Worker printf("Failed to open length %zu filename, errno=%d (%s)\n",
201*053f45beSAndroid Build Coastguard Worker strlen(longpath), errno, strerror(errno));
202*053f45beSAndroid Build Coastguard Worker fail++;
203*053f45beSAndroid Build Coastguard Worker }
204*053f45beSAndroid Build Coastguard Worker
205*053f45beSAndroid Build Coastguard Worker /*
206*053f45beSAndroid Build Coastguard Worker * Execute as a long pathname relative to "/". If this is a script,
207*053f45beSAndroid Build Coastguard Worker * the interpreter will launch but fail to open the script because its
208*053f45beSAndroid Build Coastguard Worker * name ("/dev/fd/5/xxx....") is bigger than PATH_MAX.
209*053f45beSAndroid Build Coastguard Worker *
210*053f45beSAndroid Build Coastguard Worker * The failure code is usually 127 (POSIX: "If a command is not found,
211*053f45beSAndroid Build Coastguard Worker * the exit status shall be 127."), but some systems give 126 (POSIX:
212*053f45beSAndroid Build Coastguard Worker * "If the command name is found, but it is not an executable utility,
213*053f45beSAndroid Build Coastguard Worker * the exit status shall be 126."), so allow either.
214*053f45beSAndroid Build Coastguard Worker */
215*053f45beSAndroid Build Coastguard Worker if (is_script)
216*053f45beSAndroid Build Coastguard Worker fail += check_execveat_invoked_rc(root_dfd, longpath + 1, 0,
217*053f45beSAndroid Build Coastguard Worker 127, 126);
218*053f45beSAndroid Build Coastguard Worker else
219*053f45beSAndroid Build Coastguard Worker fail += check_execveat(root_dfd, longpath + 1, 0);
220*053f45beSAndroid Build Coastguard Worker
221*053f45beSAndroid Build Coastguard Worker return fail;
222*053f45beSAndroid Build Coastguard Worker }
223*053f45beSAndroid Build Coastguard Worker
run_tests(void)224*053f45beSAndroid Build Coastguard Worker static int run_tests(void)
225*053f45beSAndroid Build Coastguard Worker {
226*053f45beSAndroid Build Coastguard Worker int fail = 0;
227*053f45beSAndroid Build Coastguard Worker char *fullname = realpath("execveat", NULL);
228*053f45beSAndroid Build Coastguard Worker char *fullname_script = realpath("script", NULL);
229*053f45beSAndroid Build Coastguard Worker char *fullname_symlink = concat(fullname, ".symlink");
230*053f45beSAndroid Build Coastguard Worker int subdir_dfd = open_or_die("subdir", O_DIRECTORY|O_RDONLY);
231*053f45beSAndroid Build Coastguard Worker int subdir_dfd_ephemeral = open_or_die("subdir.ephemeral",
232*053f45beSAndroid Build Coastguard Worker O_DIRECTORY|O_RDONLY);
233*053f45beSAndroid Build Coastguard Worker int dot_dfd = open_or_die(".", O_DIRECTORY|O_RDONLY);
234*053f45beSAndroid Build Coastguard Worker int root_dfd = open_or_die("/", O_DIRECTORY|O_RDONLY);
235*053f45beSAndroid Build Coastguard Worker int dot_dfd_path = open_or_die(".", O_DIRECTORY|O_RDONLY|O_PATH);
236*053f45beSAndroid Build Coastguard Worker int dot_dfd_cloexec = open_or_die(".", O_DIRECTORY|O_RDONLY|O_CLOEXEC);
237*053f45beSAndroid Build Coastguard Worker int fd = open_or_die("execveat", O_RDONLY);
238*053f45beSAndroid Build Coastguard Worker int fd_path = open_or_die("execveat", O_RDONLY|O_PATH);
239*053f45beSAndroid Build Coastguard Worker int fd_symlink = open_or_die("execveat.symlink", O_RDONLY);
240*053f45beSAndroid Build Coastguard Worker int fd_denatured = open_or_die("execveat.denatured", O_RDONLY);
241*053f45beSAndroid Build Coastguard Worker int fd_denatured_path = open_or_die("execveat.denatured",
242*053f45beSAndroid Build Coastguard Worker O_RDONLY|O_PATH);
243*053f45beSAndroid Build Coastguard Worker int fd_script = open_or_die("script", O_RDONLY);
244*053f45beSAndroid Build Coastguard Worker int fd_ephemeral = open_or_die("execveat.ephemeral", O_RDONLY);
245*053f45beSAndroid Build Coastguard Worker int fd_ephemeral_path = open_or_die("execveat.path.ephemeral",
246*053f45beSAndroid Build Coastguard Worker O_RDONLY|O_PATH);
247*053f45beSAndroid Build Coastguard Worker int fd_script_ephemeral = open_or_die("script.ephemeral", O_RDONLY);
248*053f45beSAndroid Build Coastguard Worker int fd_cloexec = open_or_die("execveat", O_RDONLY|O_CLOEXEC);
249*053f45beSAndroid Build Coastguard Worker int fd_script_cloexec = open_or_die("script", O_RDONLY|O_CLOEXEC);
250*053f45beSAndroid Build Coastguard Worker
251*053f45beSAndroid Build Coastguard Worker /* Check if we have execveat at all, and bail early if not */
252*053f45beSAndroid Build Coastguard Worker errno = 0;
253*053f45beSAndroid Build Coastguard Worker execveat_(-1, NULL, NULL, NULL, 0);
254*053f45beSAndroid Build Coastguard Worker if (errno == ENOSYS) {
255*053f45beSAndroid Build Coastguard Worker ksft_exit_skip(
256*053f45beSAndroid Build Coastguard Worker "ENOSYS calling execveat - no kernel support?\n");
257*053f45beSAndroid Build Coastguard Worker }
258*053f45beSAndroid Build Coastguard Worker
259*053f45beSAndroid Build Coastguard Worker /* Change file position to confirm it doesn't affect anything */
260*053f45beSAndroid Build Coastguard Worker lseek(fd, 10, SEEK_SET);
261*053f45beSAndroid Build Coastguard Worker
262*053f45beSAndroid Build Coastguard Worker /* Normal executable file: */
263*053f45beSAndroid Build Coastguard Worker /* dfd + path */
264*053f45beSAndroid Build Coastguard Worker fail += check_execveat(subdir_dfd, "../execveat", 0);
265*053f45beSAndroid Build Coastguard Worker fail += check_execveat(dot_dfd, "execveat", 0);
266*053f45beSAndroid Build Coastguard Worker fail += check_execveat(dot_dfd_path, "execveat", 0);
267*053f45beSAndroid Build Coastguard Worker /* absolute path */
268*053f45beSAndroid Build Coastguard Worker fail += check_execveat(AT_FDCWD, fullname, 0);
269*053f45beSAndroid Build Coastguard Worker /* absolute path with nonsense dfd */
270*053f45beSAndroid Build Coastguard Worker fail += check_execveat(99, fullname, 0);
271*053f45beSAndroid Build Coastguard Worker /* fd + no path */
272*053f45beSAndroid Build Coastguard Worker fail += check_execveat(fd, "", AT_EMPTY_PATH);
273*053f45beSAndroid Build Coastguard Worker /* O_CLOEXEC fd + no path */
274*053f45beSAndroid Build Coastguard Worker fail += check_execveat(fd_cloexec, "", AT_EMPTY_PATH);
275*053f45beSAndroid Build Coastguard Worker /* O_PATH fd */
276*053f45beSAndroid Build Coastguard Worker fail += check_execveat(fd_path, "", AT_EMPTY_PATH);
277*053f45beSAndroid Build Coastguard Worker
278*053f45beSAndroid Build Coastguard Worker /* Mess with executable file that's already open: */
279*053f45beSAndroid Build Coastguard Worker /* fd + no path to a file that's been renamed */
280*053f45beSAndroid Build Coastguard Worker rename("execveat.ephemeral", "execveat.moved");
281*053f45beSAndroid Build Coastguard Worker fail += check_execveat(fd_ephemeral, "", AT_EMPTY_PATH);
282*053f45beSAndroid Build Coastguard Worker /* fd + no path to a file that's been deleted */
283*053f45beSAndroid Build Coastguard Worker unlink("execveat.moved"); /* remove the file now fd open */
284*053f45beSAndroid Build Coastguard Worker fail += check_execveat(fd_ephemeral, "", AT_EMPTY_PATH);
285*053f45beSAndroid Build Coastguard Worker
286*053f45beSAndroid Build Coastguard Worker /* Mess with executable file that's already open with O_PATH */
287*053f45beSAndroid Build Coastguard Worker /* fd + no path to a file that's been deleted */
288*053f45beSAndroid Build Coastguard Worker unlink("execveat.path.ephemeral");
289*053f45beSAndroid Build Coastguard Worker fail += check_execveat(fd_ephemeral_path, "", AT_EMPTY_PATH);
290*053f45beSAndroid Build Coastguard Worker
291*053f45beSAndroid Build Coastguard Worker /* Invalid argument failures */
292*053f45beSAndroid Build Coastguard Worker fail += check_execveat_fail(fd, "", 0, ENOENT);
293*053f45beSAndroid Build Coastguard Worker fail += check_execveat_fail(fd, NULL, AT_EMPTY_PATH, EFAULT);
294*053f45beSAndroid Build Coastguard Worker
295*053f45beSAndroid Build Coastguard Worker /* Symlink to executable file: */
296*053f45beSAndroid Build Coastguard Worker /* dfd + path */
297*053f45beSAndroid Build Coastguard Worker fail += check_execveat(dot_dfd, "execveat.symlink", 0);
298*053f45beSAndroid Build Coastguard Worker fail += check_execveat(dot_dfd_path, "execveat.symlink", 0);
299*053f45beSAndroid Build Coastguard Worker /* absolute path */
300*053f45beSAndroid Build Coastguard Worker fail += check_execveat(AT_FDCWD, fullname_symlink, 0);
301*053f45beSAndroid Build Coastguard Worker /* fd + no path, even with AT_SYMLINK_NOFOLLOW (already followed) */
302*053f45beSAndroid Build Coastguard Worker fail += check_execveat(fd_symlink, "", AT_EMPTY_PATH);
303*053f45beSAndroid Build Coastguard Worker fail += check_execveat(fd_symlink, "",
304*053f45beSAndroid Build Coastguard Worker AT_EMPTY_PATH|AT_SYMLINK_NOFOLLOW);
305*053f45beSAndroid Build Coastguard Worker
306*053f45beSAndroid Build Coastguard Worker /* Symlink fails when AT_SYMLINK_NOFOLLOW set: */
307*053f45beSAndroid Build Coastguard Worker /* dfd + path */
308*053f45beSAndroid Build Coastguard Worker fail += check_execveat_fail(dot_dfd, "execveat.symlink",
309*053f45beSAndroid Build Coastguard Worker AT_SYMLINK_NOFOLLOW, ELOOP);
310*053f45beSAndroid Build Coastguard Worker fail += check_execveat_fail(dot_dfd_path, "execveat.symlink",
311*053f45beSAndroid Build Coastguard Worker AT_SYMLINK_NOFOLLOW, ELOOP);
312*053f45beSAndroid Build Coastguard Worker /* absolute path */
313*053f45beSAndroid Build Coastguard Worker fail += check_execveat_fail(AT_FDCWD, fullname_symlink,
314*053f45beSAndroid Build Coastguard Worker AT_SYMLINK_NOFOLLOW, ELOOP);
315*053f45beSAndroid Build Coastguard Worker
316*053f45beSAndroid Build Coastguard Worker /* Non-regular file failure */
317*053f45beSAndroid Build Coastguard Worker fail += check_execveat_fail(dot_dfd, "pipe", 0, EACCES);
318*053f45beSAndroid Build Coastguard Worker unlink("pipe");
319*053f45beSAndroid Build Coastguard Worker
320*053f45beSAndroid Build Coastguard Worker /* Shell script wrapping executable file: */
321*053f45beSAndroid Build Coastguard Worker /* dfd + path */
322*053f45beSAndroid Build Coastguard Worker fail += check_execveat(subdir_dfd, "../script", 0);
323*053f45beSAndroid Build Coastguard Worker fail += check_execveat(dot_dfd, "script", 0);
324*053f45beSAndroid Build Coastguard Worker fail += check_execveat(dot_dfd_path, "script", 0);
325*053f45beSAndroid Build Coastguard Worker /* absolute path */
326*053f45beSAndroid Build Coastguard Worker fail += check_execveat(AT_FDCWD, fullname_script, 0);
327*053f45beSAndroid Build Coastguard Worker /* fd + no path */
328*053f45beSAndroid Build Coastguard Worker fail += check_execveat(fd_script, "", AT_EMPTY_PATH);
329*053f45beSAndroid Build Coastguard Worker fail += check_execveat(fd_script, "",
330*053f45beSAndroid Build Coastguard Worker AT_EMPTY_PATH|AT_SYMLINK_NOFOLLOW);
331*053f45beSAndroid Build Coastguard Worker /* O_CLOEXEC fd fails for a script (as script file inaccessible) */
332*053f45beSAndroid Build Coastguard Worker fail += check_execveat_fail(fd_script_cloexec, "", AT_EMPTY_PATH,
333*053f45beSAndroid Build Coastguard Worker ENOENT);
334*053f45beSAndroid Build Coastguard Worker fail += check_execveat_fail(dot_dfd_cloexec, "script", 0, ENOENT);
335*053f45beSAndroid Build Coastguard Worker
336*053f45beSAndroid Build Coastguard Worker /* Mess with script file that's already open: */
337*053f45beSAndroid Build Coastguard Worker /* fd + no path to a file that's been renamed */
338*053f45beSAndroid Build Coastguard Worker rename("script.ephemeral", "script.moved");
339*053f45beSAndroid Build Coastguard Worker fail += check_execveat(fd_script_ephemeral, "", AT_EMPTY_PATH);
340*053f45beSAndroid Build Coastguard Worker /* fd + no path to a file that's been deleted */
341*053f45beSAndroid Build Coastguard Worker unlink("script.moved"); /* remove the file while fd open */
342*053f45beSAndroid Build Coastguard Worker fail += check_execveat(fd_script_ephemeral, "", AT_EMPTY_PATH);
343*053f45beSAndroid Build Coastguard Worker
344*053f45beSAndroid Build Coastguard Worker /* Rename a subdirectory in the path: */
345*053f45beSAndroid Build Coastguard Worker rename("subdir.ephemeral", "subdir.moved");
346*053f45beSAndroid Build Coastguard Worker fail += check_execveat(subdir_dfd_ephemeral, "../script", 0);
347*053f45beSAndroid Build Coastguard Worker fail += check_execveat(subdir_dfd_ephemeral, "script", 0);
348*053f45beSAndroid Build Coastguard Worker /* Remove the subdir and its contents */
349*053f45beSAndroid Build Coastguard Worker unlink("subdir.moved/script");
350*053f45beSAndroid Build Coastguard Worker unlink("subdir.moved");
351*053f45beSAndroid Build Coastguard Worker /* Shell loads via deleted subdir OK because name starts with .. */
352*053f45beSAndroid Build Coastguard Worker fail += check_execveat(subdir_dfd_ephemeral, "../script", 0);
353*053f45beSAndroid Build Coastguard Worker fail += check_execveat_fail(subdir_dfd_ephemeral, "script", 0, ENOENT);
354*053f45beSAndroid Build Coastguard Worker
355*053f45beSAndroid Build Coastguard Worker /* Flag values other than AT_SYMLINK_NOFOLLOW => EINVAL */
356*053f45beSAndroid Build Coastguard Worker fail += check_execveat_fail(dot_dfd, "execveat", 0xFFFF, EINVAL);
357*053f45beSAndroid Build Coastguard Worker /* Invalid path => ENOENT */
358*053f45beSAndroid Build Coastguard Worker fail += check_execveat_fail(dot_dfd, "no-such-file", 0, ENOENT);
359*053f45beSAndroid Build Coastguard Worker fail += check_execveat_fail(dot_dfd_path, "no-such-file", 0, ENOENT);
360*053f45beSAndroid Build Coastguard Worker fail += check_execveat_fail(AT_FDCWD, "no-such-file", 0, ENOENT);
361*053f45beSAndroid Build Coastguard Worker /* Attempt to execute directory => EACCES */
362*053f45beSAndroid Build Coastguard Worker fail += check_execveat_fail(dot_dfd, "", AT_EMPTY_PATH, EACCES);
363*053f45beSAndroid Build Coastguard Worker /* Attempt to execute non-executable => EACCES */
364*053f45beSAndroid Build Coastguard Worker fail += check_execveat_fail(dot_dfd, "Makefile", 0, EACCES);
365*053f45beSAndroid Build Coastguard Worker fail += check_execveat_fail(fd_denatured, "", AT_EMPTY_PATH, EACCES);
366*053f45beSAndroid Build Coastguard Worker fail += check_execveat_fail(fd_denatured_path, "", AT_EMPTY_PATH,
367*053f45beSAndroid Build Coastguard Worker EACCES);
368*053f45beSAndroid Build Coastguard Worker /* Attempt to execute nonsense FD => EBADF */
369*053f45beSAndroid Build Coastguard Worker fail += check_execveat_fail(99, "", AT_EMPTY_PATH, EBADF);
370*053f45beSAndroid Build Coastguard Worker fail += check_execveat_fail(99, "execveat", 0, EBADF);
371*053f45beSAndroid Build Coastguard Worker /* Attempt to execute relative to non-directory => ENOTDIR */
372*053f45beSAndroid Build Coastguard Worker fail += check_execveat_fail(fd, "execveat", 0, ENOTDIR);
373*053f45beSAndroid Build Coastguard Worker
374*053f45beSAndroid Build Coastguard Worker fail += check_execveat_pathmax(root_dfd, "execveat", 0);
375*053f45beSAndroid Build Coastguard Worker fail += check_execveat_pathmax(root_dfd, "script", 1);
376*053f45beSAndroid Build Coastguard Worker return fail;
377*053f45beSAndroid Build Coastguard Worker }
378*053f45beSAndroid Build Coastguard Worker
prerequisites(void)379*053f45beSAndroid Build Coastguard Worker static void prerequisites(void)
380*053f45beSAndroid Build Coastguard Worker {
381*053f45beSAndroid Build Coastguard Worker int fd;
382*053f45beSAndroid Build Coastguard Worker const char *script = "#!/system/bin/sh\nexit $*\n";
383*053f45beSAndroid Build Coastguard Worker
384*053f45beSAndroid Build Coastguard Worker /* Create ephemeral copies of files */
385*053f45beSAndroid Build Coastguard Worker exe_cp("execveat", "execveat.ephemeral");
386*053f45beSAndroid Build Coastguard Worker exe_cp("execveat", "execveat.path.ephemeral");
387*053f45beSAndroid Build Coastguard Worker exe_cp("script", "script.ephemeral");
388*053f45beSAndroid Build Coastguard Worker mkdir("subdir.ephemeral", 0755);
389*053f45beSAndroid Build Coastguard Worker
390*053f45beSAndroid Build Coastguard Worker fd = open("subdir.ephemeral/script", O_RDWR|O_CREAT|O_TRUNC, 0755);
391*053f45beSAndroid Build Coastguard Worker write(fd, script, strlen(script));
392*053f45beSAndroid Build Coastguard Worker close(fd);
393*053f45beSAndroid Build Coastguard Worker
394*053f45beSAndroid Build Coastguard Worker mkfifo("pipe", 0755);
395*053f45beSAndroid Build Coastguard Worker }
396*053f45beSAndroid Build Coastguard Worker
main(int argc,char ** argv)397*053f45beSAndroid Build Coastguard Worker int main(int argc, char **argv)
398*053f45beSAndroid Build Coastguard Worker {
399*053f45beSAndroid Build Coastguard Worker int ii;
400*053f45beSAndroid Build Coastguard Worker int rc;
401*053f45beSAndroid Build Coastguard Worker const char *verbose = getenv("VERBOSE");
402*053f45beSAndroid Build Coastguard Worker
403*053f45beSAndroid Build Coastguard Worker if (argc >= 2) {
404*053f45beSAndroid Build Coastguard Worker /* If we are invoked with an argument, don't run tests. */
405*053f45beSAndroid Build Coastguard Worker const char *in_test = getenv("IN_TEST");
406*053f45beSAndroid Build Coastguard Worker
407*053f45beSAndroid Build Coastguard Worker if (verbose) {
408*053f45beSAndroid Build Coastguard Worker printf(" invoked with:");
409*053f45beSAndroid Build Coastguard Worker for (ii = 0; ii < argc; ii++)
410*053f45beSAndroid Build Coastguard Worker printf(" [%d]='%s'", ii, argv[ii]);
411*053f45beSAndroid Build Coastguard Worker printf("\n");
412*053f45beSAndroid Build Coastguard Worker }
413*053f45beSAndroid Build Coastguard Worker
414*053f45beSAndroid Build Coastguard Worker /* Check expected environment transferred. */
415*053f45beSAndroid Build Coastguard Worker if (!in_test || strcmp(in_test, "yes") != 0) {
416*053f45beSAndroid Build Coastguard Worker printf("[FAIL] (no IN_TEST=yes in env)\n");
417*053f45beSAndroid Build Coastguard Worker return 1;
418*053f45beSAndroid Build Coastguard Worker }
419*053f45beSAndroid Build Coastguard Worker
420*053f45beSAndroid Build Coastguard Worker /* Use the final argument as an exit code. */
421*053f45beSAndroid Build Coastguard Worker rc = atoi(argv[argc - 1]);
422*053f45beSAndroid Build Coastguard Worker fflush(stdout);
423*053f45beSAndroid Build Coastguard Worker } else {
424*053f45beSAndroid Build Coastguard Worker prerequisites();
425*053f45beSAndroid Build Coastguard Worker if (verbose)
426*053f45beSAndroid Build Coastguard Worker envp[1] = "VERBOSE=1";
427*053f45beSAndroid Build Coastguard Worker rc = run_tests();
428*053f45beSAndroid Build Coastguard Worker if (rc > 0)
429*053f45beSAndroid Build Coastguard Worker printf("%d tests failed\n", rc);
430*053f45beSAndroid Build Coastguard Worker }
431*053f45beSAndroid Build Coastguard Worker return rc;
432*053f45beSAndroid Build Coastguard Worker }
433