Branch data 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.txt 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 : 3 : static int sysfs_get_tree(struct fs_context *fc) 27 : : { 28 : 3 : struct kernfs_fs_context *kfc = fc->fs_private; 29 : : int ret; 30 : : 31 : 3 : ret = kernfs_get_tree(fc); 32 : 3 : if (ret) 33 : : return ret; 34 : : 35 : 3 : if (kfc->new_sb_created) 36 : 3 : fc->root->d_sb->s_iflags |= SB_I_USERNS_VISIBLE; 37 : : return 0; 38 : : } 39 : : 40 : 3 : static void sysfs_fs_context_free(struct fs_context *fc) 41 : : { 42 : 3 : struct kernfs_fs_context *kfc = fc->fs_private; 43 : : 44 : 3 : if (kfc->ns_tag) 45 : 3 : kobj_ns_drop(KOBJ_NS_TYPE_NET, kfc->ns_tag); 46 : 3 : kernfs_free_fs_context(fc); 47 : 3 : kfree(kfc); 48 : 3 : } 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 : 3 : static int sysfs_init_fs_context(struct fs_context *fc) 56 : : { 57 : : struct kernfs_fs_context *kfc; 58 : : struct net *netns; 59 : : 60 : 3 : if (!(fc->sb_flags & SB_KERNMOUNT)) { 61 : 3 : if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET)) 62 : : return -EPERM; 63 : : } 64 : : 65 : 3 : kfc = kzalloc(sizeof(struct kernfs_fs_context), GFP_KERNEL); 66 : 3 : if (!kfc) 67 : : return -ENOMEM; 68 : : 69 : 3 : kfc->ns_tag = netns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); 70 : 3 : kfc->root = sysfs_root; 71 : 3 : kfc->magic = SYSFS_MAGIC; 72 : 3 : fc->fs_private = kfc; 73 : 3 : fc->ops = &sysfs_fs_context_ops; 74 : 3 : if (netns) { 75 : 3 : put_user_ns(fc->user_ns); 76 : 3 : fc->user_ns = get_user_ns(netns->user_ns); 77 : : } 78 : 3 : fc->global = true; 79 : 3 : 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 : 3 : int __init sysfs_init(void) 98 : : { 99 : : int err; 100 : : 101 : 3 : sysfs_root = kernfs_create_root(NULL, KERNFS_ROOT_EXTRA_OPEN_PERM_CHECK, 102 : : NULL); 103 : 3 : if (IS_ERR(sysfs_root)) 104 : 0 : return PTR_ERR(sysfs_root); 105 : : 106 : 3 : sysfs_root_kn = sysfs_root->kn; 107 : : 108 : 3 : err = register_filesystem(&sysfs_fs_type); 109 : 3 : if (err) { 110 : 0 : kernfs_destroy_root(sysfs_root); 111 : 0 : return err; 112 : : } 113 : : 114 : : return 0; 115 : : }