1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2018 Linux Test Project
4 * Copyright (c) International Business Machines Corp., 2001
5 * Copyright (c) Renaud Lottiaux <Renaud.Lottiaux@kerlabs.com>
6 * Ported to LTP: Wayne Boyer
7 */
8
9/*
10 *	Testcase to check execve sets the following errnos correctly:
11 *	1.	ENAMETOOLONG
12 *	2.	ENOENT
13 *	3.	ENOTDIR
14 *	4.	EFAULT
15 *	5.	EACCES
16 *	6.	ENOEXEC
17 *
18 * ALGORITHM
19 *	1.	Attempt to execve(2) a file whose name is more than
20 *		VFS_MAXNAMLEN fails with ENAMETOOLONG.
21 *
22 *	2.	Attempt to execve(2) a file which doesn't exist fails with
23 *		ENOENT.
24 *
25 *	3.	Attempt to execve(2) a pathname (executabl) comprising of a
26 *		directory, which doesn't exist fails with ENOTDIR.
27 *
28 *	4.	Attempt to execve(2) a filename not within the address space
29 *		of the process fails with EFAULT.
30 *
31 *	5.	Attempt to execve(2) a filename that does not have executable
32 *		permission - fails with EACCES.
33 *
34 *	6.	Attempt to execve(2) a zero length file with executable
35 *		permissions - fails with ENOEXEC.
36 */
37
38#ifndef _GNU_SOURCE
39#define _GNU_SOURCE
40#endif
41#include <sys/types.h>
42#include <sys/mman.h>
43#include <sys/stat.h>
44#include <errno.h>
45#include <fcntl.h>
46#include <pwd.h>
47#include <stdio.h>
48#include <unistd.h>
49
50#include "tst_test.h"
51
52static char nobody_uid[] = "nobody";
53static struct passwd *ltpuser;
54static char long_fname[] = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyz";
55static char no_dir[] = "testdir";
56static char test_name3[1024];
57static char test_name5[1024];
58static char test_name6[1024];
59
60static struct tcase {
61	char *tname;
62	int error;
63} tcases[] = {
64	/* the file name is greater than VFS_MAXNAMELEN - ENAMTOOLONG */
65	{long_fname, ENAMETOOLONG},
66	/* the filename does not exist - ENOENT */
67	{no_dir, ENOENT},
68	/* the path contains a directory name which doesn't exist - ENOTDIR */
69	{test_name3, ENOTDIR},
70	/* the filename isn't part of the process address space - EFAULT */
71	{NULL, EFAULT},
72	/* the filename does not have execute permission - EACCES */
73	{test_name5, EACCES},
74	/* the file is zero length with execute permissions - ENOEXEC */
75	{test_name6, ENOEXEC}
76};
77
78static void setup(void)
79{
80	char *cwdname = NULL;
81	unsigned i;
82	int fd;
83
84	umask(0);
85
86	ltpuser = SAFE_GETPWNAM(nobody_uid);
87
88	SAFE_SETGID(ltpuser->pw_gid);
89
90	cwdname = SAFE_GETCWD(cwdname, 0);
91
92	sprintf(test_name5, "%s/fake", cwdname);
93
94	fd = SAFE_CREAT(test_name5, 0444);
95	SAFE_CLOSE(fd);
96
97	sprintf(test_name3, "%s/fake", test_name5);
98
99	/* creat() and close a zero length file with executeable permission */
100	sprintf(test_name6, "%s/execve03", cwdname);
101
102	fd = SAFE_CREAT(test_name6, 0755);
103	SAFE_CLOSE(fd);
104
105	for (i = 0; i < ARRAY_SIZE(tcases); i++) {
106		if (!tcases[i].tname)
107			tcases[i].tname = tst_get_bad_addr(NULL);
108	}
109}
110
111static void verify_execve(unsigned int i)
112{
113	struct tcase *tc = &tcases[i];
114	char *argv[2] = {tc->tname, NULL};
115
116	TEST(execve(tc->tname, argv, NULL));
117
118	if (TST_RET != -1) {
119		tst_res(TFAIL, "call succeeded unexpectedly");
120		return;
121	}
122
123	if (TST_ERR == tc->error) {
124		tst_res(TPASS | TTERRNO, "execve failed as expected");
125		return;
126	}
127
128	tst_res(TFAIL | TTERRNO, "execve failed unexpectedly; expected %s",
129		strerror(tc->error));
130}
131
132static struct tst_test test = {
133	.tcnt = ARRAY_SIZE(tcases),
134	.test = verify_execve,
135	.needs_root = 1,
136	.needs_tmpdir = 1,
137	.child_needs_reinit = 1,
138	.setup = setup,
139};
140