From 7dbd79cf59e88173f385083fdf39603a49c99233 Mon Sep 17 00:00:00 2001 From: katrinzhou Date: Wed, 6 Dec 2023 00:27:39 +0800 Subject: [PATCH] tkernel: mounts: add shield mountpoint in container support Upstream: no Add shield mountpoint in container support $ echo "set /dev/name /mnt/point" >/proc/tkernel/shield_mounts to shield the mountpoint $ echo "clear /dev/name /mnt/point" >/proc/tkernel/shield_mounts to delete the mountpoint shielded Signed-off-by: Weiwei Li Signed-off-by: Xiaoming Gao Signed-off-by: katrinzhou Signed-off-by: Kairui Song --- fs/proc_namespace.c | 11 +- include/linux/shield_mounts.h | 15 ++ kernel/tkernel/Kconfig | 4 + kernel/tkernel/Makefile | 1 + kernel/tkernel/shield_mounts.c | 273 +++++++++++++++++++++++++++++++++ 5 files changed, 302 insertions(+), 2 deletions(-) create mode 100644 include/linux/shield_mounts.h create mode 100644 kernel/tkernel/shield_mounts.c diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c index 250eb5bf7b52..999de76e44fa 100644 --- a/fs/proc_namespace.c +++ b/fs/proc_namespace.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "proc/internal.h" /* only for get_proc_task() in ->open() */ @@ -104,7 +105,10 @@ static int show_vfsmnt(struct seq_file *m, struct vfsmount *mnt) struct mount *r = real_mount(mnt); struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; struct super_block *sb = mnt_path.dentry->d_sb; - int err; + int err = 0; + + if (is_mount_shielded(current, r->mnt_devname ? r->mnt_devname : "none", mnt)) + goto out; if (sb->s_op->show_devname) { err = sb->s_op->show_devname(m, mnt_path.dentry); @@ -138,7 +142,10 @@ static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt) struct mount *r = real_mount(mnt); struct super_block *sb = mnt->mnt_sb; struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; - int err; + int err = 0; + + if (is_mount_shielded(current, r->mnt_devname ? r->mnt_devname : "none", mnt)) + goto out; seq_printf(m, "%i %i %u:%u ", r->mnt_id, r->mnt_parent->mnt_id, MAJOR(sb->s_dev), MINOR(sb->s_dev)); diff --git a/include/linux/shield_mounts.h b/include/linux/shield_mounts.h new file mode 100644 index 000000000000..dc4d31593c58 --- /dev/null +++ b/include/linux/shield_mounts.h @@ -0,0 +1,15 @@ +#ifndef __SHIELD_MOUNTS_H__ +#define __SHIELD_MOUNTS_H__ + +#ifdef CONFIG_TKERNEL_SHIELD_MOUNTS +bool is_mount_shielded(struct task_struct *task, + const char *dev_name, struct vfsmount *mnt); +#else +static inline bool is_mount_shielded(struct task_struct *task, + const char *dev_name, struct vfsmount *mnt) +{ + return false; +} +#endif + +#endif /* __SHIELD_MOUNTS_H__ */ diff --git a/kernel/tkernel/Kconfig b/kernel/tkernel/Kconfig index 903dc615328b..d480fccb7e28 100644 --- a/kernel/tkernel/Kconfig +++ b/kernel/tkernel/Kconfig @@ -23,4 +23,8 @@ config TKERNEL_NETATOP help Netatop module from TKernel +config TKERNEL_SHIELD_MOUNTS + bool 'Shield mount' + default n + endif diff --git a/kernel/tkernel/Makefile b/kernel/tkernel/Makefile index a01ec41f7530..d27349ac894b 100644 --- a/kernel/tkernel/Makefile +++ b/kernel/tkernel/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_TKERNEL) += base.o obj-$(CONFIG_TKERNEL_NONPRIV_NETBIND) += netbind.o obj-$(CONFIG_TKERNEL_TTOOLS) += ttools/ obj-$(CONFIG_TKERNEL_NETATOP) += netatop/ +obj-$(CONFIG_TKERNEL_SHIELD_MOUNTS) += shield_mounts.o diff --git a/kernel/tkernel/shield_mounts.c b/kernel/tkernel/shield_mounts.c new file mode 100644 index 000000000000..8e11f35da836 --- /dev/null +++ b/kernel/tkernel/shield_mounts.c @@ -0,0 +1,273 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SHIELD_PATH_MAX 1024 + +struct mount_pair { + struct list_head list; + char dev_name[SHIELD_PATH_MAX]; + char mnt_path[SHIELD_PATH_MAX]; +}; + +static DEFINE_RWLOCK(shield_mounts_lock); +static LIST_HEAD(shield_mounts_list); +static unsigned int shield_mounts_count; +static int shield_mounts_max = 512; + +static bool __is_mount_shielded(const char *dev_name, const char *mount_path) +{ + bool ret = false; + struct mount_pair *p; + + read_lock(&shield_mounts_lock); + list_for_each_entry(p, &shield_mounts_list, list) { + if (!strcmp(p->dev_name, dev_name) && + !strcmp(p->mnt_path, mount_path)) { + ret = true; + break; + } + } + read_unlock(&shield_mounts_lock); + + return ret; +} + +static bool is_in_container(struct task_struct *task) +{ + if (task_active_pid_ns(task)->level) + return true; + else + return false; +} + +bool is_mount_shielded(struct task_struct *task, const char *dev_name, struct vfsmount *mnt) +{ + struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; + char *p, *buf; + bool ret; + + if (!is_in_container(task)) + return false; + + buf = kmalloc(PATH_MAX, GFP_KERNEL); + if (!buf) + return false; + + p = d_path(&mnt_path, buf, PAGE_SIZE); + if (IS_ERR(p)) + ret = PTR_ERR(p); + else + ret = __is_mount_shielded(dev_name, p); + kfree(buf); + + return ret; +} + +static int shield_mounts_search_and_insert(struct mount_pair *item) +{ + int ret = -EEXIST; + struct mount_pair *p; + + write_lock(&shield_mounts_lock); + + list_for_each_entry(p, &shield_mounts_list, list) { + if (!strcmp(p->dev_name, item->dev_name) && + !strcmp(p->mnt_path, item->mnt_path)) + goto unlock; + } + + if (shield_mounts_count >= shield_mounts_max) { + ret = -ENOMEM; + goto unlock; + } + + list_add_tail(&item->list, &shield_mounts_list); + shield_mounts_count++; + ret = 0; + +unlock: + write_unlock(&shield_mounts_lock); + return ret; +} + +static int shield_mounts_search_and_del(struct mount_pair *item) +{ + struct mount_pair *p; + + write_lock(&shield_mounts_lock); + + list_for_each_entry(p, &shield_mounts_list, list) { + if (!strcmp(p->dev_name, item->dev_name) && + !strcmp(p->mnt_path, item->mnt_path)) { + list_del(&p->list); + kfree(p); + shield_mounts_count--; + goto unlock; + } + } + +unlock: + write_unlock(&shield_mounts_lock); + return 0; +} + +/* helper function */ +static void str_escape(char *s, const char *esc) +{ + char *p = s; + while (p && *p != '\0') { + char c = *p++; + while (c != '\0' && strchr(esc, c)) + c = *p++; + *s++ = c; + } + *s = '\0'; +} + +/* + * parse buffer to get shield mount info + * "set devpath mountpoint": means to add a new shield mount info + * "clear devpath mountpoint": means to delete an exist one + */ +static int shield_mounts_parse(char *buf, bool *is_set, struct mount_pair *item) +{ + char *token; + + str_escape(buf, "\t\n"); + buf = skip_spaces(buf); + token = strsep(&buf, " "); + if (!token || !*token || !buf) + goto error; + + if (!strcmp(token, "set")) { + /* set */ + *is_set = true; + } else if (!strcmp(token, "clear")) { + /* clear */ + *is_set = false; + } else { + printk(KERN_ERR"set parse error\n"); + goto error; + } + + buf = skip_spaces(buf); + /* dev path */ + token = strsep(&buf, " "); + if (!buf || !token || !*token || strlen(token) > (PATH_MAX-1)) { + printk(KERN_ERR"dev path faild\n"); + goto error; + } + memcpy(item->dev_name, token, strlen(token)+1); + + /* mnt */ + buf = strim(buf); + memcpy(item->mnt_path, buf, strlen(buf)+1); + + return 0; +error: + printk(KERN_ERR"Failed to parse shield mounts pair\n"); + return -EFAULT; +} + +static int shield_mounts_proc_show(struct seq_file *m, void *v) +{ + struct mount_pair *p; + + read_lock(&shield_mounts_lock); + + list_for_each_entry(p, &shield_mounts_list, list) { + seq_printf(m, "%s on %s\n", p->dev_name, p->mnt_path); + } + + read_unlock(&shield_mounts_lock); + return 0; +} + +static int shield_mounts_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, shield_mounts_proc_show, NULL); +} + + +static ssize_t shield_mounts_proc_write(struct file *file, const char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + char *buffer = NULL; + int ret = cnt; + int order = 1; + bool is_set; + struct mount_pair *item; + + /*max file lens for 8k*/ + if (!ubuf || cnt > PAGE_SIZE * (1 << order)) + return -EINVAL; + + buffer = (char *)__get_free_pages(GFP_KERNEL, order); + if (!buffer) + return -ENOMEM; + + if (copy_from_user(buffer, ubuf, cnt)) { + ret = -EFAULT; + goto out; + } + + buffer[cnt] = 0; + + item = kmalloc(sizeof(struct mount_pair), GFP_KERNEL); + if (!item) { + printk(KERN_ERR"Failed to malloc mount_pair\n"); + ret = -ENOMEM; + goto out; + } + + /*parse buffer*/ + ret = shield_mounts_parse(buffer, &is_set, item); + if (ret) + goto out1; + + if (is_set) { + /*set */ + ret = shield_mounts_search_and_insert(item); + if (!ret) + item = NULL; + } else { + /* clear */ + ret = shield_mounts_search_and_del(item); + } + + if (!ret) + ret = cnt; +out1: + kfree(item); +out: + free_pages((unsigned long) buffer, order); + return ret; +} + +int shield_mounts_release(struct inode *inode, struct file *file) +{ + return single_release(inode, file); +} + +static const struct proc_ops shield_mounts_proc_fops = { + .proc_open = shield_mounts_proc_open, + .proc_read = seq_read, + .proc_write = shield_mounts_proc_write, + .proc_lseek = seq_lseek, + .proc_release = shield_mounts_release, +}; + +static int __init proc_shield_mounts_init(void) +{ + proc_create("shield_mounts", 0, proc_tkernel, &shield_mounts_proc_fops); + return 0; +} + +late_initcall(proc_shield_mounts_init);