1 /* 2 * 3 * Copyright (c) International Business Machines Corp., 2001 4 * 07/2001 Ported by Wayne Boyer 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 14 * the GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 /* 21 * Test Description : 22 * Verify that, 23 * 1) readlink(2) returns -1 and sets errno to EACCES if search/write 24 * permission is denied in the directory where the symbolic link 25 * resides. 26 * 2) readlink(2) returns -1 and sets errno to EINVAL if the buffer size 27 * is not positive. 28 * 3) readlink(2) returns -1 and sets errno to EINVAL if the specified 29 * file is not a symbolic link file. 30 * 4) readlink(2) returns -1 and sets errno to ENAMETOOLONG if the 31 * pathname component of symbolic link is too long (ie, > PATH_MAX). 32 * 5) readlink(2) returns -1 and sets errno to ENOENT if the component of 33 * symbolic link points to an empty string. 34 * 6) readlink(2) returns -1 and sets errno to ENOTDIR if a component of 35 * the path prefix is not a directory. 36 * 7) readlink(2) returns -1 and sets errno to ELOOP if too many symbolic 37 * links were encountered in translating the pathname. 38 */ 39 40 #include <stdio.h> 41 #include <sys/types.h> 42 #include <sys/fcntl.h> 43 #include <errno.h> 44 #include <string.h> 45 #include <signal.h> 46 #include <sys/stat.h> 47 #include <pwd.h> 48 49 #include "test.h" 50 #include "safe_macros.h" 51 52 #define MODE_RWX (S_IRWXU | S_IRWXG | S_IRWXO) 53 #define FILE_MODE (S_IRUSR | S_IRGRP | S_IROTH) 54 #define DIR_TEMP "testdir_1" 55 #define TEST_FILE1 "testdir_1/tfile_1" 56 #define SYM_FILE1 "testdir_1/sfile_1" 57 #define TEST_FILE2 "tfile_2" 58 #define SYM_FILE2 "sfile_2" 59 #define TEST_FILE3 "tfile_3" 60 #define SYM_FILE3 "tfile_3/sfile_3" 61 #define ELOOPFILE "/test_eloop" 62 #define MAX_SIZE 256 63 64 static char longpathname[PATH_MAX + 2]; 65 static char elooppathname[sizeof(ELOOPFILE) * 43] = "."; 66 67 static struct test_case_t { 68 char *link; 69 size_t buf_size; 70 int exp_errno; 71 } test_cases[] = { 72 {SYM_FILE1, 1, EACCES}, 73 /* Don't test with bufsize -1, since this cause a fortify-check-fail when 74 using glibc and -D_FORITY_SOURCE=2 75 76 Discussion: http://lkml.org/lkml/2008/10/23/229 77 Conclusion: Only test with 0 as non-positive bufsize. 78 79 { SYM_FILE2, -1, EINVAL, NULL }, 80 */ 81 {SYM_FILE2, 0, EINVAL}, 82 {TEST_FILE2, 1, EINVAL}, 83 {longpathname, 1, ENAMETOOLONG}, 84 {"", 1, ENOENT}, 85 {SYM_FILE3, 1, ENOTDIR}, 86 {elooppathname, 1, ELOOP}, 87 }; 88 89 static void setup(void); 90 static void readlink_verify(struct test_case_t *); 91 static void cleanup(void); 92 93 char *TCID = "readlink03"; 94 int TST_TOTAL = ARRAY_SIZE(test_cases); 95 96 int main(int ac, char **av) 97 { 98 int i, lc; 99 100 tst_parse_opts(ac, av, NULL, NULL); 101 102 setup(); 103 104 for (lc = 0; TEST_LOOPING(lc); lc++) { 105 tst_count = 0; 106 107 for (i = 0; i < TST_TOTAL; i++) 108 readlink_verify(&test_cases[i]); 109 } 110 111 cleanup(); 112 tst_exit(); 113 } 114 115 void setup(void) 116 { 117 struct passwd *ltpuser; 118 int i; 119 120 tst_require_root(); 121 122 tst_sig(NOFORK, DEF_HANDLER, cleanup); 123 124 ltpuser = SAFE_GETPWNAM(cleanup, "nobody"); 125 SAFE_SETEUID(cleanup, ltpuser->pw_uid); 126 127 TEST_PAUSE; 128 129 tst_tmpdir(); 130 131 SAFE_MKDIR(cleanup, DIR_TEMP, MODE_RWX); 132 SAFE_TOUCH(cleanup, TEST_FILE1, 0666, NULL); 133 SAFE_SYMLINK(cleanup, TEST_FILE1, SYM_FILE1); 134 SAFE_CHMOD(cleanup, DIR_TEMP, FILE_MODE); 135 136 SAFE_TOUCH(cleanup, TEST_FILE2, 0666, NULL); 137 SAFE_SYMLINK(cleanup, TEST_FILE2, SYM_FILE2); 138 139 memset(longpathname, 'a', PATH_MAX + 1); 140 141 SAFE_TOUCH(cleanup, TEST_FILE3, 0666, NULL); 142 143 /* 144 * NOTE: the ELOOP test is written based on that the consecutive 145 * symlinks limit in kernel is hardwired to 40. 146 */ 147 SAFE_MKDIR(cleanup, "test_eloop", MODE_RWX); 148 SAFE_SYMLINK(cleanup, "../test_eloop", "test_eloop/test_eloop"); 149 for (i = 0; i < 43; i++) 150 strcat(elooppathname, ELOOPFILE); 151 } 152 153 void readlink_verify(struct test_case_t *tc) 154 { 155 char buffer[MAX_SIZE]; 156 157 if (tc->buf_size == 1) 158 tc->buf_size = sizeof(buffer); 159 160 TEST(readlink(tc->link, buffer, tc->buf_size)); 161 162 if (TEST_RETURN != -1) { 163 tst_resm(TFAIL, "readlink() returned %ld, " 164 "expected -1, errno:%d", TEST_RETURN, 165 tc->exp_errno); 166 return; 167 } 168 169 if (TEST_ERRNO == tc->exp_errno) { 170 tst_resm(TPASS | TTERRNO, "readlink() failed as expected"); 171 } else { 172 tst_resm(TFAIL | TTERRNO, 173 "readlink() failed unexpectedly; expected: %d - %s", 174 tc->exp_errno, strerror(tc->exp_errno)); 175 if (tc->exp_errno == ENOENT && TEST_ERRNO == EINVAL) { 176 tst_resm(TWARN | TTERRNO, 177 "It may be a Kernel Bug, see the patch:" 178 "http://git.kernel.org/linus/1fa1e7f6"); 179 } 180 } 181 } 182 183 void cleanup(void) 184 { 185 if (seteuid(0) == -1) 186 tst_resm(TWARN | TERRNO, "seteuid(0) failed"); 187 188 tst_rmdir(); 189 } 190