[Devel] [PATCH RH9 01/16] ve/sysctl: write permission restriction

Pavel Tikhomirov ptikhomirov at virtuozzo.com
Tue Sep 28 15:40:51 MSK 2021


From: Konstantin Khlebnikov <khlebnikov at openvz.org>

This patch patch adds lightweight virualization for sysctl entries:

		with S_ISVTX	without S_ISVTX
init_pid_ns	read-write	read-write
container	read-write	read-only

https://jira.sw.ru/browse/PSBM-18022

Signed-off-by: Konstantin Khlebnikov <khlebnikov at openvz.org>

+++
VE/PROC/SYSCTL: show real permissions in stat

This patch calls ->permissions() callback from ->getattr() method,
as result stat() for proc entries in /proc/sys will show real permissions.
Also this patch hides sticky-bit (S_ISVTX).

Signed-off-by: Konstantin Khlebnikov <khlebnikov at openvz.org>

+++
ve/fs: Fix invalid dereference in proc_sys_getattr()

grab_header() may return -ENOENT. In this case root in the below

        struct ctl_table_header *head = grab_header(inode);
	struct ctl_table_root *root = head->root;

dereferences (void *)-ENOENT, that leads to page fault and crash.
Fix that.

https://jira.sw.ru/browse/PSBM-56704

Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>

mFixes (to merge): ac555dd ("VE/PROC/SYSCTL: show real permissions in stat")
+ hunk from 95c9cb3 ("SYSCTL: fix compilation")

+++
VE: use ve environtment for sysctl restrictions

https://jira.sw.ru/browse/PSBM-18032
https://jira.sw.ru/browse/PSBM-18030

Signed-off-by: Konstantin Khlebnikov <khlebnikov at openvz.org>

(cherry picked from commit 57c6f66050d2176f8a9847f8284cb3d345863a88)
Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>

Moving root variable to make proc_sys_getattr code more solid.
Note: sysctl_root_permissions check does not affect /proc/sys/user
/proc/sys/net sysctls, they have their own ->permissions handlers.

(cherry picked from vz8 commit bdc26f95dd3371b8b80fa943215065e0836f7fb5)
Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
---
 fs/proc/proc_sysctl.c | 30 ++++++++++++++++++++++++++----
 1 file changed, 26 insertions(+), 4 deletions(-)

diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 5d66faecd4ef..f6415add610e 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -11,6 +11,7 @@
 #include <linux/sched.h>
 #include <linux/cred.h>
 #include <linux/namei.h>
+#include <linux/nsproxy.h>
 #include <linux/mm.h>
 #include <linux/uio.h>
 #include <linux/module.h>
@@ -66,6 +67,16 @@ static struct ctl_table root_table[] = {
 	},
 	{ }
 };
+
+static int sysctl_root_permissions(struct ctl_table_header *head,
+		struct ctl_table *table)
+{
+	if (ve_is_super(get_exec_env()) || (table->mode & S_ISVTX))
+		return table->mode;
+
+	return table->mode & ~S_IWUGO;
+}
+
 static struct ctl_table_root sysctl_table_root = {
 	.default_set.dir.header = {
 		{{.count = 1,
@@ -75,6 +86,7 @@ static struct ctl_table_root sysctl_table_root = {
 		.root = &sysctl_table_root,
 		.set = &sysctl_table_root.default_set,
 	},
+	.permissions = sysctl_root_permissions,
 };
 
 static DEFINE_SPINLOCK(sysctl_lock);
@@ -452,7 +464,7 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
 	spin_unlock(&sysctl_lock);
 
 	inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
-	inode->i_mode = table->mode;
+	inode->i_mode = table->mode & S_IRWXUGO;
 	if (!S_ISDIR(table->mode)) {
 		inode->i_mode |= S_IFREG;
 		inode->i_op = &proc_sys_inode_operations;
@@ -839,8 +851,16 @@ static int proc_sys_getattr(struct user_namespace *mnt_userns,
 		return PTR_ERR(head);
 
 	generic_fillattr(&init_user_ns, inode, stat);
-	if (table)
-		stat->mode = (stat->mode & S_IFMT) | table->mode;
+
+	if (table) {
+		struct ctl_table_root *root = head->root;
+		umode_t mode = table->mode;
+
+		if (root->permissions)
+			mode = root->permissions(head, table);
+
+		stat->mode = (stat->mode & S_IFMT) | (mode & S_IRWXUGO);
+	}
 
 	sysctl_head_finish(head);
 	return 0;
@@ -1135,11 +1155,13 @@ static int sysctl_check_table(const char *path, struct ctl_table *table)
 				err |= sysctl_err(path, table, "No maxlen");
 			else
 				err |= sysctl_check_table_array(path, table);
+			if (table->mode & S_ISVTX)
+				err |= sysctl_err(path, table, "Unsafe v12n");
 		}
 		if (!table->proc_handler)
 			err |= sysctl_err(path, table, "No proc_handler");
 
-		if ((table->mode & (S_IRUGO|S_IWUGO)) != table->mode)
+		if ((table->mode & (S_IRUGO|S_IWUGO|S_ISVTX)) != table->mode)
 			err |= sysctl_err(path, table, "bogus .mode 0%o",
 				table->mode);
 	}
-- 
2.31.1



More information about the Devel mailing list