public inbox for ltp@lists.linux.it
 help / color / mirror / Atom feed
* [LTP] [PATCH] New core test of hardlinks and symlinks restrictions added in Linux 3.6. Disabled by default in Linux 3.7.
@ 2013-05-06  9:41 Alexey Kodanev
  2013-05-06 13:47 ` chrubis
  2013-05-06 15:55 ` Mike Frysinger
  0 siblings, 2 replies; 9+ messages in thread
From: Alexey Kodanev @ 2013-05-06  9:41 UTC (permalink / raw)
  To: ltp-list; +Cc: vasily.isaenko, Alexey Kodanev

Signed-off-by: Alexey Kodanev <alexey.kodanev@oracle.com>
---
 .../kernel/security/prot_hsymlinks/.gitignore      |    1 +
 testcases/kernel/security/prot_hsymlinks/Makefile  |   19 +
 testcases/kernel/security/prot_hsymlinks/README    |   24 +
 .../security/prot_hsymlinks/prot_hsymlinks.c       |  587 ++++++++++++++++++++
 4 files changed, 631 insertions(+), 0 deletions(-)
 create mode 100644 testcases/kernel/security/prot_hsymlinks/.gitignore
 create mode 100644 testcases/kernel/security/prot_hsymlinks/Makefile
 create mode 100644 testcases/kernel/security/prot_hsymlinks/README
 create mode 100644 testcases/kernel/security/prot_hsymlinks/prot_hsymlinks.c

diff --git a/testcases/kernel/security/prot_hsymlinks/.gitignore b/testcases/kernel/security/prot_hsymlinks/.gitignore
new file mode 100644
index 0000000..68e41da
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/.gitignore
@@ -0,0 +1 @@
+/prot_hsymlinks
diff --git a/testcases/kernel/security/prot_hsymlinks/Makefile b/testcases/kernel/security/prot_hsymlinks/Makefile
new file mode 100644
index 0000000..cd49588
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/Makefile
@@ -0,0 +1,19 @@
+# Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+#
+# 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 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.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
+
+top_srcdir		?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/security/prot_hsymlinks/README b/testcases/kernel/security/prot_hsymlinks/README
new file mode 100644
index 0000000..a745c8b
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/README
@@ -0,0 +1,24 @@
+TEST SUITE:
+
+The directory prot_hsymlinks contains the tests related to harlinks and
+symlinks restrictions.
+
+TESTS AIM:
+
+The aim of the tests is to check the restrictions
+for hardlinks and symlinks.
+
+This security restrictions were added in Linux 3.6 and enabled by default,
+but it broke some programs. It has been disabled by default in Linux 3.7 and
+to control it, special proc parameters added. Distributions and users
+can enable it by writing "1" to /proc/sys/fs/protected_symlinks,
+/proc/sys/fs/protected_hardlinks.
+
+This test enables restrictions and checks following preconditions:
+
+1. Users who own sticky world-writable directory can't follow symlinks
+inside that directory if their don't own ones. All other users can follow.
+
+2. Hard links restriction applies only to non-privileged users. Only
+non-privileged user can't create hard links to files if he isn't owner
+of the file or he doesn't have write access to the file.
diff --git a/testcases/kernel/security/prot_hsymlinks/prot_hsymlinks.c b/testcases/kernel/security/prot_hsymlinks/prot_hsymlinks.c
new file mode 100644
index 0000000..fcb5f28
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/prot_hsymlinks.c
@@ -0,0 +1,587 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ *
+ * 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 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.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author:
+ * Alexey Kodanev <alexey.kodanev@oracle.com>
+ *
+ * Test checks following preconditions:
+ *
+ * Symlinks
+ * ---------
+ * Users who own sticky world-writable directory can't follow symlinks
+ * inside that directory if their don't own ones. All other users can follow.
+ *
+ * Hardlinks
+ * ---------
+ * Hard links restriction applies only to non-privileged users. Only
+ * non-privileged user can't create hard links to files if he isn't owner
+ * of the file or he doesn't have write access to the file.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+#include "test.h"
+#include "usctest.h"
+#include "safe_macros.h"
+
+char *TCID = "prot_hsymlinks";
+int TST_TOTAL = 396;
+
+/* create 3 files and 1 dir in each base dir */
+#define MAX_FILES_CREATED	4
+#define MAX_PATH		128
+#define MAX_CMD_LEN		64
+#define MAX_USER_NAME		16
+
+enum {
+	ROOT = 0,
+	TEST_USER,
+	USERS_NUM
+};
+
+#define BASE_DIR_NUM		(USERS_NUM+1)
+/*
+ * max test files and directories
+ * that will be created during the test
+ * is't not include symlinks and hardlinks
+ * and base directories
+ */
+#define MAX_ENTITIES		(MAX_FILES_CREATED*BASE_DIR_NUM)
+
+struct dir_params {
+	char path[MAX_PATH];
+	int world_writable;
+	int sticky;
+	int owner;
+};
+
+static struct dir_params bdirs[BASE_DIR_NUM];
+
+static const char *file_postfix = ".hs";
+
+enum {
+	IS_FILE = 0,
+	IS_DIRECTORY,
+};
+
+struct user_file {
+	char path[MAX_PATH];
+	int is_dir;
+};
+
+struct test_user {
+	char name[MAX_USER_NAME];
+	struct user_file file[MAX_ENTITIES];
+	int num;
+};
+
+static struct test_user users[USERS_NUM];
+
+struct link_info {
+	char path[MAX_PATH];
+	int owner;
+	int source_owner;
+	int in_world_write;
+	int in_sticky;
+	int is_dir;
+	int dir_owner;
+};
+
+/* test flags */
+enum {
+	CANNOT_FOLLOW = -1,
+	CAN_FOLLOW = 0,
+};
+
+enum {
+	CANNOT_CREATE = -1,
+	CAN_CREATE = 0,
+};
+
+static char *tmp_user_name;
+static char *default_user = "hsym";
+static int nflag;
+static int skip_cleanup;
+
+option_t options[] = {
+	{"u:", &nflag, &tmp_user_name},	/* -u #user name */
+	{"s", &skip_cleanup, NULL},
+	{NULL, NULL, NULL}
+};
+/* full length of the test tmpdir path in /tmp */
+static int cwd_offset;
+
+static const char *hrdlink_proc_path	= "/proc/sys/fs/protected_hardlinks";
+static const char *symlink_proc_path	= "/proc/sys/fs/protected_symlinks";
+
+static void help(void);
+static void setup(int ac, char **av);
+static void cleanup(void);
+
+static void create_test_user(void);
+static void delete_test_user(void);
+
+static int disable_protected_slinks;
+static int disable_protected_hlinks;
+
+/*
+ * changes links restrictions
+ * @param value can be:
+ * 0 - restrictions is off
+ * 1 - restrictions is on
+ */
+static void switch_protected_slinks(int value);
+static void switch_protected_hlinks(int value);
+
+static int get_protected_slinks(void);
+static int get_protected_hlinks(void);
+
+static void create_link_path(char *buffer, int size, const char *path);
+static int create_check_hlinks(const struct user_file *ufile, int owner_idx);
+static int create_check_slinks(const struct user_file *ufile, int owner_idx);
+static int check_symlink(const struct link_info *li);
+static int try_fopen(const char *name, int mode);
+/* try to open symlink in diff modes */
+static int try_symlink(const char *name);
+
+static int test_run(void);
+static void init_base_dirs(void);
+static void init_files_dirs(void);
+
+/* change effective user id and group id by name
+ * pass NULL to set root
+ */
+static void set_user(const char *name);
+
+/* add new created files to user struct */
+static void ufiles_add(int user_idx, char *path, int type);
+
+int main(int ac, char **av)
+{
+	setup(ac, av);
+
+	test_run();
+
+	cleanup();
+
+	tst_exit();
+}
+
+static void setup(int ac, char **av)
+{
+	char *msg;
+	msg = parse_opts(ac, av, options, &help);
+	if (msg != NULL)
+		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
+
+	tst_require_root(NULL);
+
+	if (tst_kvercmp(3, 7, 0) < 0) {
+		tst_brkm(TCONF, &cleanup,
+		"Test must be run with kernel 3.7 or newer");
+	}
+
+	/* initialize user names */
+	strcpy(users[ROOT].name, "root");
+
+	if (tmp_user_name == NULL)
+		tmp_user_name = default_user;
+	snprintf(users[TEST_USER].name, MAX_USER_NAME, "%s", tmp_user_name);
+
+	tst_sig(FORK, DEF_HANDLER, &cleanup);
+
+	create_test_user();
+	/*
+	 * enable hardlinks and symlinks restrictions,
+	 * it's not defualt but have to check
+	 */
+	if (!get_protected_hlinks()) {
+	    switch_protected_hlinks(1);
+	    disable_protected_hlinks = 1;
+	}
+	if (!get_protected_slinks()) {
+	    switch_protected_slinks(1);
+	    disable_protected_slinks = 1;
+	}
+
+	init_base_dirs();
+
+	init_files_dirs();
+}
+
+static int test_run(void)
+{
+	tst_resm(TINFO, " --- HARDLINKS AND SYMLINKS RESTRICTIONS TEST ---\n");
+
+	int	result_slink = 0,
+		result_hlink = 0,
+		owner_idx,
+		file_idx;
+
+	const struct user_file *ufile;
+	/*
+	 * create symlinks and hardlinks from each user's files
+	 * to each world writable directory
+	 */
+	for (owner_idx = 0; owner_idx < USERS_NUM; ++owner_idx) {
+		/* get all users files and directories */
+		for (file_idx = 0; file_idx < users[owner_idx].num; ++file_idx) {
+			ufile = &users[owner_idx].file[file_idx];
+			result_slink |= create_check_slinks(ufile, owner_idx);
+			result_hlink |= create_check_hlinks(ufile, owner_idx);
+		}
+	}
+
+	/* final results */
+	tst_resm(TINFO, "All test-cases have been completed, summary:\n"
+		" - symlinks  test:\t%s\n"
+		" - hardlinks test:\t%s",
+		(result_slink == 1) ? "FAIL" : "PASS",
+		(result_hlink == 1) ? "FAIL" : "PASS");
+
+	return result_slink | result_hlink;
+}
+
+static void cleanup(void)
+{
+	set_user(NULL);
+
+	if (skip_cleanup)
+		return;
+
+	delete_test_user();
+
+	if (disable_protected_hlinks) {
+		tst_resm(TINFO, "Disable protected hardlinks mode back");
+		switch_protected_hlinks(0);
+	}
+	if (disable_protected_slinks) {
+		tst_resm(TINFO, "Disable protected symlinks mode back");
+		switch_protected_slinks(0);
+	}
+
+	tst_rmdir();
+	TEST_CLEANUP;
+}
+
+static int get_protected_hlinks(void)
+{
+	int value = 0;
+	SAFE_FILE_SCANF(&cleanup, hrdlink_proc_path, "%d", &value);
+	return value;
+}
+
+static int get_protected_slinks(void)
+{
+	int value = 0;
+	SAFE_FILE_SCANF(&cleanup, symlink_proc_path, "%d", &value);
+	return value;
+}
+
+static void switch_protected_hlinks(int value)
+{
+	SAFE_FILE_PRINTF(&cleanup, hrdlink_proc_path, "%d", value == 1);
+}
+
+static void switch_protected_slinks(int value)
+{
+	SAFE_FILE_PRINTF(&cleanup, symlink_proc_path, "%d", value == 1);
+}
+
+static void create_test_user(void)
+{
+	char cmd[MAX_CMD_LEN];
+	snprintf(cmd, MAX_CMD_LEN, "%s %s", "useradd", users[TEST_USER].name);
+	if (system(cmd) != 0) {
+		tst_brkm(TBROK, &cleanup, "Can't create new user: %s",
+			users[TEST_USER].name);
+	}
+}
+
+static void delete_test_user(void)
+{
+	char cmd[MAX_CMD_LEN];
+	snprintf(cmd, MAX_CMD_LEN, "%s %s", "userdel -r", users[TEST_USER].name);
+	if (system(cmd) != 0) {
+		tst_brkm(TBROK, &cleanup, "Can't delete user: %s",
+			users[TEST_USER].name);
+	}
+}
+
+static void help(void)
+{
+	printf("  -s      Skip cleanup.\n");
+	printf("  -u #user name : Define test user\n");
+}
+
+static void create_sub_dir(const char *path,
+	struct dir_params *bdir, mode_t mode)
+{
+	snprintf(bdir->path, MAX_PATH, "%s/tmp_%s", path, users[bdir->owner].name);
+	SAFE_MKDIR(&cleanup, bdir->path, mode);
+
+	if (bdir->sticky)
+	    mode |= S_ISVTX;
+	chmod(bdir->path, mode);
+}
+
+static void init_base_dirs(void)
+{
+	memset(&bdirs, 0, sizeof(bdirs));
+
+	/* create main dir, world-writable */
+	tst_tmpdir();
+
+	char *cwd = get_tst_tmpdir();
+	cwd_offset = strlen(cwd);
+
+	mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
+	chmod(cwd, mode);
+
+	struct dir_params *bdir = bdirs;
+	strcpy(bdir->path, cwd);
+	free(cwd);
+
+	bdir->sticky  = 0;
+	bdir->world_writable = 1;
+
+	/* create subdir for each user */
+	++bdir;
+	int idx;
+	for (idx = 0; idx < USERS_NUM; ++idx, ++bdir) {
+		set_user(users[idx].name);
+
+		bdir->sticky  = 1;
+		bdir->world_writable = 1;
+		bdir->owner = idx;
+
+		create_sub_dir(bdirs[0].path, bdir, mode);
+	}
+}
+
+static void init_files_dirs(void)
+{
+	int i, owner_idx;
+	/* create all other dirs and files */
+	const struct dir_params *bdir = bdirs;
+	for (i = 0; i < ARRAY_SIZE(bdirs); ++i, ++bdir) {
+		for (owner_idx = 0; owner_idx < USERS_NUM; ++owner_idx) {
+			set_user(users[owner_idx].name);
+			char path[MAX_PATH];
+
+			/* create file in the main directory */
+			snprintf(path, MAX_PATH, "%s/%s%s",
+				bdir->path, users[owner_idx].name, file_postfix);
+			ufiles_add(owner_idx, path, IS_FILE);
+
+			/* create file with S_IWOTH bit set */
+			strcat(path, "_w");
+			ufiles_add(owner_idx, path, IS_FILE);
+
+			chmod(path, S_IRUSR | S_IRGRP | S_IWOTH | S_IROTH);
+
+			/* create sub directory */
+			snprintf(path, MAX_PATH, "%s/%s", bdir->path,
+				users[owner_idx].name);
+			ufiles_add(owner_idx, path, IS_DIRECTORY);
+
+			/* create local file inside sub directory */
+			snprintf(path + strlen(path), MAX_PATH - strlen(path),
+				"/local_%s%s", users[owner_idx].name, file_postfix);
+			ufiles_add(owner_idx, path, IS_FILE);
+		}
+	}
+}
+
+static void ufiles_add(int user_idx, char *path, int type)
+{
+	int file_idx = users[user_idx].num;
+
+	if (file_idx >= MAX_ENTITIES)
+		tst_brkm(TBROK, &cleanup, "Unexpected number of files");
+
+	struct user_file *ufile = &users[user_idx].file[file_idx];
+
+	if (type == IS_FILE)
+		SAFE_CREAT(&cleanup, path, 0644);
+	else
+		SAFE_MKDIR(&cleanup, path, 0755);
+
+	strcpy(ufile->path, path);
+
+	ufile->is_dir = (type == IS_DIRECTORY);
+	++users[user_idx].num;
+}
+
+static void create_link_path(char *buffer, int size, const char *path)
+{
+	/* to make sure name is unique */
+	static int count;
+	++count;
+
+	/* construct link name */
+	snprintf(buffer, size, "%s/link_%d", path, count);
+}
+
+static int create_check_slinks(const struct user_file *ufile, int owner_idx)
+{
+	int result = 0;
+	int i, user_idx;
+
+	const struct dir_params *bdir = bdirs;
+	for (i = 0; i < ARRAY_SIZE(bdirs); ++i, ++bdir) {
+		for (user_idx = 0; user_idx < USERS_NUM; ++user_idx) {
+			/* set user who will create symlink */
+			set_user(users[user_idx].name);
+
+			struct link_info slink_info;
+			create_link_path(slink_info.path, MAX_PATH, bdir->path);
+
+			slink_info.owner = user_idx;
+			slink_info.source_owner = owner_idx;
+			slink_info.in_world_write = bdir->world_writable;
+			slink_info.in_sticky = bdir->sticky;
+			slink_info.dir_owner = bdir->owner;
+
+			if (symlink(ufile->path, slink_info.path) == -1) {
+				tst_brkm(TBROK, &cleanup, "Can't create symlink: %s",
+					slink_info.path);
+			}
+			result |= check_symlink(&slink_info);
+		}
+	}
+	return result;
+}
+
+static int create_check_hlinks(const struct user_file *ufile, int owner_idx)
+{
+	int result = 0;
+	int i, user_idx;
+	const struct dir_params *bdir = bdirs;
+	for (i = 0; i < ARRAY_SIZE(bdirs); ++i, ++bdir) {
+		for (user_idx = 0; user_idx < USERS_NUM; ++user_idx) {
+			/* can't create hardlink to directory */
+			if (ufile->is_dir)
+				continue;
+			/* set user who will create hardlink */
+			set_user(users[user_idx].name);
+
+			struct link_info hlink_info;
+			create_link_path(hlink_info.path, MAX_PATH, bdir->path);
+
+			int can_write = try_fopen(ufile->path, O_WRONLY) == 0;
+
+			int tst_flag = (can_write || user_idx == owner_idx ||
+				user_idx == ROOT) ? CAN_CREATE : CANNOT_CREATE;
+
+			int fail = tst_flag != link(ufile->path, hlink_info.path);
+
+			result |= fail;
+			tst_resm((fail) ? TFAIL : TPASS,
+				"Expect: %s create hardlink \"...%s\" to \"...%s\", "
+				"owner \"%s\", curr.user \"%s\", w(%d)",
+				(tst_flag == CAN_CREATE) ? "can" : "can't",
+				ufile->path + cwd_offset,
+				hlink_info.path + cwd_offset,
+				users[owner_idx].name, users[user_idx].name,
+				can_write);
+		}
+	}
+	return result;
+}
+
+static int check_symlink(const struct link_info *li)
+{
+	int symlink_result = 0;
+	int user_idx;
+	for (user_idx = 0; user_idx < USERS_NUM; ++user_idx) {
+		set_user(users[user_idx].name);
+		int tst_flag = (user_idx == li->dir_owner &&
+			li->in_world_write && li->in_sticky &&
+			user_idx != li->owner) ? CANNOT_FOLLOW : CAN_FOLLOW;
+
+		int fail = tst_flag != try_symlink(li->path);
+
+		symlink_result |= fail;
+
+		tst_resm((fail) ? TFAIL : TPASS,
+			"Expect: %s follow symlink \"...%s\", "
+			"owner \"%s\", src.owner \"%s\", "
+			"curr.user \"%s\", dir.owner \"%s\"",
+			(tst_flag == CAN_FOLLOW) ? "can" : "can't",
+			li->path + cwd_offset, users[li->owner].name,
+			users[li->source_owner].name, users[user_idx].name,
+			users[li->dir_owner].name);
+	}
+	return symlink_result;
+}
+
+/* differenet modes to try in the test */
+static const int o_modes[] = {
+	O_RDONLY,
+	O_WRONLY,
+	O_RDWR,
+	O_RDONLY | O_NONBLOCK | O_DIRECTORY,
+};
+
+static int try_symlink(const char *name)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(o_modes); ++i) {
+		if (try_fopen(name, o_modes[i]) != -1)
+			return CAN_FOLLOW;
+	}
+
+	return CANNOT_FOLLOW;
+}
+
+static int try_fopen(const char *name, int mode)
+{
+	int fd = open(name, mode);
+
+	if (fd == -1)
+		return fd;
+
+	if (close(fd) == -1)
+		tst_brkm(TBROK, &cleanup, "Can't close file: %s", name);
+
+	return 0;
+}
+
+static void set_user(const char *name)
+{
+	uid_t user_id = 0;
+	gid_t user_gr = 0;
+
+	if (name != NULL) {
+		struct passwd *pswd = getpwnam(name);
+
+		if (pswd == 0)
+			tst_brkm(TBROK, &cleanup, "Failed to find user \"%s\"", name);
+		user_id = pswd->pw_uid;
+		user_gr = pswd->pw_gid;
+	}
+
+	SAFE_SETEGID(&cleanup, user_gr);
+	SAFE_SETEUID(&cleanup, user_id);
+}
-- 
1.7.1


