1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
4 * AUTHOR : Richard Logan
5 * CO-PILOT : William Roske
6 * Copyright (c) 2014 Cyril Hrubis <chrubis@suse.cz>
7 */
8
9 /*\
10 * [Description]
11 *
12 * Negative test cases for link(2).
13 *
14 * This test program should contain test cases where link will fail regardless
15 * of who executed it (i.e. joe-user or root)
16 */
17
18 #include <pwd.h>
19 #include <sys/param.h>
20 #include <sys/mman.h>
21 #include "tst_test.h"
22
23 #define NOBODY_USER 99
24 #define MODE_TO1 S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IXOTH|S_IROTH
25 #define MODE_TO2 S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IXOTH|S_IROTH|S_IWOTH
26 #define MODE_TE S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
27 #define MODE_RWX S_IRWXU | S_IRWXG | S_IRWXO
28 #define DIR_TEMP "dir2/testdir_1"
29
30 static char longpath[PATH_MAX + 2];
31
32 static struct tcase {
33 char *file1;
34 char *desc1;
35 char *file2;
36 char *desc2;
37 int exp_errno;
38 } tcases[] = {
39 /* first path is invalid */
40 {"nonexistfile", "non-existent file", "nefile", "nefile", ENOENT},
41 {"", "path is empty string", "nefile", "nefile", ENOENT},
42 {"neefile/file", "path contains a non-existent file", "nefile", "nefile", ENOENT},
43 {"regfile/file", "path contains a regular file", "nefile", "nefile", ENOTDIR},
44 {longpath, "pathname too long", "nefile", "nefile", ENAMETOOLONG},
45 {NULL, "invalid address", "nefile", "nefile", EFAULT},
46
47 /* second path is invalid */
48 {"regfile", "regfile", "", "empty string", ENOENT},
49 {"regfile", "regfile", "neefile/file", "path contains a non-existent file", ENOENT},
50 {"regfile", "regfile", "file/file", "path contains a regular file", ENOENT},
51 {"regfile", "regfile", longpath, "pathname too long", ENAMETOOLONG},
52 {"regfile", "regfile", NULL, "invalid address", EFAULT},
53
54 /* two existing files */
55 {"regfile", "regfile", "regfile2", "regfile2", EEXIST},
56 {"dir1/oldpath", "Write access diretory", "dir1/newpath", "newpath", EACCES},
57 {"dir2/testdir_1/tfile_2", "Search access diretory", "dir2/testdir_1/new_tfile_2",
58 "dir2/testdir_1/new_tfile_2", EACCES},
59 };
60
verify_link(unsigned int i)61 static void verify_link(unsigned int i)
62 {
63 struct passwd *nobody_pwd;
64 struct tcase *tc = &tcases[i];
65
66 if (tc->exp_errno == EACCES) {
67 SAFE_SETEUID(0);
68
69 if (strcmp(tc->desc1, "Write access diretory") == 0) {
70 /* Modify mode permissions on test directory */
71 SAFE_CHMOD("dir1", MODE_TO1);
72 SAFE_TOUCH(tc->file1, 0777, NULL);
73 } else if (strcmp(tc->desc1, "Search access diretory") == 0) {
74 /* Modify mode permissions on test directory */
75 SAFE_CHMOD("dir2", MODE_TO2);
76 SAFE_TOUCH(tc->file1, 0666, NULL);
77
78 /* Modify mode permissions on test directory - test conditions */
79 SAFE_CHMOD(DIR_TEMP, MODE_TE);
80 }
81
82 nobody_pwd = SAFE_GETPWNAM("nobody");
83 SAFE_SETEUID(nobody_pwd->pw_uid);
84 }
85
86 TEST(link(tc->file1, tc->file2));
87
88 if (TST_RET == -1) {
89 if (TST_ERR == tc->exp_errno) {
90 tst_res(TPASS | TTERRNO,
91 "link(<%s>, <%s>)",
92 tc->desc1, tc->desc2);
93 } else {
94 tst_res(TFAIL | TTERRNO,
95 "link(<%s>, <%s>) Failed "
96 "expected errno: %d",
97 tc->desc1, tc->desc2,
98 tc->exp_errno);
99 }
100 } else {
101 tst_res(TFAIL,
102 "link(<%s>, <%s>) returned %ld, "
103 "expected -1, errno:%d",
104 tc->desc1, tc->desc2, TST_RET,
105 tc->exp_errno);
106 }
107 }
108
setup(void)109 static void setup(void)
110 {
111 unsigned int i;
112 memset(longpath, 'a', PATH_MAX+1);
113
114 SAFE_TOUCH("regfile", 0777, NULL);
115 SAFE_TOUCH("regfile2", 0777, NULL);
116 SAFE_MKDIR("dir", 0777);
117 SAFE_MKDIR("dir1", MODE_RWX);
118 SAFE_MKDIR("dir2", MODE_RWX);
119 SAFE_MKDIR(DIR_TEMP, MODE_RWX);
120
121 for (i = 0; i < ARRAY_SIZE(tcases); i++) {
122 struct tcase *tc = &tcases[i];
123
124 if (!tc->file1)
125 tc->file1 = tst_get_bad_addr(NULL);
126
127 if (!tc->file2)
128 tc->file2 = tst_get_bad_addr(NULL);
129 }
130 }
131
132 static struct tst_test test = {
133 .tcnt = ARRAY_SIZE(tcases),
134 .test = verify_link,
135 .setup = setup,
136 .needs_tmpdir = 1,
137 .needs_root = 1,
138 };
139