Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0 2 : /* 3 : * fs/sysfs/symlink.c - operations for initializing and mounting sysfs 4 : * 5 : * Copyright (c) 2001-3 Patrick Mochel 6 : * Copyright (c) 2007 SUSE Linux Products GmbH 7 : * Copyright (c) 2007 Tejun Heo <teheo@suse.de> 8 : * 9 : * Please see Documentation/filesystems/sysfs.rst for more information. 10 : */ 11 : 12 : #include <linux/fs.h> 13 : #include <linux/magic.h> 14 : #include <linux/mount.h> 15 : #include <linux/init.h> 16 : #include <linux/slab.h> 17 : #include <linux/user_namespace.h> 18 : #include <linux/fs_context.h> 19 : #include <net/net_namespace.h> 20 : 21 : #include "sysfs.h" 22 : 23 : static struct kernfs_root *sysfs_root; 24 : struct kernfs_node *sysfs_root_kn; 25 : 26 0 : static int sysfs_get_tree(struct fs_context *fc) 27 : { 28 0 : struct kernfs_fs_context *kfc = fc->fs_private; 29 : int ret; 30 : 31 0 : ret = kernfs_get_tree(fc); 32 0 : if (ret) 33 : return ret; 34 : 35 0 : if (kfc->new_sb_created) 36 0 : fc->root->d_sb->s_iflags |= SB_I_USERNS_VISIBLE; 37 : return 0; 38 : } 39 : 40 0 : static void sysfs_fs_context_free(struct fs_context *fc) 41 : { 42 0 : struct kernfs_fs_context *kfc = fc->fs_private; 43 : 44 0 : if (kfc->ns_tag) 45 0 : kobj_ns_drop(KOBJ_NS_TYPE_NET, kfc->ns_tag); 46 0 : kernfs_free_fs_context(fc); 47 0 : kfree(kfc); 48 0 : } 49 : 50 : static const struct fs_context_operations sysfs_fs_context_ops = { 51 : .free = sysfs_fs_context_free, 52 : .get_tree = sysfs_get_tree, 53 : }; 54 : 55 0 : static int sysfs_init_fs_context(struct fs_context *fc) 56 : { 57 : struct kernfs_fs_context *kfc; 58 : struct net *netns; 59 : 60 0 : if (!(fc->sb_flags & SB_KERNMOUNT)) { 61 0 : if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET)) 62 : return -EPERM; 63 : } 64 : 65 0 : kfc = kzalloc(sizeof(struct kernfs_fs_context), GFP_KERNEL); 66 0 : if (!kfc) 67 : return -ENOMEM; 68 : 69 0 : kfc->ns_tag = netns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); 70 0 : kfc->root = sysfs_root; 71 0 : kfc->magic = SYSFS_MAGIC; 72 0 : fc->fs_private = kfc; 73 0 : fc->ops = &sysfs_fs_context_ops; 74 0 : if (netns) { 75 0 : put_user_ns(fc->user_ns); 76 0 : fc->user_ns = get_user_ns(netns->user_ns); 77 : } 78 0 : fc->global = true; 79 0 : return 0; 80 : } 81 : 82 0 : static void sysfs_kill_sb(struct super_block *sb) 83 : { 84 0 : void *ns = (void *)kernfs_super_ns(sb); 85 : 86 0 : kernfs_kill_sb(sb); 87 0 : kobj_ns_drop(KOBJ_NS_TYPE_NET, ns); 88 0 : } 89 : 90 : static struct file_system_type sysfs_fs_type = { 91 : .name = "sysfs", 92 : .init_fs_context = sysfs_init_fs_context, 93 : .kill_sb = sysfs_kill_sb, 94 : .fs_flags = FS_USERNS_MOUNT, 95 : }; 96 : 97 1 : int __init sysfs_init(void) 98 : { 99 : int err; 100 : 101 1 : sysfs_root = kernfs_create_root(NULL, KERNFS_ROOT_EXTRA_OPEN_PERM_CHECK, 102 : NULL); 103 2 : if (IS_ERR(sysfs_root)) 104 0 : return PTR_ERR(sysfs_root); 105 : 106 1 : sysfs_root_kn = kernfs_root_to_node(sysfs_root); 107 : 108 1 : err = register_filesystem(&sysfs_fs_type); 109 1 : if (err) { 110 0 : kernfs_destroy_root(sysfs_root); 111 0 : return err; 112 : } 113 : 114 : return 0; 115 : }