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 <nuonuoli@tencent.com> Signed-off-by: Xiaoming Gao <newtongao@tencent.com> Signed-off-by: katrinzhou <katrinzhou@tencent.com> Signed-off-by: Kairui Song <kasong@tencent.com>
This commit is contained in:
parent
1c4e7e7a52
commit
7dbd79cf59
|
@ -12,6 +12,7 @@
|
||||||
#include <linux/security.h>
|
#include <linux/security.h>
|
||||||
#include <linux/fs_struct.h>
|
#include <linux/fs_struct.h>
|
||||||
#include <linux/sched/task.h>
|
#include <linux/sched/task.h>
|
||||||
|
#include <linux/shield_mounts.h>
|
||||||
|
|
||||||
#include "proc/internal.h" /* only for get_proc_task() in ->open() */
|
#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 mount *r = real_mount(mnt);
|
||||||
struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
|
struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
|
||||||
struct super_block *sb = mnt_path.dentry->d_sb;
|
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) {
|
if (sb->s_op->show_devname) {
|
||||||
err = sb->s_op->show_devname(m, mnt_path.dentry);
|
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 mount *r = real_mount(mnt);
|
||||||
struct super_block *sb = mnt->mnt_sb;
|
struct super_block *sb = mnt->mnt_sb;
|
||||||
struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
|
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,
|
seq_printf(m, "%i %i %u:%u ", r->mnt_id, r->mnt_parent->mnt_id,
|
||||||
MAJOR(sb->s_dev), MINOR(sb->s_dev));
|
MAJOR(sb->s_dev), MINOR(sb->s_dev));
|
||||||
|
|
|
@ -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__ */
|
|
@ -23,4 +23,8 @@ config TKERNEL_NETATOP
|
||||||
help
|
help
|
||||||
Netatop module from TKernel
|
Netatop module from TKernel
|
||||||
|
|
||||||
|
config TKERNEL_SHIELD_MOUNTS
|
||||||
|
bool 'Shield mount'
|
||||||
|
default n
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -2,3 +2,4 @@ obj-$(CONFIG_TKERNEL) += base.o
|
||||||
obj-$(CONFIG_TKERNEL_NONPRIV_NETBIND) += netbind.o
|
obj-$(CONFIG_TKERNEL_NONPRIV_NETBIND) += netbind.o
|
||||||
obj-$(CONFIG_TKERNEL_TTOOLS) += ttools/
|
obj-$(CONFIG_TKERNEL_TTOOLS) += ttools/
|
||||||
obj-$(CONFIG_TKERNEL_NETATOP) += netatop/
|
obj-$(CONFIG_TKERNEL_NETATOP) += netatop/
|
||||||
|
obj-$(CONFIG_TKERNEL_SHIELD_MOUNTS) += shield_mounts.o
|
||||||
|
|
|
@ -0,0 +1,273 @@
|
||||||
|
#include <linux/tkernel.h>
|
||||||
|
#include <linux/seq_file.h>
|
||||||
|
#include <linux/proc_fs.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <linux/shield_mounts.h>
|
||||||
|
#include <linux/pid_namespace.h>
|
||||||
|
|
||||||
|
#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);
|
Loading…
Reference in New Issue