1/* 2 * Copyright (c) 2014 Fujitsu Ltd. 3 * Author: Zeng Linggang <zenglg.jy@cn.fujitsu.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of version 2 of the GNU General Public License as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it would be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 * 13 * You should have received a copy of the GNU General Public License along 14 * with this program. 15 */ 16/* 17 * Test Description: 18 * Verify that, 19 * The flag of fchownat() is AT_SYMLINK_NOFOLLOW and the pathname would 20 * not be dereferenced if the pathname is a symbolic link. 21 */ 22 23#define _GNU_SOURCE 24 25#include <sys/types.h> 26#include <sys/stat.h> 27#include <fcntl.h> 28#include <unistd.h> 29#include <stdlib.h> 30#include <errno.h> 31#include <string.h> 32#include <signal.h> 33#include "test.h" 34#include "safe_macros.h" 35#include "fchownat.h" 36#include "lapi/fcntl.h" 37 38#define TESTFILE "testfile" 39#define TESTFILE_LINK "testfile_link" 40 41char *TCID = "fchownat02"; 42int TST_TOTAL = 1; 43 44static int dir_fd; 45static uid_t set_uid = 1000; 46static gid_t set_gid = 1000; 47static void setup(void); 48static void cleanup(void); 49static void test_verify(void); 50static void fchownat_verify(void); 51 52int main(int ac, char **av) 53{ 54 int lc; 55 int i; 56 57 tst_parse_opts(ac, av, NULL, NULL); 58 59 setup(); 60 61 for (lc = 0; TEST_LOOPING(lc); lc++) { 62 tst_count = 0; 63 for (i = 0; i < TST_TOTAL; i++) 64 fchownat_verify(); 65 } 66 67 cleanup(); 68 tst_exit(); 69} 70 71static void setup(void) 72{ 73 struct stat c_buf, l_buf; 74 75 if ((tst_kvercmp(2, 6, 16)) < 0) 76 tst_brkm(TCONF, NULL, "This test needs kernel 2.6.16 or newer"); 77 78 tst_require_root(); 79 80 tst_sig(NOFORK, DEF_HANDLER, cleanup); 81 82 TEST_PAUSE; 83 84 tst_tmpdir(); 85 86 dir_fd = SAFE_OPEN(cleanup, "./", O_DIRECTORY); 87 88 SAFE_TOUCH(cleanup, TESTFILE, 0600, NULL); 89 90 SAFE_SYMLINK(cleanup, TESTFILE, TESTFILE_LINK); 91 92 SAFE_STAT(cleanup, TESTFILE_LINK, &c_buf); 93 94 SAFE_LSTAT(cleanup, TESTFILE_LINK, &l_buf); 95 96 if (l_buf.st_uid == set_uid || l_buf.st_gid == set_gid) { 97 tst_brkm(TBROK | TERRNO, cleanup, 98 "link_uid(%d) == set_uid(%d) or link_gid(%d) == " 99 "set_gid(%d)", l_buf.st_uid, set_uid, l_buf.st_gid, 100 set_gid); 101 } 102} 103 104static void fchownat_verify(void) 105{ 106 TEST(fchownat(dir_fd, TESTFILE_LINK, set_uid, set_gid, 107 AT_SYMLINK_NOFOLLOW)); 108 109 if (TEST_RETURN != 0) { 110 tst_resm(TFAIL | TTERRNO, "fchownat() failed, errno=%d : %s", 111 TEST_ERRNO, strerror(TEST_ERRNO)); 112 } else { 113 test_verify(); 114 } 115} 116 117static void test_verify(void) 118{ 119 struct stat c_buf, l_buf; 120 121 SAFE_STAT(cleanup, TESTFILE_LINK, &c_buf); 122 123 SAFE_LSTAT(cleanup, TESTFILE_LINK, &l_buf); 124 125 if (c_buf.st_uid != set_uid && l_buf.st_uid == set_uid && 126 c_buf.st_gid != set_gid && l_buf.st_gid == set_gid) { 127 tst_resm(TPASS, "fchownat() test AT_SYMLINK_NOFOLLOW success"); 128 } else { 129 tst_resm(TFAIL, 130 "fchownat() test AT_SYMLINK_NOFOLLOW fail with uid=%d " 131 "link_uid=%d set_uid=%d | gid=%d link_gid=%d " 132 "set_gid=%d", c_buf.st_uid, l_buf.st_uid, set_uid, 133 c_buf.st_gid, l_buf.st_gid, set_gid); 134 } 135} 136 137static void cleanup(void) 138{ 139 tst_rmdir(); 140} 141