1 /* 2 * Copyright (c) International Business Machines Corp., 2001 3 * 07/2001 Ported by Wayne Boyer 4 * Copyright (c) 2014 Cyril Hrubis <chrubis (at) suse.cz> 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 /* 22 * Test Name: chown04 23 * 24 * Test Description: 25 * Verify that, 26 * 1) chown(2) returns -1 and sets errno to EPERM if the effective user id 27 * of process does not match the owner of the file and the process 28 * is not super user. 29 * 2) chown(2) returns -1 and sets errno to EACCES if search permission is 30 * denied on a component of the path prefix. 31 * 3) chown(2) returns -1 and sets errno to EFAULT if pathname points 32 * outside user's accessible address space. 33 * 4) chown(2) returns -1 and sets errno to ENAMETOOLONG if the pathname 34 * component is too long. 35 * 5) chown(2) returns -1 and sets errno to ENOTDIR if the directory 36 * component in pathname is not a directory. 37 * 6) chown(2) returns -1 and sets errno to ENOENT if the specified file 38 * does not exists. 39 */ 40 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <unistd.h> 44 #include <fcntl.h> 45 #include <errno.h> 46 #include <string.h> 47 #include <signal.h> 48 #include <grp.h> 49 #include <pwd.h> 50 #include <sys/types.h> 51 #include <sys/stat.h> 52 #include <sys/mman.h> 53 #include <sys/mount.h> 54 55 #include "test.h" 56 #include "safe_macros.h" 57 #include "compat_16.h" 58 59 #define MODE_RWX (S_IRWXU|S_IRWXG|S_IRWXO) 60 #define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) 61 #define DIR_MODE (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP| \ 62 S_IXGRP|S_IROTH|S_IXOTH) 63 #define DIR_TEMP "testdir_1" 64 #define TEST_FILE1 "tfile_1" 65 #define TEST_FILE2 (DIR_TEMP "/tfile_2") 66 #define TEST_FILE3 "t_file/tfile_3" 67 #define TEST_FILE4 "test_eloop1" 68 #define TEST_FILE5 "mntpoint" 69 70 static char long_path[PATH_MAX + 2]; 71 static const char *device; 72 static int mount_flag; 73 74 static struct test_case_t { 75 char *pathname; 76 int exp_errno; 77 } tc[] = { 78 {TEST_FILE1, EPERM}, 79 {TEST_FILE2, EACCES}, 80 {(char *)-1, EFAULT}, 81 {long_path, ENAMETOOLONG}, 82 {"", ENOENT}, 83 {TEST_FILE3, ENOTDIR}, 84 {TEST_FILE4, ELOOP}, 85 {TEST_FILE5, EROFS} 86 }; 87 88 TCID_DEFINE(chown04); 89 int TST_TOTAL = ARRAY_SIZE(tc); 90 91 static char *bad_addr; 92 93 static void setup(void); 94 static void cleanup(void); 95 96 int main(int ac, char **av) 97 { 98 int lc; 99 int i; 100 uid_t user_id; 101 gid_t group_id; 102 103 tst_parse_opts(ac, av, NULL, NULL); 104 105 setup(); 106 107 UID16_CHECK((user_id = geteuid()), "chown", cleanup) 108 GID16_CHECK((group_id = getegid()), "chown", cleanup) 109 110 for (lc = 0; TEST_LOOPING(lc); lc++) { 111 tst_count = 0; 112 113 for (i = 0; i < TST_TOTAL; i++) { 114 TEST(CHOWN(cleanup, tc[i].pathname, user_id, group_id)); 115 116 if (TEST_RETURN == 0) { 117 tst_resm(TFAIL, "chown succeeded unexpectedly"); 118 continue; 119 } 120 121 if (TEST_ERRNO == tc[i].exp_errno) { 122 tst_resm(TPASS | TTERRNO, "chown failed"); 123 } else { 124 tst_resm(TFAIL | TTERRNO, 125 "chown failed; expected: %d - %s", 126 tc[i].exp_errno, 127 tst_strerrno(tc[i].exp_errno)); 128 } 129 } 130 } 131 132 cleanup(); 133 tst_exit(); 134 } 135 136 static void setup(void) 137 { 138 struct passwd *ltpuser; 139 const char *fs_type; 140 141 tst_require_root(); 142 tst_sig(FORK, DEF_HANDLER, cleanup); 143 ltpuser = SAFE_GETPWNAM(NULL, "nobody"); 144 145 tst_tmpdir(); 146 147 fs_type = tst_dev_fs_type(); 148 device = tst_acquire_device(cleanup); 149 if (!device) 150 tst_brkm(TCONF, cleanup, "Failed to obtain block device"); 151 152 tst_mkfs(cleanup, device, fs_type, NULL, NULL); 153 154 TEST_PAUSE; 155 156 memset(long_path, 'a', PATH_MAX - 1); 157 158 bad_addr = mmap(0, 1, PROT_NONE, 159 MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0); 160 if (bad_addr == MAP_FAILED) 161 tst_brkm(TBROK | TERRNO, cleanup, "mmap failed"); 162 163 tc[2].pathname = bad_addr; 164 165 SAFE_SYMLINK(cleanup, "test_eloop1", "test_eloop2"); 166 SAFE_SYMLINK(cleanup, "test_eloop2", "test_eloop1"); 167 168 SAFE_SETEUID(cleanup, 0); 169 SAFE_TOUCH(cleanup, "t_file", MODE_RWX, NULL); 170 SAFE_TOUCH(cleanup, TEST_FILE1, 0666, NULL); 171 SAFE_MKDIR(cleanup, DIR_TEMP, S_IRWXU); 172 SAFE_TOUCH(cleanup, TEST_FILE2, 0666, NULL); 173 174 SAFE_MKDIR(cleanup, "mntpoint", DIR_MODE); 175 if (mount(device, "mntpoint", fs_type, MS_RDONLY, NULL) < 0) { 176 tst_brkm(TBROK | TERRNO, cleanup, 177 "mount device:%s failed", device); 178 } 179 mount_flag = 1; 180 181 SAFE_SETEUID(cleanup, ltpuser->pw_uid); 182 } 183 184 void cleanup(void) 185 { 186 if (seteuid(0) == -1) 187 tst_resm(TWARN | TERRNO, "seteuid(0) failed"); 188 189 if (mount_flag && tst_umount("mntpoint") < 0) { 190 tst_brkm(TBROK | TERRNO, NULL, 191 "umount device:%s failed", device); 192 } 193 194 if (device) 195 tst_release_device(device); 196 197 tst_rmdir(); 198 } 199