------------------------------------------------------------------------------
Introducing AppDynamics Lite, a free troubleshooting tool for Java/.NET
Get 100% visibility into your production application - at no cost.
Code-level diagnostics for performance bottlenecks with <2% overhead
Download for free and get started troubleshooting in minutes.
http://p.sf.net/sfu/appdyn_d2d_ap1
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list

^ permalink raw reply related	[flat|nested] 9+ messages in thread
* [LTP] [PATCH] New core test of hardlinks and symlinks restrictions added in Linux 3.6. Disabled by default in Linux 3.7.
@ 2013-05-07  8:40 Alexey Kodanev
  2013-05-07 14:29 ` chrubis
  0 siblings, 1 reply; 9+ messages in thread
From: Alexey Kodanev @ 2013-05-07  8:40 UTC (permalink / raw)
  To: ltp-list; +Cc: vasily.isaenko, Alexey Kodanev

Signed-off-by: Alexey Kodanev <alexey.kodanev@oracle.com>
---
 .../kernel/security/prot_hsymlinks/.gitignore      |    1 +
 testcases/kernel/security/prot_hsymlinks/Makefile  |   19 +
 testcases/kernel/security/prot_hsymlinks/README    |   24 +
 .../security/prot_hsymlinks/prot_hsymlinks.c       |  584 ++++++++++++++++++++
 4 files changed, 628 insertions(+), 0 deletions(-)
 create mode 100644 testcases/kernel/security/prot_hsymlinks/.gitignore
 create mode 100644 testcases/kernel/security/prot_hsymlinks/Makefile
 create mode 100644 testcases/kernel/security/prot_hsymlinks/README
 create mode 100644 testcases/kernel/security/prot_hsymlinks/prot_hsymlinks.c

diff --git a/testcases/kernel/security/prot_hsymlinks/.gitignore b/testcases/kernel/security/prot_hsymlinks/.gitignore
new file mode 100644
index 0000000..68e41da
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/.gitignore
@@ -0,0 +1 @@
+/prot_hsymlinks
diff --git a/testcases/kernel/security/prot_hsymlinks/Makefile b/testcases/kernel/security/prot_hsymlinks/Makefile
new file mode 100644
index 0000000..cd49588
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/Makefile
@@ -0,0 +1,19 @@
+# Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+#
+# 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 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.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
+
+top_srcdir		?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/security/prot_hsymlinks/README b/testcases/kernel/security/prot_hsymlinks/README
new file mode 100644
index 0000000..a745c8b
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/README
@@ -0,0 +1,24 @@
+TEST SUITE:
+
+The directory prot_hsymlinks contains the tests related to harlinks and
+symlinks restrictions.
+
+TESTS AIM:
+
+The aim of the tests is to check the restrictions
+for hardlinks and symlinks.
+
+This security restrictions were added in Linux 3.6 and enabled by default,
+but it broke some programs. It has been disabled by default in Linux 3.7 and
+to control it, special proc parameters added. Distributions and users
+can enable it by writing "1" to /proc/sys/fs/protected_symlinks,
+/proc/sys/fs/protected_hardlinks.
+
+This test enables restrictions and checks following preconditions:
+
+1. Users who own sticky world-writable directory can't follow symlinks
+inside that directory if their don't own ones. All other users can follow.
+
+2. Hard links restriction applies only to non-privileged users. Only
+non-privileged user can't create hard links to files if he isn't owner
+of the file or he doesn't have write access to the file.
diff --git a/testcases/kernel/security/prot_hsymlinks/prot_hsymlinks.c b/testcases/kernel/security/prot_hsymlinks/prot_hsymlinks.c
new file mode 100644
index 0000000..d13131c
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/prot_hsymlinks.c
@@ -0,0 +1,584 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ *
+ * 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 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.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author:
+ * Alexey Kodanev <alexey.kodanev@oracle.com>
+ *
+ * Test checks following preconditions:
+ *
+ * Symlinks
+ * ---------
+ * Users who own sticky world-writable directory can't follow symlinks
+ * inside that directory if their don't own ones. All other users can follow.
+ *
+ * Hardlinks
+ * ---------
+ * Hard links restriction applies only to non-privileged users. Only
+ * non-privileged user can't create hard links to files if he isn't owner
+ * of the file or he doesn't have write access to the file.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+#include "test.h"
+#include "usctest.h"
+#include "safe_macros.h"
+
+char *TCID = "prot_hsymlinks";
+int TST_TOTAL = 396;
+
+/* create 3 files and 1 dir in each base dir */
+#define MAX_FILES_CREATED	4
+#define MAX_PATH		128
+#define MAX_CMD_LEN		64
+#define MAX_USER_NAME		16
+
+enum {
+	ROOT = 0,
+	TEST_USER,
+	USERS_NUM
+};
+
+#define BASE_DIR_NUM		(USERS_NUM + 1)
+/*
+ * max test files and directories
+ * that will be created during the test
+ * is't not include symlinks and hardlinks
+ * and base directories
+ */
+#define MAX_ENTITIES		(MAX_FILES_CREATED * BASE_DIR_NUM)
+
+struct dir_params {
+	char path[MAX_PATH];
+	int world_writable;
+	int sticky;
+	int owner;
+};
+
+static struct dir_params bdirs[BASE_DIR_NUM];
+
+static const char file_ext[] = ".hs";
+
+enum {
+	IS_FILE = 0,
+	IS_DIRECTORY,
+};
+
+struct user_file {
+	char path[MAX_PATH];
+	int is_dir;
+};
+
+struct test_user {
+	char name[MAX_USER_NAME];
+	struct user_file file[MAX_ENTITIES];
+	int num;
+};
+
+static struct test_user users[USERS_NUM];
+
+struct link_info {
+	char path[MAX_PATH];
+	int owner;
+	int source_owner;
+	int in_world_write;
+	int in_sticky;
+	int is_dir;
+	int dir_owner;
+};
+
+/* test flags */
+enum {
+	CANNOT_FOLLOW = -1,
+	CAN_FOLLOW = 0,
+};
+
+enum {
+	CANNOT_CREATE = -1,
+	CAN_CREATE = 0,
+};
+
+static char *tmp_user_name;
+static char *default_user = "hsym";
+static int nflag;
+static int skip_cleanup;
+
+static const option_t options[] = {
+	{"u:", &nflag, &tmp_user_name},	/* -u #user name */
+	{"s", &skip_cleanup, NULL},
+	{NULL, NULL, NULL}
+};
+/* full length of the test tmpdir path in /tmp */
+static size_t cwd_offset;
+
+static const char hrdlink_proc_path[]	= "/proc/sys/fs/protected_hardlinks";
+static const char symlink_proc_path[]	= "/proc/sys/fs/protected_symlinks";
+
+static void help(void);
+static void setup(int argc, char *argv[]);
+static void cleanup(void);
+
+static void test_user_cmd(const char *user_cmd);
+
+static int disable_protected_slinks;
+static int disable_protected_hlinks;
+
+/*
+ * changes links restrictions
+ * @param value can be:
+ * 0 - restrictions is off
+ * 1 - restrictions is on
+ */
+static void switch_protected_slinks(int value);
+static void switch_protected_hlinks(int value);
+
+static int get_protected_slinks(void);
+static int get_protected_hlinks(void);
+
+static void create_link_path(char *buffer, int size, const char *path);
+static int create_check_hlinks(const struct user_file *ufile, int owner_idx);
+static int create_check_slinks(const struct user_file *ufile, int owner_idx);
+static int check_symlink(const struct link_info *li);
+static int try_open(const char *name, int mode);
+/* try to open symlink in diff modes */
+static int try_symlink(const char *name);
+
+static int test_run(void);
+static void init_base_dirs(void);
+static void init_files_dirs(void);
+
+/* change effective user id and group id by name
+ * pass NULL to set root
+ */
+static void set_user(const char *name);
+
+/* add new created files to user struct */
+static void ufiles_add(int usr_idx, char *path, int type);
+
+int main(int argc, char *argv[])
+{
+	setup(argc, argv);
+
+	test_run();
+
+	cleanup();
+
+	tst_exit();
+}
+
+static void setup(int argc, char *argv[])
+{
+	char *msg;
+	msg = parse_opts(argc, argv, options, &help);
+	if (msg != NULL)
+		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
+
+	tst_require_root(NULL);
+
+	if (tst_kvercmp(3, 7, 0) < 0) {
+		tst_brkm(TCONF, &cleanup,
+			"Test must be run with kernel 3.7 or newer");
+	}
+
+	/* initialize user names */
+	strcpy(users[ROOT].name, "root");
+
+	if (tmp_user_name == NULL)
+		tmp_user_name = default_user;
+	snprintf(users[TEST_USER].name, MAX_USER_NAME, "%s", tmp_user_name);
+
+	tst_sig(FORK, DEF_HANDLER, &cleanup);
+
+	test_user_cmd("useradd");
+	/*
+	 * enable hardlinks and symlinks restrictions,
+	 * it's not defualt but have to check
+	 */
+	if (!get_protected_hlinks()) {
+		switch_protected_hlinks(1);
+		disable_protected_hlinks = 1;
+	}
+	if (!get_protected_slinks()) {
+		switch_protected_slinks(1);
+		disable_protected_slinks = 1;
+	}
+
+	tst_tmpdir();
+
+	init_base_dirs();
+
+	init_files_dirs();
+}
+
+static int test_run(void)
+{
+	tst_resm(TINFO, " --- HARDLINKS AND SYMLINKS RESTRICTIONS TEST ---\n");
+
+	int	result_slink = 0,
+		result_hlink = 0,
+		usr_idx,
+		file_idx;
+
+	const struct user_file *ufile;
+	/*
+	 * create symlinks and hardlinks from each user's files
+	 * to each world writable directory
+	 */
+	for (usr_idx = 0; usr_idx < USERS_NUM; ++usr_idx) {
+		/* get all users files and directories */
+		for (file_idx = 0; file_idx < users[usr_idx].num; ++file_idx) {
+			ufile = &users[usr_idx].file[file_idx];
+			result_slink |= create_check_slinks(ufile, usr_idx);
+			result_hlink |= create_check_hlinks(ufile, usr_idx);
+		}
+	}
+
+	/* final results */
+	tst_resm(TINFO, "All test-cases have been completed, summary:\n"
+		" - symlinks  test:\t%s\n"
+		" - hardlinks test:\t%s",
+		(result_slink == 1) ? "FAIL" : "PASS",
+		(result_hlink == 1) ? "FAIL" : "PASS");
+
+	return result_slink | result_hlink;
+}
+
+static void cleanup(void)
+{
+	/* call cleanup function only once */
+	static int first_call = 1;
+	if (!first_call)
+		return;
+	first_call = 0;
+
+	set_user(NULL);
+
+	if (skip_cleanup)
+		return;
+
+	test_user_cmd("userdel -r");
+
+	if (disable_protected_hlinks) {
+		tst_resm(TINFO, "Disable protected hardlinks mode back");
+		switch_protected_hlinks(0);
+	}
+	if (disable_protected_slinks) {
+		tst_resm(TINFO, "Disable protected symlinks mode back");
+		switch_protected_slinks(0);
+	}
+
+	tst_rmdir();
+	TEST_CLEANUP;
+}
+
+static int get_protected_hlinks(void)
+{
+	int value = 0;
+	SAFE_FILE_SCANF(&cleanup, hrdlink_proc_path, "%d", &value);
+	return value;
+}
+
+static int get_protected_slinks(void)
+{
+	int value = 0;
+	SAFE_FILE_SCANF(&cleanup, symlink_proc_path, "%d", &value);
+	return value;
+}
+
+static void switch_protected_hlinks(int value)
+{
+	SAFE_FILE_PRINTF(&cleanup, hrdlink_proc_path, "%d", value == 1);
+}
+
+static void switch_protected_slinks(int value)
+{
+	SAFE_FILE_PRINTF(&cleanup, symlink_proc_path, "%d", value == 1);
+}
+
+static void test_user_cmd(const char *user_cmd)
+{
+	char cmd[MAX_CMD_LEN];
+	snprintf(cmd, MAX_CMD_LEN, "%s %s", user_cmd, users[TEST_USER].name);
+	if (system(cmd) != 0) {
+		tst_brkm(TBROK, &cleanup, "Failed to run cmd: %s %s",
+			user_cmd, users[TEST_USER].name);
+	}
+}
+
+static void help(void)
+{
+	printf("  -s      Skip cleanup.\n");
+	printf("  -u #user name : Define test user\n");
+}
+
+static void create_sub_dir(const char *path,
+	struct dir_params *bdir, mode_t mode)
+{
+	snprintf(bdir->path, MAX_PATH, "%s/tmp_%s",
+		path, users[bdir->owner].name);
+	SAFE_MKDIR(&cleanup, bdir->path, mode);
+
+	if (bdir->sticky)
+		mode |= S_ISVTX;
+	chmod(bdir->path, mode);
+}
+
+static void init_base_dirs(void)
+{
+	char *cwd = get_tst_tmpdir();
+	cwd_offset = strlen(cwd);
+
+	mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
+	chmod(cwd, mode);
+
+	struct dir_params *bdir = bdirs;
+	strcpy(bdir->path, cwd);
+	free(cwd);
+
+	bdir->sticky  = 0;
+	bdir->world_writable = 1;
+
+	/* create subdir for each user */
+	++bdir;
+	int idx;
+	for (idx = 0; idx < USERS_NUM; ++idx, ++bdir) {
+		set_user(users[idx].name);
+
+		bdir->sticky  = 1;
+		bdir->world_writable = 1;
+		bdir->owner = idx;
+
+		create_sub_dir(bdirs[0].path, bdir, mode);
+	}
+}
+
+static void init_files_dirs(void)
+{
+	int i, owner_idx;
+	/* create all other dirs and files */
+	const struct dir_params *bdir = bdirs;
+	for (i = 0; i < ARRAY_SIZE(bdirs); ++i, ++bdir) {
+		for (owner_idx = 0; owner_idx < USERS_NUM; ++owner_idx) {
+			set_user(users[owner_idx].name);
+			char path[MAX_PATH];
+
+			/* create file in the main directory */
+			snprintf(path, MAX_PATH, "%s/%s%s",
+				bdir->path, users[owner_idx].name, file_ext);
+			ufiles_add(owner_idx, path, IS_FILE);
+
+			/* create file with S_IWOTH bit set */
+			strcat(path, "_w");
+			ufiles_add(owner_idx, path, IS_FILE);
+
+			chmod(path, S_IRUSR | S_IRGRP | S_IWOTH | S_IROTH);
+
+			/* create sub directory */
+			snprintf(path, MAX_PATH, "%s/%s", bdir->path,
+				users[owner_idx].name);
+			ufiles_add(owner_idx, path, IS_DIRECTORY);
+
+			/* create local file inside sub directory */
+			snprintf(path + strlen(path), MAX_PATH - strlen(path),
+				"/local_%s%s", users[owner_idx].name, file_ext);
+			ufiles_add(owner_idx, path, IS_FILE);
+		}
+	}
+}
+
+static void ufiles_add(int usr_idx, char *path, int type)
+{
+	int file_idx = users[usr_idx].num;
+
+	if (file_idx >= MAX_ENTITIES)
+		tst_brkm(TBROK, &cleanup, "Unexpected number of files");
+
+	struct user_file *ufile = &users[usr_idx].file[file_idx];
+
+	if (type == IS_FILE)
+		SAFE_CREAT(&cleanup, path, 0644);
+	else
+		SAFE_MKDIR(&cleanup, path, 0755);
+
+	strcpy(ufile->path, path);
+
+	ufile->is_dir = (type == IS_DIRECTORY);
+	++users[usr_idx].num;
+}
+
+static void create_link_path(char *buffer, int size, const char *path)
+{
+	/* to make sure name is unique */
+	static int count;
+	++count;
+
+	/* construct link name */
+	snprintf(buffer, size, "%s/link_%d", path, count);
+}
+
+static int create_check_slinks(const struct user_file *ufile, int owner_idx)
+{
+	int result = 0;
+	int i, usr_idx;
+
+	const struct dir_params *bdir = bdirs;
+	for (i = 0; i < ARRAY_SIZE(bdirs); ++i, ++bdir) {
+		for (usr_idx = 0; usr_idx < USERS_NUM; ++usr_idx) {
+			/* set user who will create symlink */
+			set_user(users[usr_idx].name);
+
+			struct link_info slink_info;
+			create_link_path(slink_info.path, MAX_PATH, bdir->path);
+
+			slink_info.owner = usr_idx;
+			slink_info.source_owner = owner_idx;
+			slink_info.in_world_write = bdir->world_writable;
+			slink_info.in_sticky = bdir->sticky;
+			slink_info.dir_owner = bdir->owner;
+
+			if (symlink(ufile->path, slink_info.path) == -1) {
+				tst_brkm(TBROK, &cleanup,
+					"Can't create symlink: %s",
+					slink_info.path);
+			}
+			result |= check_symlink(&slink_info);
+		}
+	}
+	return result;
+}
+
+static int create_check_hlinks(const struct user_file *ufile, int owner_idx)
+{
+	int result = 0;
+	int i, usr_idx;
+	const struct dir_params *bdir = bdirs;
+	for (i = 0; i < ARRAY_SIZE(bdirs); ++i, ++bdir) {
+		for (usr_idx = 0; usr_idx < USERS_NUM; ++usr_idx) {
+			/* can't create hardlink to directory */
+			if (ufile->is_dir)
+				continue;
+			/* set user who will create hardlink */
+			set_user(users[usr_idx].name);
+
+			struct link_info hlink_info;
+			create_link_path(hlink_info.path, MAX_PATH, bdir->path);
+
+			int can_write = try_open(ufile->path, O_WRONLY) == 0;
+
+			int tst_flag = (can_write || usr_idx == owner_idx ||
+				usr_idx == ROOT) ? CAN_CREATE : CANNOT_CREATE;
+
+			int fail;
+			fail = tst_flag != link(ufile->path, hlink_info.path);
+
+			result |= fail;
+			tst_resm((fail) ? TFAIL : TPASS,
+				"Expect: %s create hardlink '...%s' to '...%s', "
+				"owner '%s', curr.user '%s', w(%d)",
+				(tst_flag == CAN_CREATE) ? "can" : "can't",
+				ufile->path + cwd_offset,
+				hlink_info.path + cwd_offset,
+				users[owner_idx].name, users[usr_idx].name,
+				can_write);
+		}
+	}
+	return result;
+}
+
+static int check_symlink(const struct link_info *li)
+{
+	int symlink_result = 0;
+	int usr_idx;
+	for (usr_idx = 0; usr_idx < USERS_NUM; ++usr_idx) {
+		set_user(users[usr_idx].name);
+		int tst_flag = (usr_idx == li->dir_owner &&
+			li->in_world_write && li->in_sticky &&
+			usr_idx != li->owner) ? CANNOT_FOLLOW : CAN_FOLLOW;
+
+		int fail = tst_flag != try_symlink(li->path);
+
+		symlink_result |= fail;
+
+		tst_resm((fail) ? TFAIL : TPASS,
+			"Expect: %s follow symlink '...%s', "
+			"owner '%s', src.owner '%s', "
+			"curr.user '%s', dir.owner '%s'",
+			(tst_flag == CAN_FOLLOW) ? "can" : "can't",
+			li->path + cwd_offset, users[li->owner].name,
+			users[li->source_owner].name, users[usr_idx].name,
+			users[li->dir_owner].name);
+	}
+	return symlink_result;
+}
+
+/* differenet modes to try in the test */
+static const int o_modes[] = {
+	O_RDONLY,
+	O_WRONLY,
+	O_RDWR,
+	O_RDONLY | O_NONBLOCK | O_DIRECTORY,
+};
+
+static int try_symlink(const char *name)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(o_modes); ++i) {
+		if (try_open(name, o_modes[i]) != -1)
+			return CAN_FOLLOW;
+	}
+
+	return CANNOT_FOLLOW;
+}
+
+static int try_open(const char *name, int mode)
+{
+	int fd = open(name, mode);
+
+	if (fd == -1)
+		return fd;
+
+	if (close(fd) == -1)
+		tst_brkm(TBROK, &cleanup, "Can't close file: %s", name);
+
+	return 0;
+}
+
+static void set_user(const char *name)
+{
+	uid_t user_id = 0;
+	gid_t user_gr = 0;
+
+	if (name != NULL) {
+		struct passwd *pswd = getpwnam(name);
+
+		if (pswd == 0) {
+			tst_brkm(TBROK, &cleanup,
+				"Failed to find user '%s'", name);
+		}
+		user_id = pswd->pw_uid;
+		user_gr = pswd->pw_gid;
+	}
+
+	SAFE_SETEGID(&cleanup, user_gr);
+	SAFE_SETEUID(&cleanup, user_id);
+}
-- 
1.7.1


------------------------------------------------------------------------------
Learn Graph Databases - Download FREE O'Reilly Book
"Graph Databases" is the definitive new guide to graph databases and 
their applications. This 200-page book is written by three acclaimed 
leaders in the field. The early access version is available now. 
Download your free book today! http://p.sf.net/sfu/neotech_d2d_may
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list

^ permalink raw reply related	[flat|nested] 9+ messages in thread
* [LTP] [PATCH] New core test of hardlinks and symlinks restrictions added in Linux 3.6. Disabled by default in Linux 3.7.
@ 2013-04-30  6:27 Alexey Kodanev
  2013-04-30 12:24 ` chrubis
  2013-04-30 17:24 ` Mike Frysinger
  0 siblings, 2 replies; 9+ messages in thread
From: Alexey Kodanev @ 2013-04-30  6:27 UTC (permalink / raw)
  To: ltp-list; +Cc: vasily.isaenko, Alexey Kodanev

Signed-off-by: Alexey Kodanev <alexey.kodanev@oracle.com>
---
 .../kernel/security/prot_hsymlinks/.gitignore      |    1 +
 testcases/kernel/security/prot_hsymlinks/Makefile  |   71 +++
 testcases/kernel/security/prot_hsymlinks/README    |   64 +++
 testcases/kernel/security/prot_hsymlinks/cleanup.c |  118 +++++
 testcases/kernel/security/prot_hsymlinks/cleanup.h |   51 ++
 .../kernel/security/prot_hsymlinks/exec_cmd.c      |   69 +++
 .../kernel/security/prot_hsymlinks/exec_cmd.h      |   37 ++
 testcases/kernel/security/prot_hsymlinks/hs_main.c |  210 ++++++++
 testcases/kernel/security/prot_hsymlinks/hs_test.c |  515 ++++++++++++++++++++
 testcases/kernel/security/prot_hsymlinks/hs_test.h |   47 ++
 testcases/kernel/security/prot_hsymlinks/options.c |  104 ++++
 testcases/kernel/security/prot_hsymlinks/options.h |   39 ++
 .../kernel/security/prot_hsymlinks/wrp_links.c     |  101 ++++
 .../kernel/security/prot_hsymlinks/wrp_links.h     |   38 ++
 .../kernel/security/prot_hsymlinks/wrp_users.c     |   55 ++
 .../kernel/security/prot_hsymlinks/wrp_users.h     |   40 ++
 16 files changed, 1560 insertions(+), 0 deletions(-)
 create mode 100644 testcases/kernel/security/prot_hsymlinks/.gitignore
 create mode 100644 testcases/kernel/security/prot_hsymlinks/Makefile
 create mode 100644 testcases/kernel/security/prot_hsymlinks/README
 create mode 100644 testcases/kernel/security/prot_hsymlinks/cleanup.c
 create mode 100644 testcases/kernel/security/prot_hsymlinks/cleanup.h
 create mode 100644 testcases/kernel/security/prot_hsymlinks/exec_cmd.c
 create mode 100644 testcases/kernel/security/prot_hsymlinks/exec_cmd.h
 create mode 100644 testcases/kernel/security/prot_hsymlinks/hs_main.c
 create mode 100644 testcases/kernel/security/prot_hsymlinks/hs_test.c
 create mode 100644 testcases/kernel/security/prot_hsymlinks/hs_test.h
 create mode 100644 testcases/kernel/security/prot_hsymlinks/options.c
 create mode 100644 testcases/kernel/security/prot_hsymlinks/options.h
 create mode 100644 testcases/kernel/security/prot_hsymlinks/wrp_links.c
 create mode 100644 testcases/kernel/security/prot_hsymlinks/wrp_links.h
 create mode 100644 testcases/kernel/security/prot_hsymlinks/wrp_users.c
 create mode 100644 testcases/kernel/security/prot_hsymlinks/wrp_users.h

diff --git a/testcases/kernel/security/prot_hsymlinks/.gitignore b/testcases/kernel/security/prot_hsymlinks/.gitignore
new file mode 100644
index 0000000..68e41da
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/.gitignore
@@ -0,0 +1 @@
+/prot_hsymlinks
diff --git a/testcases/kernel/security/prot_hsymlinks/Makefile b/testcases/kernel/security/prot_hsymlinks/Makefile
new file mode 100644
index 0000000..80b91fe
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/Makefile
@@ -0,0 +1,71 @@
+# Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+#
+# 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 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.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
+
+top_srcdir		?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+
+####### Tools and options
+DEFINES			=
+INCPATH			= -I. -I/usr/include
+LINK			= $(CC)
+MKDIR			= mkdir -p
+RM_DIR			= rmdir
+RM_FILE			= rm -f
+CHK_DIR_EXISTS	= test -d
+
+####### Files
+
+SOURCES	= 	hs_main.c \
+		options.c \
+		exec_cmd.c \
+		hs_test.c \
+		cleanup.c \
+		wrp_links.c \
+		wrp_users.c
+
+OBJECTS	= 	hs_main.o \
+		options.o \
+		exec_cmd.o \
+		hs_test.o \
+		cleanup.o \
+		wrp_links.o \
+		wrp_users.o
+
+TARGET_NAME 		= prot_hsymlinks
+MAKE_TARGETS		:=$(TARGET_NAME)
+
+first: all
+
+####### Build rules
+
+all: Makefile $(MAKE_TARGETS)
+
+FILTER_OUT_MAKE_TARGETS		:= hs_test cleanup exec_cmd options wrp_links wrp_users
+
+$(MAKE_TARGETS):  $(OBJECTS)
+	$(LINK) $(LDFLAGS) -o $(MAKE_TARGETS) $(OBJECTS) $(LIBS) $(LDLIBS)
+	@$(RM_FILE) $(OBJECTS)
+
+####### Compile
+
+INSTALL_TARGETS	:=	$(MAKE_TARGETS)
+
+CLEAN_TARGETS	+=	$(MAKE_TARGETS).tar.gz
+
+pack:
+	tar -cvzf $(TARGET_NAME).tar.gz $(TARGET_NAME)
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/security/prot_hsymlinks/README b/testcases/kernel/security/prot_hsymlinks/README
new file mode 100644
index 0000000..860e2c0
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/README
@@ -0,0 +1,64 @@
+TEST SUITE:
+
+The directory prot_hsymlinks contains the tests related to harlinks and
+symlinks restrictions.
+
+TESTS AIM:
+
+The aim of the tests is to check the restrictions
+for hardlinks and symlinks:
+
+This security restrictions were added in Linux 3.6 and enabled by default,
+but it broke some programs. It has been disabled by default in Linux 3.7 and
+to control it special proc parameters added. Distributions and users can enable it by writing "1"
+to /proc/sys/fs/protected_symlinks and /proc/sys/fs/protected_hardlinks.
+
+This test enables restrictions and check following preconditions.
+Symlinks restriction applies only to privileged users (other
+combinations of non-privileged user, sticky bit and world-writable
+dirs are not affected). Only privileged user can't follow symlinks
+in only sticky world-writable directory if he isn't owner of that link.
+All other users can.
+
+Hard links restriction applies only to non-privileged users. Only
+non-privileged user can't create hard links to files if he isn't owner
+of the file or he doesn't have write access to the file despite of file's
+directory permission.
+
+FILES DESCRIPTION:
+
+hs_main.c
+----------
+Test main entry point.
+
+hs_test.c
+----------
+This file contains tests implementation.
+
+cleanup.c
+---------------
+This file contains cleanup functions and linked list structure.
+
+exec_cmd.c
+---------------
+Implements execution of some other programs in the test.
+
+options.c
+----------
+Implements program options.
+
+wrp_links.c
+----------
+Implements functions to deal with hard and symbolic links.
+
+wrp_users.c
+----------
+Wrapper to change effective group and user id.
+
+Makefile
+--------
+The makefile for this test.
+
+README:
+--------
+This file.
diff --git a/testcases/kernel/security/prot_hsymlinks/cleanup.c b/testcases/kernel/security/prot_hsymlinks/cleanup.c
new file mode 100644
index 0000000..db0c862
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/cleanup.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ *
+ * 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 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.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author:
+ * Alexey Kodanev <alexey.kodanev@oracle.com>
+ *
+ * File: cleanup.c
+ *
+ * This file contains cleanup functions and linked list structure
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* LTP includes */
+#include <test.h>
+#include <safe_macros.h>
+#include <usctest.h>
+
+#include "cleanup.h"
+
+int _skip_cleanup;
+
+int _root_cleanup;
+
+/* cleanup linked-list, contains cleanup functions */
+struct cleanup_list {
+	void (*cleanup_fun)(void);
+	struct cleanup_list *prev;
+	struct cleanup_list *next;
+};
+
+/* head of list */
+struct cleanup_list* clean_list_head;
+
+/* current position */
+struct cleanup_list* clean_list;
+
+void cleanup_init(void)
+{
+	_skip_cleanup = 0;
+	_root_cleanup = 1;
+	clean_list_head=NULL;
+	clean_list=NULL;
+}
+
+void cleanup_add( void (*cleanup_fun)(void) )
+{
+	
+	if(clean_list_head==NULL) {
+		/* first time */
+		clean_list_head = (struct cleanup_list*)SAFE_MALLOC(NULL,
+					sizeof(struct cleanup_list));
+		clean_list = clean_list_head;
+		clean_list->prev = NULL;
+	} else {
+		clean_list->next = (struct cleanup_list*)SAFE_MALLOC(NULL,
+					sizeof(struct cleanup_list));
+		(clean_list->next)->prev = clean_list;
+		clean_list = clean_list->next;
+	}
+	
+	clean_list->cleanup_fun = cleanup_fun;
+	clean_list->next = NULL;
+
+}
+
+void cleanup(void)
+{
+	/* call cleanup function only once */
+	static int first_call = 1;
+	if(!first_call) return;
+	first_call = 0;
+	
+	if(_root_cleanup) {
+		SAFE_SETEGID(NULL,0);
+		SAFE_SETEUID(NULL,0);
+	}
+		
+	struct cleanup_list* lst = clean_list;
+	
+	/* call every cleanup functions passed
+	 * in reverse order 
+	 */
+	if(!_skip_cleanup)
+		while(lst) {
+			lst->cleanup_fun();
+			lst = lst->prev;
+		}
+
+	lst = clean_list_head;
+	struct cleanup_list *new_list = clean_list;
+
+	/* free the list */
+	while(new_list) {
+		
+		new_list = lst->prev;
+		free(lst);
+		lst=new_list;
+	}
+	
+	tst_rmdir();
+	TEST_CLEANUP;
+}
diff --git a/testcases/kernel/security/prot_hsymlinks/cleanup.h b/testcases/kernel/security/prot_hsymlinks/cleanup.h
new file mode 100644
index 0000000..f63fa2b
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/cleanup.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ *
+ * 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 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.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author:
+ * Alexey Kodanev <alexey.kodanev@oracle.com>
+ *
+ * File: cleanup.h
+ *
+ * This file contains cleanup functions and linked list structure
+ *
+ */
+
+#ifndef CLEANUP_FILE_H
+#define CLEANUP_FILE_H
+
+/*
+ * flag to skip cleanup
+ */
+extern int _skip_cleanup;
+
+/*
+ * set root user for cleanup
+ * 1 - cleanup as root (default)
+ * 0 - cleanup as current user
+ */
+extern int _root_cleanup;
+
+/*
+ * have to call it befor any use of cleanup
+ */
+extern void cleanup_init(void);
+
+extern void cleanup(void);
+
+/* pass pointer of cleanup function, it'll be added to cleanup list */
+extern void cleanup_add( void (*cleanup_fun)(void) );
+
+#endif /* CLEANUP_FILE_H */
diff --git a/testcases/kernel/security/prot_hsymlinks/exec_cmd.c b/testcases/kernel/security/prot_hsymlinks/exec_cmd.c
new file mode 100644
index 0000000..8130567
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/exec_cmd.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ *
+ * 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 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.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author:
+ * Alexey Kodanev <alexey.kodanev@oracle.com>
+ *
+ * File: exec_cmd.c
+ *
+ * Implements execution of some other programs in the test.
+ */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <string.h>
+#include <errno.h>
+#include <sys/wait.h>
+
+/* LTP include */
+#include <test.h>
+
+#include "exec_cmd.h"
+
+void exec_cmd(	void (*cleanup_fn)(void),
+		const char* name, char* arg_list[],
+		char* env[])
+{
+	/* clone the process */
+	pid_t pid = vfork();
+
+	if(pid==-1) {
+		tst_brkm(TBROK,cleanup_fn,"Failed to fork, error: %s",
+			strerror(errno));
+	}
+	
+	if(!pid) {
+		/* child process code */
+		if(env==NULL)
+			_exit( execvp(name,arg_list) );
+		else
+			_exit( execve(name,arg_list,env) );
+	}
+	
+
+	/* Wait and get the child process status */
+	int child_status;
+	child_status = 0;
+	wait (&child_status);
+
+	if (child_status!=0)
+		tst_brkm(TBROK,cleanup_fn,"the child process exited abnormally");
+}
diff --git a/testcases/kernel/security/prot_hsymlinks/exec_cmd.h b/testcases/kernel/security/prot_hsymlinks/exec_cmd.h
new file mode 100644
index 0000000..b21b1fe
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/exec_cmd.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ *
+ * 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 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.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author:
+ * Alexey Kodanev <alexey.kodanev@oracle.com>
+ *
+ * File: exec_cmd.h
+ *
+ * Implements execution of some other programs in the test.
+ */
+
+#ifndef EXEC_CMD_FILE_H
+#define EXEC_CMD_FILE_H
+
+/* exec program
+ * @param cleanup function
+ * @param name program name 
+ * @param arg_list argument list
+ */
+extern void exec_cmd(	void (*cleanup_fn)(void),
+			const char* name, char* arg_list[],
+			char* env[]);
+
+#endif /* EXEC_CMD_FILE_H */
diff --git a/testcases/kernel/security/prot_hsymlinks/hs_main.c b/testcases/kernel/security/prot_hsymlinks/hs_main.c
new file mode 100644
index 0000000..7afa743
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/hs_main.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ *
+ * 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 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.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author:
+ * Alexey Kodanev <alexey.kodanev@oracle.com>
+ *
+ * File: main.c
+ *
+ * Test checks following preconditions:
+ *
+ * Symlinks restriction applies only to privileged users (other
+ * combinations of non-privileged user, sticky bit and world-writable
+ * dirs are not affected). Only privileged user can't follow symlinks in 
+ * only sticky world-writable directory if he isn't owner of that link. 
+ * All other users can.
+ *
+ * Hard links restriction applies only to non-privileged users. Only 
+ * non-privileged user can't create hard links to files if he isn't owner 
+ * of the file or he doesn't have write access to the file despite of 
+ * file's directory permission.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+
+/* LTP Port */
+#include <test.h>
+#include <usctest.h>
+
+#include "options.h"	/* program options */
+#include "hs_test.h"	/* hard & symlinks tests */
+#include "cleanup.h"
+#include "exec_cmd.h"
+
+char* TCID="prot_hsymlinks";
+int TST_TOTAL=396;
+
+static void setup(int argc, char **argv);
+
+/* cleanup function */
+void delete_test_user(void);
+
+/* cleanup functions 
+ * disable protected mode in kernel
+ */
+void disable_protected_slinks(void);
+void disable_protected_hlinks(void);
+
+/* 
+ * changes links restrictions 
+ * @param value can be:
+ * 0 - restrictions is off
+ * 1 - restrictions is on
+ */
+void switch_protected_slinks(int value);
+void switch_protected_hlinks(int value);
+
+int get_protected_slinks(void);
+int get_protected_hlinks(void);
+
+static const char*  hardlink_protected_path 	= "/proc/sys/fs/protected_hardlinks";
+static const char*  symlink_protected_path	= "/proc/sys/fs/protected_symlinks";
+
+int main(int argc, char **argv)
+{	
+	/* test setup */
+	setup(argc,argv);
+
+	/* run all tests */
+	hs_test_run();
+
+	/* cleanup and exit */
+	cleanup();
+	tst_exit();
+}
+
+void setup(int argc, char **argv)
+{
+	cleanup_init();
+	
+	/* Deal with any options specified */
+	init_options(argc,argv);
+
+	tst_require_root(NULL);
+
+	if(tst_kvercmp(3,7,0)<0)
+		tst_brkm(TCONF,&cleanup,"Test must be run with kernel 3.7 or newer"); 
+
+	/* setup default signal handler */
+	tst_sig(FORK,DEF_HANDLER,&cleanup);
+
+	/* create new user */
+	char *useradd_argv[] = {
+		"useradd",
+		_users[TEST_USER],
+		NULL,
+	};
+		
+	exec_cmd(&cleanup,"useradd",useradd_argv,NULL);
+
+	/* 1st use hear */
+	cleanup_add( &delete_test_user );
+	
+
+	/* enable hard and symlinks restriction, it's not defualt
+	 * but have to check
+	 */
+	if(!get_protected_hlinks()) {
+	    switch_protected_hlinks(1);
+	    cleanup_add(&disable_protected_hlinks);
+	}
+	if(!get_protected_slinks()) {
+	    switch_protected_slinks(1);
+	    cleanup_add(&disable_protected_slinks);
+	}
+	
+	/* init the restriction test */
+	hs_test_init();	
+}
+
+void disable_protected_hlinks(void)
+{
+	tst_resm(TINFO,"Disable protected hardlinks mode back");
+	switch_protected_hlinks(0);
+}
+void disable_protected_slinks(void)
+{
+	tst_resm(TINFO,"Disable protected symlinks mode back");
+	switch_protected_slinks(0);
+}
+
+int get_protected_hlinks(void)
+{
+	FILE* fd;
+	fd = fopen(hardlink_protected_path,"r");
+	if(fd==NULL)
+	    tst_brkm(TBROK,&cleanup,"Can't read %s",hardlink_protected_path);
+
+	int value=0;
+	fscanf(fd,"%d",&value);
+	fclose(fd);
+	return value;
+}
+
+int get_protected_slinks(void)
+{
+	FILE* fd;
+	fd = fopen(symlink_protected_path,"r");
+	if(fd==NULL)
+	    tst_brkm(TBROK,&cleanup,"Can't read %s",symlink_protected_path);
+
+	int value=0;
+	fscanf(fd,"%d",&value);
+	fclose(fd);
+	return value;
+}
+
+void switch_protected_hlinks(int value)
+{
+	FILE* fd;
+	fd = fopen(hardlink_protected_path,"w");
+	if(fd==NULL)
+		tst_brkm(TBROK,&cleanup,"Can't set %d to %s",value,
+			hardlink_protected_path);
+
+	fprintf(fd,"%d",value==1);
+	fclose(fd);
+}
+
+void switch_protected_slinks(int value)
+{
+	FILE* fd = fopen(symlink_protected_path,"w");
+	if(fd==NULL)
+		tst_brkm(TBROK,&cleanup,"Can't set %d to %s",value,
+			symlink_protected_path);
+
+	fprintf(fd,"%d",value==1);
+	fclose(fd);
+}
+
+void delete_test_user(void)
+{
+	/* create new user */
+	
+	tst_resm(TINFO,"Delete test user: %s",_users[TEST_USER]);
+
+	
+	char *userdel_argv[] = {
+		"userdel",
+		"-r",
+		_users[TEST_USER],
+		NULL,
+	};
+	
+	exec_cmd(&cleanup,"userdel",userdel_argv,NULL);
+}
diff --git a/testcases/kernel/security/prot_hsymlinks/hs_test.c b/testcases/kernel/security/prot_hsymlinks/hs_test.c
new file mode 100644
index 0000000..02178b4
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/hs_test.c
@@ -0,0 +1,515 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ *
+ * 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 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.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author:
+ * Alexey Kodanev <alexey.kodanev@oracle.com>
+ *
+ * File: hs_test.c
+ *
+ * Test implementation
+ * -------------------
+ * Symlinks restriction applies only to privileged users (other
+ * combinations of non-privileged user, sticky bit and world-writable
+ * dirs are not affected). Only privileged user can't follow symlinks in 
+ * only sticky world-writable directory if he isn't owner of that link. 
+ * All other users can.
+ *
+ * Hard links restriction applies only to non-privileged users. Only 
+ * non-privileged user can't create hard links to files if he isn't owner 
+ * of the file or he doesn't have write access to the file despite of 
+ * file's directory permission.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+/* LTP include */
+#include <test.h>
+#include <safe_macros.h>
+
+#include "options.h"
+#include "wrp_links.h"	/* hard & symlinks wrappers */
+#include "wrp_users.h"	/* users func. */
+
+#include "hs_test.h"
+#include "cleanup.h"
+
+/* prefixes and postfixes of files and dirs */
+static const char* file_postfix = ".hsym";
+static const char* symlink_prefix = "sym";
+static const char* symlink_dir_prefix = "dsy";
+static const char* hardlink_prefix = "hrd";
+
+/* base directories to test */
+struct base_test_dir
+{
+	const char* path;
+	const char* user_name;
+	const int world_writable;
+	const int sticky;
+	const int create;
+};
+
+enum TEST_DIRS {
+	TEST_DIR=0,
+	TEST_TMP_DIR,
+	TMP_DIR,
+	TEST_DIR_NUM
+};
+
+/* this base dirs which will be created */
+static struct base_test_dir test_dir[] = {
+	[TEST_DIR] = {
+		.path = "/tmp_test",
+		.user_name = "root",
+		.world_writable = 1,
+		.sticky = 0,
+		.create = 1,
+	},	
+	[TEST_TMP_DIR] = {
+		.path = "/tmp_test/tmp",
+		.user_name = "root",
+		.world_writable = 1,
+		.sticky = 1,
+		.create = 1,
+	},
+	[TMP_DIR] = {
+		.path = "/tmp",
+		.user_name = "root",
+		.world_writable = 1,
+		.sticky = 1,
+		.create = 0,
+	},
+};
+
+/* create 3 files and 1 dir in each base dir */
+#define MAX_FILES_CREATED 	4
+#define MAX_PATH 		128
+#define MIN_PATH 		2
+
+/*
+ * max test files and directories 
+ * that will be created during the test
+ * is't not include symlinks and hardlinks
+ * and base directories
+ */
+#define MAX_ENTITIES 	MAX_FILES_CREATED*TEST_DIR_NUM
+struct user_file {
+	char file[MAX_ENTITIES][MAX_PATH];
+	int is_dir[MAX_ENTITIES];
+	int num;	/* number of files */
+};
+/* create struct for each user */
+static struct user_file ufiles[USERS_NUM];
+
+#define MAX_SYMLINKS	MAX_ENTITIES*USERS_NUM*USERS_NUM*TEST_DIR_NUM
+#define MAX_HARDLINKS	MAX_SYMLINKS
+
+enum {
+    IS_FILE=0,
+    IS_DIRECTORY,
+};
+
+/* test info about link */
+struct hs_link
+{
+	char path[MAX_PATH];
+	char owner[MAX_USER_NAME];
+	char source_owner[MAX_USER_NAME];
+	int in_wwd; 	/* link in world-writable directory */
+	int in_sticky; 	/* link in sticky directory */
+	int is_dir; 	/* just for symlinks */
+};
+
+/* simple struct to save info about created links */
+struct hs_links
+{
+	struct hs_link sym[MAX_SYMLINKS];
+	struct hs_link hrd[MAX_HARDLINKS];
+	
+	int s_num; /* symlinks number */
+	int h_num; /* hardlinks number */
+};
+
+/* struct to keep all created links for test */
+static struct hs_links links;
+
+/* test flags */
+enum {
+	CANNOT_FOLLOW=-1,
+	CAN_FOLLOW=0,
+};
+
+enum {
+	CANNOT_CREATE=-1,
+	CAN_CREATE=0,
+};
+
+/* create hardlinks */
+static int create_links(void);
+
+/* add new created files to ufiles struct */
+static void ufiles_add(const int* id, const char* path, const int is_dir);
+
+/* cleanup function */
+void delete_files(void)
+{
+	tst_resm(TINFO,"Remove tmp files...");
+	
+	/* remove all users files */
+	int j,p;
+	for(j=0;j<USERS_NUM;++j) {
+		for(p=0;p<ufiles[j].num;++p) {
+			if(!ufiles[j].is_dir[p])
+				remove(ufiles[j].file[p]);
+		}
+	}
+
+	/* delete hard links */
+	for(j=0;j<links.h_num;++j)
+		remove(links.hrd[j].path);
+
+	/* delete symlinks */
+	for(j=0;j<links.s_num;++j)
+		remove(links.sym[j].path);
+
+	/* delete directories */
+	for(j=0;j<USERS_NUM;++j) {
+		for(p=0;p<ufiles[j].num;++p) {
+			if(ufiles[j].is_dir[p])
+				remove(ufiles[j].file[p]);
+		}
+	}
+
+	/* delete base directories */
+	for(j=TEST_DIR_NUM-1;j>=0;--j) {
+		const struct base_test_dir* tdir = &test_dir[j];
+		if(tdir->create)
+			remove(tdir->path);
+	}
+}
+
+char rchar()
+{
+    /* return random character from A...Z */
+    return (rand()%0x19+0x41);
+}
+
+void hs_test_init(void)
+{
+	cleanup_add(&delete_files);
+
+	/* initialize random seed */
+	srand( time(NULL) );
+	 
+	tst_resm(TINFO," -- Hard & Symbolic links restriction test -- \n");
+
+	/* init the links struct */
+	memset(&links,0,sizeof(links));
+	
+	/* init struct to store info about created files */
+	memset(&ufiles,0,sizeof(ufiles));
+
+	/* create main directories */
+	int i;
+	for(i=0;i<TEST_DIR_NUM;++i) {
+		if( !test_dir[i].create ) continue;
+		const struct base_test_dir* tdir = &test_dir[i];
+
+		SAFE_MKDIR(&cleanup,tdir->path,	S_IRWXU | 
+						S_IRGRP | S_IXGRP |
+						S_IROTH | S_IXOTH 
+						/* 0755 */);
+
+		mode_t mode = 0;
+
+		if( tdir->world_writable )
+			mode = S_IRWXU | S_IRWXG | S_IRWXO;
+			
+		if( tdir->sticky )
+			mode |= S_ISVTX; 
+
+		if(mode) chmod(tdir->path, mode);
+
+	} //for
+
+	/* create all other directories and files */		
+	for(i=0;i<TEST_DIR_NUM;++i) {
+		const struct base_test_dir* tdir = &test_dir[i];
+		
+		int k;
+		for(k = 0;k<USERS_NUM;++k) {
+			
+			set_user( _users[k] );
+			
+			/* create file in the main directory */
+			char fpath[MAX_PATH];
+			sprintf(fpath,"%s/%s%s",
+				tdir->path,_users[k],file_postfix);
+			ufiles_add(&k, fpath, IS_FILE);
+			SAFE_CREAT(	&cleanup,fpath,		/* 0644 */
+					S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+			
+			
+			/* create file with S_IWOTH bit set */
+			char w_fpath[MAX_PATH];
+			strcpy(w_fpath, fpath);
+			strcat(w_fpath,"_w");
+			ufiles_add(&k, w_fpath, IS_FILE);
+			SAFE_CREAT(	&cleanup,w_fpath,	/* 0644 */
+					S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+			/* change permissions r--r--rw*/
+			chmod(w_fpath,	S_IRUSR | /* skip S_IWUSR | */
+					S_IRGRP | S_IWGRP |
+					S_IWOTH | S_IROTH);
+
+			/* create sub directory */
+			char sub_dpath[MAX_PATH];
+			sprintf(sub_dpath,"%s/%s_%c%c%c%c%c", tdir->path,
+				_users[k],rchar(),rchar(),rchar(),rchar(),rchar());
+			ufiles_add(&k, sub_dpath, IS_DIRECTORY);
+			SAFE_MKDIR(&cleanup,sub_dpath,	S_IRWXU |
+							S_IRGRP | S_IXGRP |
+							S_IROTH | S_IXOTH 
+							/* 0755 */);
+
+			/* create local file inside user directory */
+			strcat(sub_dpath,"/local_");
+			strcat(sub_dpath,_users[k]);
+			strcat(sub_dpath,file_postfix);
+			ufiles_add(&k, sub_dpath, IS_FILE);
+			SAFE_CREAT(	&cleanup,sub_dpath,	/* 0644 */
+					S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+		} /* for(each user) */
+				
+	}
+	
+}
+
+static void ufiles_add(const int* id, const char* path, const int is_dir) 
+{
+	if(!id) return;
+	if(ufiles[*id].num>=MAX_ENTITIES)
+		tst_brkm(TBROK,&cleanup,"Unexpected number of files");
+
+	strcpy(ufiles[*id].file[ ufiles[*id].num ], path);
+	ufiles[*id].is_dir[ ufiles[*id].num ] = is_dir;
+	++ufiles[*id].num;
+}
+
+static void create_link_path(	char* buffer, const char* path,
+				const char* prefix,	const char* owner, 
+				const char* source_owner, const char* postfix) 
+{
+	/* to make sure name is unique */
+	static int count = 0;
+	++count;
+	
+	int len = strlen(path) + strlen(prefix) + strlen(owner) +
+		strlen(source_owner) + strlen(postfix);
+
+	if ( len>MAX_PATH || len<MIN_PATH )
+		tst_brkm(TBROK,&cleanup,"Length of the new symlink %d, "
+			"should be between min(%d) <len< max(%d)",
+			len, MIN_PATH, MAX_PATH);
+	/* construct link name */
+	sprintf(buffer,"%s/%s_%s_%s_%d%s",
+			path, prefix, owner, source_owner,
+			count, postfix);
+}
+
+static void show_mode(char* buffer, const mode_t* mode)
+{
+	sprintf(buffer,"%c%c%c %c%c%c %c%c%c",
+		*mode&S_IRUSR?'r':'-',*mode&S_IWUSR?'w':'-',*mode&S_IXUSR?'x':'-',
+		*mode&S_IRGRP?'r':'-',*mode&S_IWGRP?'w':'-',*mode&S_IXGRP?'x':'-',
+		*mode&S_IROTH?'r':'-',*mode&S_IWOTH?'w':'-',*mode&S_IXOTH?'x':'-');
+}
+
+/* create hard and symlinks */
+static int create_links(void) 
+{
+	int k;
+	int hlink_result = 0;
+	int hlink_tests_count = 0;
+
+	for(k=0;k<USERS_NUM;++k) {
+		/* set user who will create symlinks */
+		set_user( _users[k] );
+
+		/* create symlinks from each user 
+		 * to each world writable directory
+	 	*/
+		int j,p,i;
+
+		for(j=0;j<USERS_NUM;++j) {
+
+			/* get all users files and directories */
+			for(p=0;p<ufiles[j].num;++p) {
+				/* get all world-writable directrories */
+				for(i=0;i<TEST_DIR_NUM;++i) {
+
+					char new_path[MAX_PATH];
+					char hlink_path[MAX_PATH];
+
+					const struct base_test_dir* tdir = &test_dir[i];
+
+					/* create symlink */
+					const int* is_dir = &ufiles[j].is_dir[p];
+					create_link_path(new_path,tdir->path,
+						(*is_dir==1)?symlink_dir_prefix:symlink_prefix, _users[k],
+						_users[j],(*is_dir==1)?"":file_postfix);
+
+
+					/* create path for hard link */
+					create_link_path(hlink_path,tdir->path,
+							hardlink_prefix, _users[k],
+							_users[j],file_postfix);
+
+					strcpy(links.sym[links.s_num].owner,_users[k]);
+					strcpy(links.sym[links.s_num].source_owner,_users[j]);
+					
+					links.sym[links.s_num].in_wwd = tdir->world_writable;
+					links.sym[links.s_num].in_sticky = tdir->sticky;
+					links.sym[links.s_num].is_dir = *is_dir;
+
+					/* add symlink to array */
+					strcpy( links.sym[links.s_num].path, new_path );
+					if(links.s_num>=MAX_SYMLINKS)
+						tst_brkm(TBROK,&cleanup,"Unexpected number of symlinks");
+					++(links.s_num);
+
+					create_symlink( ufiles[j].file[p], new_path);
+
+					/* 
+					 * Hard Link Test-Case
+					 * Hard link can only be created if user has write access to a file or
+					 * owner of the file.
+					 */
+					
+					if (*is_dir) continue;
+					
+					struct stat stat_buf;
+
+					/* don't have access */
+					if (stat (ufiles[j].file[p], &stat_buf) == -1)
+						continue;
+					
+					/* current user has the same uid and gid */
+					int user_is_owner =	stat_buf.st_uid == geteuid() && 
+								stat_buf.st_gid == getegid();
+					
+					/* curent user has write access */
+					int user_can_write = stat_buf.st_mode & S_IWOTH;
+
+					int test_flag = (user_can_write || user_is_owner ||
+							k == ROOT )?CAN_CREATE:CANNOT_CREATE;
+					
+					if(links.h_num>=MAX_HARDLINKS)
+						tst_brkm(TBROK,&cleanup,"Unexpected number of symlinks");
+					strcpy(links.hrd[links.h_num].path,hlink_path);
+					++links.h_num;
+					int res = (test_flag!=create_link(ufiles[j].file[p], hlink_path));
+					
+					/* return 1 if one of the tests has failed */
+					hlink_result |= res;
+					++hlink_tests_count;
+					
+					char mode_buff[32];
+					show_mode(mode_buff,&stat_buf.st_mode);
+
+					tst_resm((res==1)?TFAIL:TPASS,
+						"Expected: %s create hard link from file %s, to file %s, "
+						"file's owner (%s), current user (%s), file mode (%s)",
+						(test_flag==CAN_CREATE)?"can":"can't",
+						ufiles[j].file[p],
+						hlink_path,
+						_users[j],_users[k],
+						mode_buff);
+
+				} /* for(each directory) */
+			} /* for(each file) */
+		} /* for(each user) */
+	} /* for(each user) */
+
+	return hlink_result;
+}
+
+int check_all_symlinks(void) {
+	
+	int symlink_result = 0;
+	/* root can follow all links except links */
+	/* in world writable directories and links's */
+	/* owner isn't root */
+	int k,i;
+	for(k=0;k<USERS_NUM;++k) {
+		set_user(_users[k]);
+		
+		for(i=0;i<links.s_num;++i) {
+			int root_isnt_owner = strcmp(links.sym[i].owner,_users[ROOT]);
+
+			int test_flag = CAN_FOLLOW;
+			if( k==ROOT && links.sym[i].in_wwd &&
+				links.sym[i].in_sticky && root_isnt_owner) {
+
+				/* We can't follow link */
+				test_flag = CANNOT_FOLLOW;
+			}
+
+			int res = (test_flag!=check_symlink(links.sym[i].path));
+
+			/* return 1 if one of the tests has failed */
+			symlink_result |= res;
+
+			tst_resm((res==1)?TFAIL:TPASS,"Expected: %s follow symlink %s, "
+					"link's owner (%s), target's owner (%s), "
+					"user who's tried (%s)",
+					(test_flag==CAN_FOLLOW)?"can":"can't",
+					links.sym[i].path, links.sym[i].owner,
+					links.sym[i].source_owner, _users[k]);
+		} /* for(links) */
+	} /* for(users) */
+
+	return symlink_result;
+}
+
+int hs_test_run(void)
+{
+	/* init header for hard link test */
+	tst_resm(TINFO," --- TEST HARD LINKS RESTRICTION --- \n");
+	/* create symlinks from each file and directory */
+	int result_hard_links = create_links();
+
+	tst_resm(TINFO," --- TEST SYMBOLIC LINKS RESTRICTION --- \n");
+	int result_sym_links = check_all_symlinks();
+
+	/* final results */
+	tst_resm(TINFO,"All TEST-CASES have been completed, summary:\n"
+				" - %d\thardlinks created\ttests: %s\n"
+				" - %d\tsymlinks  created\ttests: %s",
+				links.h_num, (result_hard_links==1)?"FAIL":"PASS",
+				links.s_num, (result_sym_links ==1)?"FAIL":"PASS");
+
+	/* set back privileged user to allow creation of gmon.out if ever needed */
+	set_user(_users[ROOT]);
+	
+	return (result_hard_links | result_sym_links);
+}
diff --git a/testcases/kernel/security/prot_hsymlinks/hs_test.h b/testcases/kernel/security/prot_hsymlinks/hs_test.h
new file mode 100644
index 0000000..6c950b3
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/hs_test.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ *
+ * 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 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.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author:
+ * Alexey Kodanev <alexey.kodanev@oracle.com>
+ *
+ * File: hs_test.h
+ *
+ * Test implementation
+ * -------------------
+ * Symlinks restriction applies only to privileged users (other
+ * combinations of non-privileged user, sticky bit and world-writable
+ * dirs are not affected). Only privileged user can't follow symlinks in 
+ * only sticky world-writable directory if he isn't owner of that link. 
+ * All other users can.
+ *
+ * Hard links restriction applies only to non-privileged users. Only 
+ * non-privileged user can't create hard links to files if he isn't owner 
+ * of the file or he doesn't have write access to the file despite of 
+ * file's directory permission.
+ */
+
+#ifndef HS_TEST_FILE_H
+#define HS_TEST_FILE_H
+
+/* init of the tests */
+extern void hs_test_init(void);
+
+/* run all tests
+ * return 1, if one of the test-cases has failed
+ */
+extern int hs_test_run(void);
+
+#endif /* TEST_FILE_H */
diff --git a/testcases/kernel/security/prot_hsymlinks/options.c b/testcases/kernel/security/prot_hsymlinks/options.c
new file mode 100644
index 0000000..eecd23e
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/options.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ *
+ * 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 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.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author:
+ * Alexey Kodanev <alexey.kodanev@oracle.com>
+ *
+ * File: options.c
+ *
+ * Implements program options
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <test.h>
+
+#include "cleanup.h"
+#include "options.h"
+
+static const char* program_name;
+
+char _users[USERS_NUM][MAX_USER_NAME];
+ 
+static void print_usage (FILE* stream, int exit_code)
+{
+    fprintf (stream, "Usage: %s options:\n", program_name);
+    fprintf (stream,
+    " -h --help Display this usage information.\n"
+    " -s --skip Skip cleanup.\n"
+    " -u --define test user name.\n"
+			);
+    tst_brkm(TBROK,&cleanup, "Print usage");
+}
+
+void init_options(int argc,char **argv)
+{
+	int next_option;
+	/* A string listing valid short options letters. */
+	const char* const short_options = "hsu:";
+
+	/* An array describing valid long options. */
+	const struct option long_options[] = {
+	    { "help", 0, NULL, 'h' },
+	    { "skip", 0, NULL, 's' },
+	    { "user", 0, NULL, 'u' },
+	    { NULL, 0, NULL, 0 } /* Required at end of array. */
+	};
+	program_name = argv[0];
+
+	const char* tmp_user_name=NULL;
+	do {
+		next_option = getopt_long (argc, argv, short_options,
+				    long_options, NULL);
+		switch (next_option) {
+		case 'h': /* -h or --help */
+			print_usage (stdout, 1);
+		break;
+		case 'u': /* -u or --user */
+			tmp_user_name = optarg;
+		break;
+		case 's': /* -s or --skip */
+			_skip_cleanup = 1;
+		break;
+		case '?': 
+			/* The user specified an invalid option. */
+			print_usage (stderr, 1);
+		case -1: /* Done with options. */
+		break;
+		default: /* Something else: unexpected. */
+			print_usage(stderr,1);
+		}
+	} while (next_option != -1);
+
+
+	/* initialize user names */
+	/* 1st user always root */
+	strcpy(_users[ROOT],"root");
+
+	/* create defualt user, if it's not defined in program's arguments */
+	if(tmp_user_name==NULL || strlen(tmp_user_name)<MIN_USER_NAME ||
+		!strcmp(tmp_user_name,"root") )
+		strcpy(_users[TEST_USER],"userhsym");
+	else {
+		if(strlen(tmp_user_name)>=MAX_USER_NAME) {
+			strncpy(_users[TEST_USER],tmp_user_name,MAX_USER_NAME-1);
+			_users[TEST_USER][MAX_USER_NAME-1]='\0';
+		} else
+			strcpy(_users[TEST_USER],tmp_user_name);
+	}		
+}
diff --git a/testcases/kernel/security/prot_hsymlinks/options.h b/testcases/kernel/security/prot_hsymlinks/options.h
new file mode 100644
index 0000000..d4f00cb
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/options.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ *
+ * 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 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.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author:
+ * Alexey Kodanev <alexey.kodanev@oracle.com>
+ *
+ * File: options.h
+ *
+ * Implements program options
+ */
+
+#ifndef OPTIONS_FILE_H
+#define OPTIONS_FILE_H
+
+#include <stdio.h>
+
+#include "wrp_users.h"
+
+/* users who will be participate in the tests */
+extern char _users[USERS_NUM][MAX_USER_NAME];
+
+/* init program options */
+extern void init_options(int argc,char **argv);
+
+
+#endif /* OPRIONS_FILE_H */
diff --git a/testcases/kernel/security/prot_hsymlinks/wrp_links.c b/testcases/kernel/security/prot_hsymlinks/wrp_links.c
new file mode 100644
index 0000000..62e895b
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/wrp_links.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ *
+ * 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 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.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author:
+ * Alexey Kodanev <alexey.kodanev@oracle.com>
+ *
+ * File: wrp_links.c
+ *
+ * Implements functions to deal 
+ * with hard and symbolic links
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <test.h>
+
+#include "cleanup.h"
+#include "wrp_links.h"
+
+struct open_modes {
+	const char* name;
+	const int mode;
+};
+
+/* differenet modes to try in the test */
+static const struct open_modes o_modes[] = {
+	{
+		.name 	= "O_RDONLY",
+		.mode	= O_RDONLY,
+	},
+	{
+		.name	= "O_WRONLY",
+		.mode	= O_WRONLY,
+	},
+	{
+		.name	= "O_RDWR",
+		.mode	= O_RDWR,
+	},
+	{
+		.name	= "O_RDONLY | O_NONBLOCK | O_DIRECTORY",
+		.mode	= O_RDONLY | O_NONBLOCK | O_DIRECTORY,
+	},
+	{ .name = NULL, .mode = -1, } /* end */
+};
+
+
+int check_symlink(const char* name) 
+{
+	int result = 0;
+	
+	const struct open_modes *o_mode = o_modes;
+	
+	while(o_mode->mode!=-1) {
+		
+		int fd = open(name, o_mode->mode);
+		if(fd==-1) {
+			/* can't open, continue testing */
+			result = -1;
+			++o_mode;
+			continue;
+		} else
+		if (close(fd)==-1) {
+		    tst_brkm(TBROK,&cleanup,"Can't close symlink: %s",name);
+		}
+		result = 0;
+		break;
+	}
+
+	return result;
+}
+
+int create_link(const char* old_path, const char* new_path)
+{
+	int result = link(old_path,new_path);
+	return result;
+}
+
+void create_symlink(const char* old_path, const char* new_path)
+{
+	if (symlink(old_path,new_path)==-1) {
+		fprintf(stderr,"Can't create symlink from %s, to %s\n",
+						old_path, new_path);
+	}
+}
diff --git a/testcases/kernel/security/prot_hsymlinks/wrp_links.h b/testcases/kernel/security/prot_hsymlinks/wrp_links.h
new file mode 100644
index 0000000..e319f48
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/wrp_links.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ *
+ * 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 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.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author:
+ * Alexey Kodanev <alexey.kodanev@oracle.com>
+ *
+ * File: wrp_links.h
+ *
+ * Implements functions to deal 
+ * with hard and symbolic links
+ */
+
+#ifndef LINKS_FILE_H
+#define LINKS_FILE_H
+
+/* create symbolic link */
+extern void create_symlink(const char* old_path, const char* new_path);
+
+/* it checks symlinks in multi-mode, return -1 if can't follow, 0 - if can */
+extern int check_symlink(const char* name);
+
+/* create hard link */
+extern int create_link(const char* old_path, const char* new_path);
+
+#endif /* LINKS_FILE_H */
diff --git a/testcases/kernel/security/prot_hsymlinks/wrp_users.c b/testcases/kernel/security/prot_hsymlinks/wrp_users.c
new file mode 100644
index 0000000..7abfff6
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/wrp_users.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ *
+ * 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 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.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author:
+ * Alexey Kodanev <alexey.kodanev@oracle.com>
+ *
+ * File: wrp_users.c
+ *
+ * Changes effective user id
+ */
+
+#include <pwd.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* LTP include */
+#include <test.h>
+#include <safe_macros.h>
+
+#include "cleanup.h"
+#include "wrp_users.h"
+
+void set_user(const char* name)
+{
+	struct passwd *pswd = getpwnam (name);
+
+	/* if can't find the user */
+	if(pswd==0)
+		tst_brkm(TBROK,&cleanup,"The user (%s) has to exist "
+						"on this machine to perform the test",
+						name);
+
+	uid_t user_id = pswd->pw_uid;
+	gid_t user_gr = pswd->pw_gid;
+
+	/* change effective user id and group id to test user */
+	SAFE_SETEGID(&cleanup,user_gr);
+
+	SAFE_SETEUID(&cleanup,user_id);
+}
diff --git a/testcases/kernel/security/prot_hsymlinks/wrp_users.h b/testcases/kernel/security/prot_hsymlinks/wrp_users.h
new file mode 100644
index 0000000..9ff49a2
--- /dev/null
+++ b/testcases/kernel/security/prot_hsymlinks/wrp_users.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ *
+ * 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 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.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author:
+ * Alexey Kodanev <alexey.kodanev@oracle.com>
+ *
+ * File: wrp_users.h
+ *
+ * Changes effective user id
+ */
+
+#ifndef USERS_FILE_H
+#define USERS_FILE_H
+
+#define MIN_USER_NAME 1
+#define MAX_USER_NAME 16
+
+enum USERS {
+	ROOT=0,
+	TEST_USER,
+	USERS_NUM
+};
+
+/* set effective user id and group id by name */
+extern void set_user(const char* name);
+
+#endif /* USERS_FILE_H */
-- 
1.7.1


------------------------------------------------------------------------------
Introducing AppDynamics Lite, a free troubleshooting tool for Java/.NET
Get 100% visibility into your production application - at no cost.
Code-level diagnostics for performance bottlenecks with <2% overhead
Download for free and get started troubleshooting in minutes.
http://p.sf.net/sfu/appdyn_d2d_ap1
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list

^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2013-05-07 14:28 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-05-06  9:41 [LTP] [PATCH] New core test of hardlinks and symlinks restrictions added in Linux 3.6. Disabled by default in Linux 3.7 Alexey Kodanev
2013-05-06 13:47 ` chrubis
     [not found]   ` <5187D15B.7080106@oracle.com>
2013-05-06 16:42     ` chrubis
2013-05-06 15:55 ` Mike Frysinger
  -- strict thread matches above, loose matches on Subject: below --
2013-05-07  8:40 Alexey Kodanev
2013-05-07 14:29 ` chrubis
2013-04-30  6:27 Alexey Kodanev
2013-04-30 12:24 ` chrubis
2013-04-30 17:24 ` Mike Frysinger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox