• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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