1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) International Business Machines Corp., 2001
4 * 07/2001 Ported by Wayne Boyer
5 * 06/2019 Ported to new library: Christian Amann <camann@suse.com>
6 */
7 /*
8 * This test verifies that:
9 *
10 * 1) lstat(2) returns -1 and sets errno to EACCES if search permission is
11 * denied on a component of the path prefix.
12 * 2) lstat(2) returns -1 and sets errno to ENOENT if the specified file
13 * does not exists or empty string.
14 * 3) lstat(2) returns -1 and sets errno to EFAULT if pathname points
15 * outside user's accessible address space.
16 * 4) lstat(2) returns -1 and sets errno to ENAMETOOLONG if the pathname
17 * component is too long.
18 * 5) lstat(2) returns -1 and sets errno to ENOTDIR if the directory
19 * component in pathname is not a directory.
20 * 6) lstat(2) returns -1 and sets errno to ELOOP if the pathname has too
21 * many symbolic links encountered while traversing.
22 */
23
24 #include <errno.h>
25 #include <pwd.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include "tst_test.h"
32
33 #define MODE_RWX 0777
34 #define MODE_RW0 0666
35 #define TEST_DIR "test_dir"
36 #define TEST_FILE "test_file"
37
38 #define TEST_ELOOP "/test_eloop"
39 #define TEST_ENOENT ""
40 #define TEST_EACCES TEST_DIR"/test_eacces"
41 #define TEST_ENOTDIR TEST_FILE"/test_enotdir"
42
43 static char longpathname[PATH_MAX + 2];
44 static char elooppathname[sizeof(TEST_ELOOP) * 43];
45 static struct stat stat_buf;
46
47 static struct test_case_t {
48 char *pathname;
49 int exp_errno;
50 } test_cases[] = {
51 {TEST_EACCES, EACCES},
52 {TEST_ENOENT, ENOENT},
53 {NULL, EFAULT},
54 {longpathname, ENAMETOOLONG},
55 {TEST_ENOTDIR, ENOTDIR},
56 {elooppathname, ELOOP},
57 };
58
run(unsigned int n)59 static void run(unsigned int n)
60 {
61 struct test_case_t *tc = &test_cases[n];
62
63 TEST(lstat(tc->pathname, &stat_buf));
64
65 if (TST_RET != -1) {
66 tst_res(TFAIL | TTERRNO, "lstat() returned %ld, expected -1",
67 TST_RET);
68 return;
69 }
70
71 if (tc->exp_errno == TST_ERR) {
72 tst_res(TPASS | TTERRNO, "lstat() failed as expected");
73 } else {
74 tst_res(TFAIL | TTERRNO,
75 "lstat() failed unexpectedly; expected: %s - got",
76 tst_strerrno(tc->exp_errno));
77 }
78 }
79
setup(void)80 static void setup(void)
81 {
82 int i;
83 struct passwd *ltpuser;
84
85 /* Drop privileges for EACCES test */
86 if (geteuid() == 0) {
87 ltpuser = SAFE_GETPWNAM("nobody");
88 SAFE_SETEUID(ltpuser->pw_uid);
89 }
90
91 memset(longpathname, 'a', PATH_MAX+1);
92 longpathname[PATH_MAX+1] = '\0';
93
94 SAFE_MKDIR(TEST_DIR, MODE_RWX);
95 SAFE_TOUCH(TEST_EACCES, MODE_RWX, NULL);
96 SAFE_TOUCH(TEST_FILE, MODE_RWX, NULL);
97 SAFE_CHMOD(TEST_DIR, MODE_RW0);
98
99 SAFE_MKDIR("test_eloop", MODE_RWX);
100 SAFE_SYMLINK("../test_eloop", "test_eloop/test_eloop");
101 /*
102 * NOTE: The ELOOP test is written based on the fact that the
103 * consecutive symlinks limit in the kernel is hardwired to 40.
104 */
105 elooppathname[0] = '.';
106 for (i = 0; i < 43; i++)
107 strcat(elooppathname, TEST_ELOOP);
108 }
109
cleanup(void)110 static void cleanup(void)
111 {
112 SAFE_CHMOD(TEST_DIR, MODE_RWX);
113 }
114
115 static struct tst_test test = {
116 .test = run,
117 .tcnt = ARRAY_SIZE(test_cases),
118 .setup = setup,
119 .cleanup = cleanup,
120 .needs_tmpdir = 1,
121 };
122