Home | History | Annotate | Download | only in lstat
      1 /*
      2  *   Copyright (c) International Business Machines  Corp., 2001
      3  *   07/2001 Ported by Wayne Boyer
      4  *
      5  *   This program is free software;  you can redistribute it and/or modify
      6  *   it under the terms of the GNU General Public License as published by
      7  *   the Free Software Foundation; either version 2 of the License, or
      8  *   (at your option) any later version.
      9  *
     10  *   This program is distributed in the hope that it will be useful,
     11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
     12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     13  *   the GNU General Public License for more details.
     14  *
     15  *   You should have received a copy of the GNU General Public License
     16  *   along with this program;  if not, write to the Free Software Foundation,
     17  *   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     18  */
     19 /*
     20  * Test Description:
     21  *   Verify that,
     22  *   1) lstat(2) returns -1 and sets errno to EACCES if search permission is
     23  *	denied on a component of the path prefix.
     24  *   2) lstat(2) returns -1 and sets errno to ENOENT if the specified file
     25  *	does not exists or empty string.
     26  *   3) lstat(2) returns -1 and sets errno to EFAULT if pathname points
     27  *	outside user's accessible address space.
     28  *   4) lstat(2) returns -1 and sets errno to ENAMETOOLONG if the pathname
     29  *	component is too long.
     30  *   5) lstat(2) returns -1 and sets errno to ENOTDIR if the directory
     31  *	component in pathname is not a directory.
     32  *   6) lstat(2) returns -1 and sets errno to ELOOP if the pathname has too
     33  *	many symbolic links encountered while traversing.
     34  */
     35 
     36 #include <stdio.h>
     37 #include <stdlib.h>
     38 #include <unistd.h>
     39 #include <fcntl.h>
     40 #include <errno.h>
     41 #include <string.h>
     42 #include <signal.h>
     43 #include <sys/types.h>
     44 #include <sys/stat.h>
     45 #include <sys/mman.h>
     46 #include <pwd.h>
     47 
     48 #include "test.h"
     49 #include "safe_macros.h"
     50 
     51 #define MODE_RWX	S_IRWXU | S_IRWXG | S_IRWXO
     52 #define FILE_MODE	S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
     53 #define TEST_DIR	"test_dir"
     54 #define TEST_EACCES	TEST_DIR"/test_eacces"
     55 #define TEST_ENOENT	""
     56 #define TEST_ENOTDIR	"test_file/test_enotdir"
     57 #define TEST_ELOOP	"/test_eloop"
     58 
     59 static char longpathname[PATH_MAX + 2];
     60 static char elooppathname[sizeof(TEST_ELOOP) * 43] = ".";
     61 
     62 #if !defined(UCLINUX)
     63 static void bad_addr_setup(int);
     64 static void high_address_setup(int);
     65 #endif
     66 
     67 static struct test_case_t {
     68 	char *pathname;
     69 	int exp_errno;
     70 	void (*setup) ();
     71 } test_cases[] = {
     72 	{TEST_EACCES, EACCES, NULL},
     73 	{TEST_ENOENT, ENOENT, NULL},
     74 #if !defined(UCLINUX)
     75 	{NULL, EFAULT, bad_addr_setup},
     76 	{NULL, EFAULT, high_address_setup},
     77 #endif
     78 	{longpathname, ENAMETOOLONG, NULL},
     79 	{TEST_ENOTDIR, ENOTDIR, NULL},
     80 	{elooppathname, ELOOP, NULL},
     81 };
     82 
     83 char *TCID = "lstat02";
     84 int TST_TOTAL = ARRAY_SIZE(test_cases);
     85 
     86 static void setup(void);
     87 static void lstat_verify(int);
     88 static void cleanup(void);
     89 
     90 int main(int ac, char **av)
     91 {
     92 	int lc;
     93 	int i;
     94 
     95 	tst_parse_opts(ac, av, NULL, NULL);
     96 
     97 	setup();
     98 
     99 	for (lc = 0; TEST_LOOPING(lc); lc++) {
    100 		tst_count = 0;
    101 		for (i = 0; i < TST_TOTAL; i++)
    102 			lstat_verify(i);
    103 	}
    104 
    105 	cleanup();
    106 	tst_exit();
    107 }
    108 
    109 static void setup(void)
    110 {
    111 	int i;
    112 	struct passwd *ltpuser;
    113 
    114 	tst_require_root();
    115 
    116 	tst_sig(NOFORK, DEF_HANDLER, cleanup);
    117 
    118 	ltpuser = SAFE_GETPWNAM(cleanup, "nobody");
    119 	SAFE_SETEUID(cleanup, ltpuser->pw_uid);
    120 
    121 	TEST_PAUSE;
    122 
    123 	tst_tmpdir();
    124 
    125 	SAFE_MKDIR(cleanup, TEST_DIR, MODE_RWX);
    126 	SAFE_TOUCH(cleanup, TEST_EACCES, 0666, NULL);
    127 	SAFE_CHMOD(cleanup, TEST_DIR, FILE_MODE);
    128 
    129 	SAFE_TOUCH(cleanup, "test_file", MODE_RWX, NULL);
    130 
    131 	memset(longpathname, 'a', PATH_MAX+1);
    132 
    133 	SAFE_MKDIR(cleanup, "test_eloop", MODE_RWX);
    134 	SAFE_SYMLINK(cleanup, "../test_eloop", "test_eloop/test_eloop");
    135 	/*
    136 	 * NOTE: the ELOOP test is written based on that the consecutive
    137 	 * symlinks limits in kernel is hardwired to 40.
    138 	 */
    139 	for (i = 0; i < 43; i++)
    140 		strcat(elooppathname, TEST_ELOOP);
    141 }
    142 
    143 #if !defined(UCLINUX)
    144 static void bad_addr_setup(int i)
    145 {
    146 	test_cases[i].pathname = SAFE_MMAP(cleanup, 0, 1, PROT_NONE,
    147 					   MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
    148 }
    149 
    150 static void high_address_setup(int i)
    151 {
    152 	test_cases[i].pathname = (char *)get_high_address();
    153 }
    154 #endif
    155 
    156 static void lstat_verify(int i)
    157 {
    158 	struct stat stat_buf;
    159 
    160 	if (test_cases[i].setup != NULL)
    161 		test_cases[i].setup(i);
    162 
    163 	TEST(lstat(test_cases[i].pathname, &stat_buf));
    164 
    165 	if (TEST_RETURN != -1) {
    166 		tst_resm(TFAIL, "lstat() returned %ld, expected -1, errno=%d",
    167 			 TEST_RETURN, test_cases[i].exp_errno);
    168 		return;
    169 	}
    170 
    171 	if (TEST_ERRNO == test_cases[i].exp_errno) {
    172 		tst_resm(TPASS | TTERRNO, "lstat() failed as expected");
    173 	} else {
    174 		tst_resm(TFAIL | TTERRNO,
    175 			 "lstat() failed unexpectedly; expected: %d - %s",
    176 			 test_cases[i].exp_errno,
    177 			 strerror(test_cases[i].exp_errno));
    178 	}
    179 }
    180 
    181 static void cleanup(void)
    182 {
    183 	if (seteuid(0))
    184 		tst_resm(TINFO | TERRNO, "Failet to seteuid(0) before cleanup");
    185 
    186 	tst_rmdir();
    187 }
    188