1 /*
2 * Copyright (c) 2018 Linux Test Project
3 * Copyright (c) International Business Machines Corp., 2001
4 *
5 * 07/2001 Ported by Wayne Boyer
6 * 21/04/2008 Renaud Lottiaux (Renaud.Lottiaux@kerlabs.com)
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /*
23 * NAME
24 * execve03.c
25 *
26 * DESCRIPTION
27 * Testcase to check execve sets the following errnos correctly:
28 * 1. ENAMETOOLONG
29 * 2. ENOENT
30 * 3. ENOTDIR
31 * 4. EFAULT
32 * 5. EACCES
33 * 6. ENOEXEC
34 *
35 * ALGORITHM
36 * 1. Attempt to execve(2) a file whose name is more than
37 * VFS_MAXNAMLEN fails with ENAMETOOLONG.
38 *
39 * 2. Attempt to execve(2) a file which doesn't exist fails with
40 * ENOENT.
41 *
42 * 3. Attempt to execve(2) a pathname (executabl) comprising of a
43 * directory, which doesn't exist fails with ENOTDIR.
44 *
45 * 4. Attempt to execve(2) a filename not within the address space
46 * of the process fails with EFAULT.
47 *
48 * 5. Attempt to execve(2) a filename that does not have executable
49 * permission - fails with EACCES.
50 *
51 * 6. Attempt to execve(2) a zero length file with executable
52 * permissions - fails with ENOEXEC.
53 *
54 * HISTORY
55 * 07/2001 Ported by Wayne Boyer
56 */
57
58 #ifndef _GNU_SOURCE
59 #define _GNU_SOURCE
60 #endif
61 #include <sys/types.h>
62 #include <sys/mman.h>
63 #include <sys/stat.h>
64 #include <errno.h>
65 #include <fcntl.h>
66 #include <pwd.h>
67 #include <stdio.h>
68 #include <unistd.h>
69
70 #include "tst_test.h"
71
72 static char nobody_uid[] = "nobody";
73 static struct passwd *ltpuser;
74 static char long_fname[] = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyz";
75 static char no_dir[] = "testdir";
76 static char test_name3[1024];
77 static char test_name5[1024];
78 static char test_name6[1024];
79
80 static struct tcase {
81 char *tname;
82 int error;
83 } tcases[] = {
84 /* the file name is greater than VFS_MAXNAMELEN - ENAMTOOLONG */
85 {long_fname, ENAMETOOLONG},
86 /* the filename does not exist - ENOENT */
87 {no_dir, ENOENT},
88 /* the path contains a directory name which doesn't exist - ENOTDIR */
89 {test_name3, ENOTDIR},
90 /* the filename isn't part of the process address space - EFAULT */
91 {NULL, EFAULT},
92 /* the filename does not have execute permission - EACCES */
93 {test_name5, EACCES},
94 /* the file is zero length with execute permissions - ENOEXEC */
95 {test_name6, ENOEXEC}
96 };
97
setup(void)98 static void setup(void)
99 {
100 char *cwdname = NULL;
101 unsigned i;
102 int fd;
103
104 umask(0);
105
106 ltpuser = SAFE_GETPWNAM(nobody_uid);
107
108 SAFE_SETGID(ltpuser->pw_gid);
109
110 cwdname = SAFE_GETCWD(cwdname, 0);
111
112 sprintf(test_name5, "%s/fake", cwdname);
113
114 fd = SAFE_CREAT(test_name5, 0444);
115 SAFE_CLOSE(fd);
116
117 sprintf(test_name3, "%s/fake", test_name5);
118
119 /* creat() and close a zero length file with executeable permission */
120 sprintf(test_name6, "%s/execve03", cwdname);
121
122 fd = SAFE_CREAT(test_name6, 0755);
123 SAFE_CLOSE(fd);
124
125 for (i = 0; i < ARRAY_SIZE(tcases); i++) {
126 if (!tcases[i].tname)
127 tcases[i].tname = tst_get_bad_addr(NULL);
128 }
129 }
130
verify_execve(unsigned int i)131 static void verify_execve(unsigned int i)
132 {
133 struct tcase *tc = &tcases[i];
134 char *argv[2] = {tc->tname, NULL};
135
136 TEST(execve(tc->tname, argv, NULL));
137
138 if (TST_RET != -1) {
139 tst_res(TFAIL, "call succeeded unexpectedly");
140 return;
141 }
142
143 if (TST_ERR == tc->error) {
144 tst_res(TPASS | TTERRNO, "execve failed as expected");
145 return;
146 }
147
148 tst_res(TFAIL | TTERRNO, "execve failed unexpectedly; expected %s",
149 strerror(tc->error));
150 }
151
152 static struct tst_test test = {
153 .tcnt = ARRAY_SIZE(tcases),
154 .test = verify_execve,
155 .needs_root = 1,
156 .needs_tmpdir = 1,
157 .child_needs_reinit = 1,
158 .setup = setup,
159 };
160