Hi! Hope that this version is final. See attached patch. Signed-off-by: Cyril Hrubis [email protected]
-- Cyril Hrubis [email protected]
diff --git a/include/test.h b/include/test.h index e291b36..7ac182a 100644 --- a/include/test.h +++ b/include/test.h @@ -262,6 +262,11 @@ int ltp_clone_quick(unsigned long clone_flags, int (*fn)(void *arg), char *get_block_device(const char *path); char *get_mountpoint(const char *path); +/* + * Function from lib/get_path.c + */ +int tst_get_path(const char *prog_name, char *buf, size_t buf_len); + #ifdef TST_USE_COMPAT16_SYSCALL #define TCID_BIT_SUFFIX "_16" #elif TST_USE_NEWER64_SYSCALL diff --git a/lib/get_path.c b/lib/get_path.c new file mode 100644 index 0000000..89334a8 --- /dev/null +++ b/lib/get_path.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2010 Cyril Hrubis [email protected] + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + */ + + /* + * Looks for binary prog_name in $PATH. + * + * If such file exists and if you are able at least to read it, zero is + * returned and absolute path to the file is filled into buf. In case buf is + * too short to hold the absolute path + prog_name for the file we are looking + * for -1 is returned as well as when there is no such file in all paths in + * $PATH. + */ + +#include "test.h" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> + +#define MIN(a, b) ((a)<(b)?(a):(b)) + +static int file_exist(const char *path) +{ + struct stat st; + + if (!access(path, R_OK) && !stat(path, &st) && S_ISREG(st.st_mode)) + return 1; + + return 0; +} + +int tst_get_path(const char *prog_name, char *buf, size_t buf_len) +{ + const char *path = (const char*) getenv("PATH"); + const char *start = path; + const char *end; + size_t size, ret; + + + if (path == NULL) + return -1; + + do { + end = strchr(start, ':'); + + if (end != NULL) + snprintf(buf, MIN(buf_len, (size_t)(end - start + 1)), "%s", start); + else + snprintf(buf, buf_len, "%s", start); + + size = strlen(buf); + + /* + * "::" inside $PATH, $PATH ending with ':' or $PATH strarting + * with ':' should be expanded into current working directory. + */ + if (size == 0) { + snprintf(buf, buf_len, "."); + size = strlen(buf); + } + + /* + * If there is no '/' ad the end of path from $PATH add it. + */ + if (buf[size - 1] != '/') + ret = snprintf(buf + size, buf_len - size, "/%s", prog_name); + else + ret = snprintf(buf + size, buf_len - size, "%s", prog_name); + + if (buf_len - size > ret && file_exist(buf)) + return 0; + + start = end + 1; + + } while (end != NULL); + + return -1; +} diff --git a/runltp b/runltp index 07994e9..7a8ac28 100755 --- a/runltp +++ b/runltp @@ -570,6 +570,7 @@ main() for SCENFILES in ${LTPROOT}/runtest/syscalls \ ${LTPROOT}/runtest/fs \ + ${LTPROOT}/runtest/fs_perms_simple \ ${LTPROOT}/runtest/fsx \ ${LTPROOT}/runtest/dio \ ${LTPROOT}/runtest/io \ diff --git a/runtest/fs b/runtest/fs index 75c5e38..2de871d 100644 --- a/runtest/fs +++ b/runtest/fs @@ -64,9 +64,6 @@ writetest01 writetest #Also run the fs_di (Data Integrity tests) fs_di fs_di -d $TMPDIR -#Also run the fs_perms (File System Permission Tests) -fs_perms fs_perms_simpletest.sh - # Read every file in /proc. Not likely to crash, but does enough # to disturb the kernel. A good kernel latency killer too. # Was not sure why it should reside in runtest/crashme and won´t get tested ever diff --git a/runtest/fs_perms_simple b/runtest/fs_perms_simple new file mode 100644 index 0000000..cc986bd --- /dev/null +++ b/runtest/fs_perms_simple @@ -0,0 +1,26 @@ +# +# These tests are setting file permissions/group/uid and are trying to +# open/write/execute the file. +# +# +# +# fs_perms file_mode file_uid file_gid test_uid test_gid mode (r|w|x) expected_result +# +fs_perms01 fs_perms 001 99 99 12 100 x 0 +fs_perms02 fs_perms 010 99 99 200 99 x 0 +fs_perms03 fs_perms 100 99 99 99 500 x 0 +fs_perms04 fs_perms 002 99 99 12 100 w 0 +fs_perms05 fs_perms 020 99 99 200 99 w 0 +fs_perms06 fs_perms 200 99 99 99 500 w 0 +fs_perms07 fs_perms 004 99 99 12 100 r 0 +fs_perms08 fs_perms 040 99 99 200 99 r 0 +fs_perms09 fs_perms 400 99 99 99 500 r 0 +fs_perms10 fs_perms 000 99 99 99 99 r 1 +fs_perms11 fs_perms 000 99 99 99 99 w 1 +fs_perms12 fs_perms 000 99 99 99 99 x 1 +fs_perms13 fs_perms 010 99 99 99 500 x 1 +fs_perms14 fs_perms 100 99 99 200 99 x 1 +fs_perms15 fs_perms 020 99 99 99 500 w 1 +fs_perms16 fs_perms 200 99 99 200 99 w 1 +fs_perms17 fs_perms 040 99 99 99 500 r 1 +fs_perms18 fs_perms 400 99 99 200 99 r 1 diff --git a/testcases/kernel/fs/fs_perms/Makefile b/testcases/kernel/fs/fs_perms/Makefile index 48aa7d6..c0377cc 100644 --- a/testcases/kernel/fs/fs_perms/Makefile +++ b/testcases/kernel/fs/fs_perms/Makefile @@ -23,7 +23,4 @@ top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk - -INSTALL_TARGETS := fs_perms_simpletest.sh - include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/fs/fs_perms/fs_perms.c b/testcases/kernel/fs/fs_perms/fs_perms.c index ad44028..9fbe9ec 100644 --- a/testcases/kernel/fs/fs_perms/fs_perms.c +++ b/testcases/kernel/fs/fs_perms/fs_perms.c @@ -1,5 +1,6 @@ /* * Copyright (c) International Business Machines Corp., 2000 + * Copyright (c) 2010 Cyril Hrubis [email protected] * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,9 +26,12 @@ * (04/19/01)v1.0 Added test for execute bit. * (05/23/01)v1.1 Added command line parameter to specify test file. * (07/12/01)v1.2 Removed conf file and went to command line parameters. + * (10/19/04) Rewritten to fit ltp test interface. + * Also now we try to run two different files, one is executed by execl, + * has shebang and should end up executed by kernel, other one is empty + * is executed by execlp and should end up executed by libc. */ -#include <errno.h> #include <stdio.h> #include <string.h> #include <ctype.h> @@ -36,117 +40,190 @@ #include <stdlib.h> #include <unistd.h> #include <wait.h> +#include <linux/limits.h> #include "test.h" +#define TEST_FILE_NAME1 "./test.file1" +#define TEST_FILE_NAME2 "./test.file2" + char *TCID = "fs_perms"; int TST_TOTAL = 1; -static int testsetup(mode_t mode, int cuserId, int cgroupId) -{ - int ret; - char cmd_str[256]; - - sprintf(cmd_str, "cp %s/testx test.file", getcwd(NULL, 0)); - tst_tmpdir(); - - ret = unlink("test.file"); - if (ret && errno != ENOENT) - goto done; - ret = system(cmd_str); - if (ret) - goto done; - ret = chmod("test.file", mode); - if (ret) - goto done; - ret = chown("test.file", cuserId, cgroupId); - - done: - return ret; -} - -void cleanup(void) +static void cleanup(void) { + seteuid(0); + setegid(0); + tst_rmdir(); tst_exit(); } -static int testfperm(int userId, int groupId, char *fperm) +/* + * Create file and set permissions, user id, group id. + * + * If flag is non zero, the file contains #!/PATH/sh shebang otherwise it's + * empty. + */ +static void testsetup(const char *file_name, int flag, mode_t mode, + int user_id, int group_id) { - /* SET CURRENT USER/GROUP PERMISSIONS */ - if (setegid(groupId)) { - tst_brkm(TBROK, cleanup, "could not setegid to %d: %s", groupId, strerror(errno)); - seteuid(0); - setegid(0); - return -1; - } - if (seteuid(userId)) { - tst_brkm(TBROK, cleanup, "could not seteuid to %d: %s", userId, strerror(errno)); - seteuid(0); - setegid(0); - return -1; + FILE *file; + + file = fopen(file_name, "w"); + + if (file == NULL) + tst_brkm(TBROK | TERRNO, cleanup, + "Could not create test file %s.", file_name); + + /* create file with shebang */ + if (flag) { + char buf[PATH_MAX]; + + if (tst_get_path("sh", buf, PATH_MAX)) + tst_brkm(TBROK, cleanup, + "Could not find path to sh in $PATH."); + + if (fprintf(file, "#!%s\n", buf) < 0) + tst_brkm(TBROK, cleanup, "Calling fprintf failed."); } - switch (tolower(fperm[0])) { - case 'x': { + if (fclose(file)) + tst_brkm(TBROK | TERRNO, cleanup, "Calling fclose failed."); + + if (chmod(file_name, mode)) + tst_brkm(TBROK | TERRNO, cleanup, + "Could not chmod test file %s.", file_name); + + if (chown(file_name, user_id, group_id)) + tst_brkm(TBROK | TERRNO, cleanup, + "Could not chown test file %s.", file_name); +} + +/* + * Test permissions. + */ +static int testfperm(const char *file_name, int flag, int user_id, + int group_id, char *fperm) + +{ + FILE *file; + int ret; + + if (setegid(group_id)) + tst_brkm(TBROK | TERRNO, cleanup, "Could not setegid to %d.", + group_id); + + if (seteuid(user_id)) + tst_brkm(TBROK | TERRNO, cleanup, "Could not seteuid to %d.", + user_id); + + if (tolower(fperm[0]) == 'x') { int status; + if (fork() == 0) { - execlp("./test.file", "test.file", NULL); + /* + * execlp runs file with sh in case kernel has + * no binmft handler for it, execl does not. + */ + if (flag) + execl(file_name, file_name, NULL); + else + execlp(file_name, "test", NULL); + exit(1); } + wait(&status); + seteuid(0); setegid(0); + return WEXITSTATUS(status); } - default: { - FILE *testfile; - if ((testfile = fopen("test.file", fperm))) { - fclose(testfile); - seteuid(0); - setegid(0); - return 0; - } else { - seteuid(0); - setegid(0); - return 1; - } - } - } + + if ((file = fopen(file_name, fperm)) != NULL) { + fclose(file); + ret = 0; + } else + ret = 1; + + seteuid(0); + setegid(0); + + return ret; +} + +static void print_usage(const char *bname) +{ + char *usage = "<file mode> <file UID> <file GID> " + "<tester UID> <tester GID> <permission " + "to test r|w|x> <expected result 0|1>"; + + printf("Usage: %s %s\n", bname, usage); +} + +static long str_to_l(const char *str, const char *name) +{ + char *end; + long i = strtol(str, &end, 10); + + if (*end != '\0') + tst_brkm(TBROK, tst_exit, "Invalid parameter '%s' passed. (%s)", + name, str); + + return i; } int main(int argc, char *argv[]) { char *fperm; - int result, exresult = 0, cuserId = 0, cgroupId = 0, userId = 0, groupId = 0; - mode_t mode; + gid_t fgroup_id, group_id; + uid_t fuser_id, user_id; + mode_t fmode; + int exp_res; + int res1, res2 = 1; tst_require_root(tst_exit); - switch (argc) { - case 8: - mode = strtol(argv[1], (char **)NULL, 010); - cuserId = atoi(argv[2]); - cgroupId = atoi(argv[3]); - userId = atoi(argv[4]); - groupId = atoi(argv[5]); - fperm = argv[6]; - exresult = atoi(argv[7]); - break; - default: - printf("Usage: %s <mode of file> <UID of file> <GID of file> <UID of tester> <GID of tester> <permission to test r|w|x> <expected result as 0|1>\n", argv[0]); - return 1; + if (argc != 8) { + print_usage(argv[0]); + tst_exit(); } - result = testsetup(mode, cuserId, cgroupId); - if (result) { - tst_brkm(TBROK, cleanup, "testsetup() failed: %s", strerror(errno)); + if (strlen(argv[6]) > 1) { + print_usage(argv[0]); + tst_exit(); } - result = testfperm(userId, groupId, fperm); - unlink("test.file"); - tst_resm(exresult == result ? TPASS : TFAIL, "%c a %03o file owned by (%d/%d) as user/group(%d/%d)", - fperm[0], mode, cuserId, cgroupId, userId, groupId); - cleanup(); - return 0; + fmode = str_to_l(argv[1], "file mode"); + fuser_id = str_to_l(argv[2], "file uid"); + fgroup_id = str_to_l(argv[3], "file gid"); + user_id = str_to_l(argv[4], "tester uid"); + group_id = str_to_l(argv[5], "tester gid"); + fperm = argv[6]; + exp_res = str_to_l(argv[7], "expected result"); + + tst_tmpdir(); + testsetup(TEST_FILE_NAME1, 0, fmode, fuser_id, fgroup_id); + + /* more tests for 'x' flag */ + if (tolower(fperm[0]) == 'x') { + testsetup(TEST_FILE_NAME2, 1, fmode, fuser_id, fgroup_id); + res2 = testfperm(TEST_FILE_NAME2, 1, user_id, group_id, fperm); + + if (res2 == exp_res) + res2 = 1; + else + res2 = 0; + } + + res1 = testfperm(TEST_FILE_NAME1, 0, user_id, group_id, fperm); + + tst_resm((exp_res == res1) && res2 ? TPASS : TFAIL, + "%c a %03o file owned by (%d/%d) as user/group (%d/%d)", + fperm[0], fmode, fuser_id, fgroup_id, user_id, group_id); + + tst_rmdir(); + tst_exit(); } diff --git a/testcases/kernel/fs/fs_perms/fs_perms_simpletest.sh b/testcases/kernel/fs/fs_perms/fs_perms_simpletest.sh deleted file mode 100755 index 5a8df8b..0000000 --- a/testcases/kernel/fs/fs_perms/fs_perms_simpletest.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh - -Code=0 - -test() -{ - arg=${1}; shift - res=${1} - - ./fs_perms ${arg} ${res} - if [ $? -ne 0 ]; then - Code=$((Code + 1)) - fi -} - -test "001 99 99 12 100 x" 0 -test "010 99 99 200 99 x" 0 -test "100 99 99 99 500 x" 0 -test "002 99 99 12 100 w" 0 -test "020 99 99 200 99 w" 0 -test "200 99 99 99 500 w" 0 -test "004 99 99 12 100 r" 0 -test "040 99 99 200 99 r" 0 -test "400 99 99 99 500 r" 0 -test "000 99 99 99 99 r" 1 -test "000 99 99 99 99 w" 1 -test "000 99 99 99 99 x" 1 -test "010 99 99 99 500 x" 1 -test "100 99 99 200 99 x" 1 -test "020 99 99 99 500 w" 1 -test "200 99 99 200 99 w" 1 -test "040 99 99 99 500 r" 1 -test "400 99 99 200 99 r" 1 - -exit ${Code} diff --git a/testcases/kernel/fs/fs_perms/testx.c b/testcases/kernel/fs/fs_perms/testx.c deleted file mode 100644 index 5944ce0..0000000 --- a/testcases/kernel/fs/fs_perms/testx.c +++ /dev/null @@ -1,4 +0,0 @@ -#include <stdio.h> -int main(void) { - return 0; -}
------------------------------------------------------------------------------
_______________________________________________ Ltp-list mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/ltp-list
