From a5c8655cfb97a370d167248f993134c718d97719 Mon Sep 17 00:00:00 2001 From: hiyoyolumi <862127279@qq.com> Date: Thu, 29 Sep 2022 17:50:39 +0800 Subject: [PATCH] overlayfs: add sysfs file for OverlayFS XUPT inclusion category: feature bugzilla: https://gitee.com/open_euler/dashboard?issue_id=I5WIS5 CVE: NA -------------------------------- In the actual production environment, Overlayfs often occurs some problems, such as continuous growth of quota statistics. There is no good way to define this category for the current environment. Overlatfs has many restrictions in the actual use process but it has not directly restricted at the code level. Therefore, some strange problems introduced in operation errors will occur during the use process. It is time-consuming. Based on this background, Overlayfs's maintenance function needs to be enhanced. This patch add sysfs file for overlayfs to recording the mount information. The sysfs file will be deleted only when overlayfs if truly unloaded. Mainly implementation: Put a hook function in file_system_type, and register sysfs after do_add_mount(). Signed-off-by: hiyoyolumi <862127279@qq.com> --- fs/namespace.c | 2 + fs/overlayfs/Makefile | 2 +- fs/overlayfs/overlayfs.h | 7 ++ fs/overlayfs/ovl_entry.h | 5 ++ fs/overlayfs/super.c | 38 +++++++++++ fs/overlayfs/sysfs.c | 144 +++++++++++++++++++++++++++++++++++++++ include/linux/fs.h | 4 ++ 7 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 fs/overlayfs/sysfs.c diff --git a/fs/namespace.c b/fs/namespace.c index 6e76f2a72cfc..3334f6916b3b 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2900,6 +2900,8 @@ static int do_new_mount(struct path *path, const char *fstype, int sb_flags, err = vfs_get_tree(fc); if (!err) err = do_new_mount_fc(fc, path, mnt_flags); + if (!err && type->mount_end) + err = type->mount_end(fc, path); put_fs_context(fc); return err; diff --git a/fs/overlayfs/Makefile b/fs/overlayfs/Makefile index 9164c585eb2f..328656b819a8 100644 --- a/fs/overlayfs/Makefile +++ b/fs/overlayfs/Makefile @@ -6,4 +6,4 @@ obj-$(CONFIG_OVERLAY_FS) += overlay.o overlay-objs := super.o namei.o util.o inode.o file.o dir.o readdir.o \ - copy_up.o export.o + copy_up.o export.o sysfs.o diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 898de3bf884e..d447d8ecea89 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -546,3 +546,10 @@ int ovl_set_origin(struct dentry *dentry, struct dentry *lower, /* export.c */ extern const struct export_operations ovl_export_operations; + +/* sysfs.c */ +int __init ovl_init_sysfs(void); +void ovl_exit_sysfs(void); +int ovl_register_sysfs(struct super_block *sb); +void ovl_unregister_sysfs(struct super_block *sb); +int ovl_mergedir_backup(struct super_block *sb, const char *str); diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h index b208eba5d0b6..9b4662336e84 100644 --- a/fs/overlayfs/ovl_entry.h +++ b/fs/overlayfs/ovl_entry.h @@ -5,10 +5,13 @@ * Copyright (C) 2016 Red Hat, Inc. */ +#include + struct ovl_config { char *lowerdir; char *upperdir; char *workdir; + char *mergedir; bool default_permissions; bool redirect_dir; bool redirect_follow; @@ -81,6 +84,8 @@ struct ovl_fs { struct dentry *whiteout; /* r/o snapshot of upperdir sb's only taken on volatile mounts */ errseq_t errseq; + struct kobject kobj; + struct completion kobj_unregister; }; static inline struct vfsmount *ovl_upper_mnt(struct ovl_fs *ofs) diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 45c596dfe3a3..477147faa67d 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "overlayfs.h" MODULE_AUTHOR("Miklos Szeredi "); @@ -244,9 +245,14 @@ static void ovl_free_fs(struct ovl_fs *ofs) kfree(ofs->config.lowerdir); kfree(ofs->config.upperdir); kfree(ofs->config.workdir); + kfree(ofs->config.mergedir); kfree(ofs->config.redirect_mode); if (ofs->creator_cred) put_cred(ofs->creator_cred); + + kobject_put(&ofs->kobj); + wait_for_completion(&ofs->kobj_unregister); + kfree(ofs); } @@ -254,6 +260,8 @@ static void ovl_put_super(struct super_block *sb) { struct ovl_fs *ofs = sb->s_fs_info; + ovl_unregister_sysfs(sb); + ovl_free_fs(ofs); } @@ -2054,11 +2062,32 @@ static struct dentry *ovl_mount(struct file_system_type *fs_type, int flags, return mount_nodev(fs_type, flags, raw_data, ovl_fill_super); } +static int ovl_mount_end(struct fs_context *fc, struct path *path) +{ + char buffer[PATH_MAX]; + const char *tmp; + int err; + + err = ovl_register_sysfs(fc->root->d_sb); + if (err) + return err; + + tmp = dentry_path_raw(path->dentry, buffer, PATH_MAX); + if (IS_ERR_OR_NULL(tmp)) + tmp = path->dentry->d_name.name; + err = ovl_mergedir_backup(fc->root->d_sb, tmp); + if (err) + return err; + + return err; +} + static struct file_system_type ovl_fs_type = { .owner = THIS_MODULE, .name = "overlay", .mount = ovl_mount, .kill_sb = kill_anon_super, + .mount_end = ovl_mount_end, }; MODULE_ALIAS_FS("overlay"); @@ -2081,6 +2110,12 @@ static int __init ovl_init(void) if (ovl_inode_cachep == NULL) return -ENOMEM; + err = ovl_init_sysfs(); + if (err) { + kmem_cache_destroy(ovl_inode_cachep); + return err; + } + err = ovl_aio_request_cache_init(); if (!err) { err = register_filesystem(&ovl_fs_type); @@ -2089,6 +2124,7 @@ static int __init ovl_init(void) ovl_aio_request_cache_destroy(); } + ovl_exit_sysfs(); kmem_cache_destroy(ovl_inode_cachep); return err; @@ -2105,6 +2141,8 @@ static void __exit ovl_exit(void) rcu_barrier(); kmem_cache_destroy(ovl_inode_cachep); ovl_aio_request_cache_destroy(); + + ovl_exit_sysfs(); } module_init(ovl_init); diff --git a/fs/overlayfs/sysfs.c b/fs/overlayfs/sysfs.c new file mode 100644 index 000000000000..2faf4edf22b3 --- /dev/null +++ b/fs/overlayfs/sysfs.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * fs/overlayfs/sysfs.c + * + * This file is used for creating a sysfs file for the + * overlay file system + * + * Based significantly on the fs/ext4/sysfs.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ovl_entry.h" + +static struct kobject *ovl_root; + +enum attr_id_t { + attr_upper, + attr_lower, + attr_work, + attr_merge, +}; + +struct ovl_attr { + struct attribute attr; + short attr_id; +}; + +#define OVL_ATTR(_name, _mode) \ + static struct ovl_attr ovl_attr_##_name = { \ + .attr = { .name = __stringify(_name), .mode = _mode }, \ + .attr_id = attr_##_name, \ + } + +#define ATTR_LIST(name) &ovl_attr_##name.attr + +OVL_ATTR(upper, 0440); +OVL_ATTR(lower, 0440); +OVL_ATTR(work, 0440); +OVL_ATTR(merge, 0440); +static struct attribute *default_attrs[] = { + ATTR_LIST(upper), + ATTR_LIST(lower), + ATTR_LIST(work), + ATTR_LIST(merge), + NULL +}; + +int ovl_mergedir_backup(struct super_block *sb, const char *str) +{ + struct ovl_fs *ofs = sb->s_fs_info; + + ofs->config.mergedir = kstrdup(str, GFP_KERNEL); + if (!ofs->config.mergedir) + return -ENOMEM; + return 0; +} + +static ssize_t ovl_sysfs_show(struct kobject *kobj, struct attribute *attr, char *buf) +{ + struct ovl_fs *ofs = container_of(kobj, struct ovl_fs, kobj); + struct ovl_attr *ovl_attribute = + container_of(attr, struct ovl_attr, attr); + + switch (ovl_attribute->attr_id) { + case attr_upper: + return snprintf(buf, PAGE_SIZE, "%s\n", + ofs->config.upperdir); + case attr_lower: + return snprintf(buf, PAGE_SIZE, "%s\n", + ofs->config.lowerdir); + case attr_work: + return snprintf(buf, PAGE_SIZE, "%s\n", + ofs->config.workdir); + case attr_merge: + return snprintf(buf, PAGE_SIZE, "%s\n", + ofs->config.mergedir); + default: + return -EPERM; + } +} + +static void ovl_kobj_release(struct kobject *kobj) +{ + struct ovl_fs *ofs = container_of(kobj, struct ovl_fs, kobj); + + complete(&ofs->kobj_unregister); +} + +static struct sysfs_ops ovl_sysfs_ops = { + .show = ovl_sysfs_show +}; + +static struct kobj_type ovl_sb_ktype = { + .sysfs_ops = &ovl_sysfs_ops, + .default_attrs = default_attrs, + .release = ovl_kobj_release +}; + +int ovl_register_sysfs(struct super_block *sb) +{ + struct ovl_fs *ofs = OVL_FS(sb); + int err; + + init_completion(&ofs->kobj_unregister); + + err = kobject_init_and_add(&ofs->kobj, &ovl_sb_ktype, + ovl_root, "merge_%d_%d", + MAJOR(sb->s_dev), MINOR(sb->s_dev)); + if (err) { + kobject_put(&ofs->kobj); + wait_for_completion(&ofs->kobj_unregister); + } + return err; +} + +void ovl_unregister_sysfs(struct super_block *sb) +{ + kobject_del(&OVL_FS(sb)->kobj); +} + +int __init ovl_init_sysfs(void) +{ + ovl_root = kobject_create_and_add("overlayfs", fs_kobj); + if (!ovl_root) + return -ENOMEM; + return 0; +} + +void ovl_exit_sysfs(void) +{ + kobject_put(ovl_root); + ovl_root = NULL; +} diff --git a/include/linux/fs.h b/include/linux/fs.h index fa9d89379da1..32d29c007a89 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2316,7 +2316,11 @@ struct file_system_type { struct lock_class_key i_mutex_key; struct lock_class_key i_mutex_dir_key; +#ifndef __GENKSYMS__ + int (*mount_end) (struct fs_context *, struct path *); +#else KABI_RESERVE(1) +#endif KABI_RESERVE(2) KABI_RESERVE(3) KABI_RESERVE(4) -- Gitee