diff options
-rw-r--r-- | arch/s390/hypfs/inode.c | 12 | ||||
-rw-r--r-- | drivers/firmware/efi/efi.c | 6 | ||||
-rw-r--r-- | fs/configfs/mount.c | 10 | ||||
-rw-r--r-- | fs/dcache.c | 11 | ||||
-rw-r--r-- | fs/debugfs/inode.c | 11 | ||||
-rw-r--r-- | fs/fuse/inode.c | 9 | ||||
-rw-r--r-- | fs/kernfs/dir.c | 38 | ||||
-rw-r--r-- | fs/kernfs/inode.c | 2 | ||||
-rw-r--r-- | fs/libfs.c | 95 | ||||
-rw-r--r-- | fs/namespace.c | 39 | ||||
-rw-r--r-- | fs/proc/generic.c | 23 | ||||
-rw-r--r-- | fs/proc/inode.c | 4 | ||||
-rw-r--r-- | fs/proc/internal.h | 6 | ||||
-rw-r--r-- | fs/proc/proc_sysctl.c | 37 | ||||
-rw-r--r-- | fs/proc/root.c | 9 | ||||
-rw-r--r-- | fs/pstore/inode.c | 12 | ||||
-rw-r--r-- | fs/sysfs/dir.c | 34 | ||||
-rw-r--r-- | fs/sysfs/mount.c | 5 | ||||
-rw-r--r-- | fs/tracefs/inode.c | 6 | ||||
-rw-r--r-- | include/linux/fs.h | 4 | ||||
-rw-r--r-- | include/linux/kernfs.h | 3 | ||||
-rw-r--r-- | include/linux/sysctl.h | 3 | ||||
-rw-r--r-- | include/linux/sysfs.h | 15 | ||||
-rw-r--r-- | kernel/cgroup.c | 10 | ||||
-rw-r--r-- | kernel/sysctl.c | 8 | ||||
-rw-r--r-- | security/inode.c | 10 | ||||
-rw-r--r-- | security/selinux/selinuxfs.c | 11 | ||||
-rw-r--r-- | security/smack/smackfs.c | 8 |
28 files changed, 340 insertions, 101 deletions
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index d3f896a35b98..2eeb0a0f506d 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c | |||
@@ -456,8 +456,6 @@ static const struct super_operations hypfs_s_ops = { | |||
456 | .show_options = hypfs_show_options, | 456 | .show_options = hypfs_show_options, |
457 | }; | 457 | }; |
458 | 458 | ||
459 | static struct kobject *s390_kobj; | ||
460 | |||
461 | static int __init hypfs_init(void) | 459 | static int __init hypfs_init(void) |
462 | { | 460 | { |
463 | int rc; | 461 | int rc; |
@@ -481,18 +479,16 @@ static int __init hypfs_init(void) | |||
481 | rc = -ENODATA; | 479 | rc = -ENODATA; |
482 | goto fail_hypfs_sprp_exit; | 480 | goto fail_hypfs_sprp_exit; |
483 | } | 481 | } |
484 | s390_kobj = kobject_create_and_add("s390", hypervisor_kobj); | 482 | rc = sysfs_create_mount_point(hypervisor_kobj, "s390"); |
485 | if (!s390_kobj) { | 483 | if (rc) |
486 | rc = -ENOMEM; | ||
487 | goto fail_hypfs_diag0c_exit; | 484 | goto fail_hypfs_diag0c_exit; |
488 | } | ||
489 | rc = register_filesystem(&hypfs_type); | 485 | rc = register_filesystem(&hypfs_type); |
490 | if (rc) | 486 | if (rc) |
491 | goto fail_filesystem; | 487 | goto fail_filesystem; |
492 | return 0; | 488 | return 0; |
493 | 489 | ||
494 | fail_filesystem: | 490 | fail_filesystem: |
495 | kobject_put(s390_kobj); | 491 | sysfs_remove_mount_point(hypervisor_kobj, "s390"); |
496 | fail_hypfs_diag0c_exit: | 492 | fail_hypfs_diag0c_exit: |
497 | hypfs_diag0c_exit(); | 493 | hypfs_diag0c_exit(); |
498 | fail_hypfs_sprp_exit: | 494 | fail_hypfs_sprp_exit: |
@@ -510,7 +506,7 @@ fail_dbfs_exit: | |||
510 | static void __exit hypfs_exit(void) | 506 | static void __exit hypfs_exit(void) |
511 | { | 507 | { |
512 | unregister_filesystem(&hypfs_type); | 508 | unregister_filesystem(&hypfs_type); |
513 | kobject_put(s390_kobj); | 509 | sysfs_remove_mount_point(hypervisor_kobj, "s390"); |
514 | hypfs_diag0c_exit(); | 510 | hypfs_diag0c_exit(); |
515 | hypfs_sprp_exit(); | 511 | hypfs_sprp_exit(); |
516 | hypfs_vm_exit(); | 512 | hypfs_vm_exit(); |
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index ca617f40574a..9fa8084a7c8d 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c | |||
@@ -66,7 +66,6 @@ static int __init parse_efi_cmdline(char *str) | |||
66 | early_param("efi", parse_efi_cmdline); | 66 | early_param("efi", parse_efi_cmdline); |
67 | 67 | ||
68 | struct kobject *efi_kobj; | 68 | struct kobject *efi_kobj; |
69 | static struct kobject *efivars_kobj; | ||
70 | 69 | ||
71 | /* | 70 | /* |
72 | * Let's not leave out systab information that snuck into | 71 | * Let's not leave out systab information that snuck into |
@@ -218,10 +217,9 @@ static int __init efisubsys_init(void) | |||
218 | goto err_remove_group; | 217 | goto err_remove_group; |
219 | 218 | ||
220 | /* and the standard mountpoint for efivarfs */ | 219 | /* and the standard mountpoint for efivarfs */ |
221 | efivars_kobj = kobject_create_and_add("efivars", efi_kobj); | 220 | error = sysfs_create_mount_point(efi_kobj, "efivars"); |
222 | if (!efivars_kobj) { | 221 | if (error) { |
223 | pr_err("efivars: Subsystem registration failed.\n"); | 222 | pr_err("efivars: Subsystem registration failed.\n"); |
224 | error = -ENOMEM; | ||
225 | goto err_remove_group; | 223 | goto err_remove_group; |
226 | } | 224 | } |
227 | 225 | ||
diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c index 537356742091..a8f3b589a2df 100644 --- a/fs/configfs/mount.c +++ b/fs/configfs/mount.c | |||
@@ -129,8 +129,6 @@ void configfs_release_fs(void) | |||
129 | } | 129 | } |
130 | 130 | ||
131 | 131 | ||
132 | static struct kobject *config_kobj; | ||
133 | |||
134 | static int __init configfs_init(void) | 132 | static int __init configfs_init(void) |
135 | { | 133 | { |
136 | int err = -ENOMEM; | 134 | int err = -ENOMEM; |
@@ -141,8 +139,8 @@ static int __init configfs_init(void) | |||
141 | if (!configfs_dir_cachep) | 139 | if (!configfs_dir_cachep) |
142 | goto out; | 140 | goto out; |
143 | 141 | ||
144 | config_kobj = kobject_create_and_add("config", kernel_kobj); | 142 | err = sysfs_create_mount_point(kernel_kobj, "config"); |
145 | if (!config_kobj) | 143 | if (err) |
146 | goto out2; | 144 | goto out2; |
147 | 145 | ||
148 | err = register_filesystem(&configfs_fs_type); | 146 | err = register_filesystem(&configfs_fs_type); |
@@ -152,7 +150,7 @@ static int __init configfs_init(void) | |||
152 | return 0; | 150 | return 0; |
153 | out3: | 151 | out3: |
154 | pr_err("Unable to register filesystem!\n"); | 152 | pr_err("Unable to register filesystem!\n"); |
155 | kobject_put(config_kobj); | 153 | sysfs_remove_mount_point(kernel_kobj, "config"); |
156 | out2: | 154 | out2: |
157 | kmem_cache_destroy(configfs_dir_cachep); | 155 | kmem_cache_destroy(configfs_dir_cachep); |
158 | configfs_dir_cachep = NULL; | 156 | configfs_dir_cachep = NULL; |
@@ -163,7 +161,7 @@ out: | |||
163 | static void __exit configfs_exit(void) | 161 | static void __exit configfs_exit(void) |
164 | { | 162 | { |
165 | unregister_filesystem(&configfs_fs_type); | 163 | unregister_filesystem(&configfs_fs_type); |
166 | kobject_put(config_kobj); | 164 | sysfs_remove_mount_point(kernel_kobj, "config"); |
167 | kmem_cache_destroy(configfs_dir_cachep); | 165 | kmem_cache_destroy(configfs_dir_cachep); |
168 | configfs_dir_cachep = NULL; | 166 | configfs_dir_cachep = NULL; |
169 | } | 167 | } |
diff --git a/fs/dcache.c b/fs/dcache.c index 592c4b582495..910968b4b6bf 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -2927,17 +2927,6 @@ restart: | |||
2927 | vfsmnt = &mnt->mnt; | 2927 | vfsmnt = &mnt->mnt; |
2928 | continue; | 2928 | continue; |
2929 | } | 2929 | } |
2930 | /* | ||
2931 | * Filesystems needing to implement special "root names" | ||
2932 | * should do so with ->d_dname() | ||
2933 | */ | ||
2934 | if (IS_ROOT(dentry) && | ||
2935 | (dentry->d_name.len != 1 || | ||
2936 | dentry->d_name.name[0] != '/')) { | ||
2937 | WARN(1, "Root dentry has weird name <%.*s>\n", | ||
2938 | (int) dentry->d_name.len, | ||
2939 | dentry->d_name.name); | ||
2940 | } | ||
2941 | if (!error) | 2930 | if (!error) |
2942 | error = is_mounted(vfsmnt) ? 1 : 2; | 2931 | error = is_mounted(vfsmnt) ? 1 : 2; |
2943 | break; | 2932 | break; |
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 7eaec88ea970..d6d1cf004123 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c | |||
@@ -716,20 +716,17 @@ bool debugfs_initialized(void) | |||
716 | } | 716 | } |
717 | EXPORT_SYMBOL_GPL(debugfs_initialized); | 717 | EXPORT_SYMBOL_GPL(debugfs_initialized); |
718 | 718 | ||
719 | |||
720 | static struct kobject *debug_kobj; | ||
721 | |||
722 | static int __init debugfs_init(void) | 719 | static int __init debugfs_init(void) |
723 | { | 720 | { |
724 | int retval; | 721 | int retval; |
725 | 722 | ||
726 | debug_kobj = kobject_create_and_add("debug", kernel_kobj); | 723 | retval = sysfs_create_mount_point(kernel_kobj, "debug"); |
727 | if (!debug_kobj) | 724 | if (retval) |
728 | return -EINVAL; | 725 | return retval; |
729 | 726 | ||
730 | retval = register_filesystem(&debug_fs_type); | 727 | retval = register_filesystem(&debug_fs_type); |
731 | if (retval) | 728 | if (retval) |
732 | kobject_put(debug_kobj); | 729 | sysfs_remove_mount_point(kernel_kobj, "debug"); |
733 | else | 730 | else |
734 | debugfs_registered = true; | 731 | debugfs_registered = true; |
735 | 732 | ||
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index ac81f48ab2f4..2913db2a5b99 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -1294,7 +1294,6 @@ static void fuse_fs_cleanup(void) | |||
1294 | } | 1294 | } |
1295 | 1295 | ||
1296 | static struct kobject *fuse_kobj; | 1296 | static struct kobject *fuse_kobj; |
1297 | static struct kobject *connections_kobj; | ||
1298 | 1297 | ||
1299 | static int fuse_sysfs_init(void) | 1298 | static int fuse_sysfs_init(void) |
1300 | { | 1299 | { |
@@ -1306,11 +1305,9 @@ static int fuse_sysfs_init(void) | |||
1306 | goto out_err; | 1305 | goto out_err; |
1307 | } | 1306 | } |
1308 | 1307 | ||
1309 | connections_kobj = kobject_create_and_add("connections", fuse_kobj); | 1308 | err = sysfs_create_mount_point(fuse_kobj, "connections"); |
1310 | if (!connections_kobj) { | 1309 | if (err) |
1311 | err = -ENOMEM; | ||
1312 | goto out_fuse_unregister; | 1310 | goto out_fuse_unregister; |
1313 | } | ||
1314 | 1311 | ||
1315 | return 0; | 1312 | return 0; |
1316 | 1313 | ||
@@ -1322,7 +1319,7 @@ static int fuse_sysfs_init(void) | |||
1322 | 1319 | ||
1323 | static void fuse_sysfs_cleanup(void) | 1320 | static void fuse_sysfs_cleanup(void) |
1324 | { | 1321 | { |
1325 | kobject_put(connections_kobj); | 1322 | sysfs_remove_mount_point(fuse_kobj, "connections"); |
1326 | kobject_put(fuse_kobj); | 1323 | kobject_put(fuse_kobj); |
1327 | } | 1324 | } |
1328 | 1325 | ||
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index fffca9517321..2d48d28e1640 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c | |||
@@ -592,6 +592,9 @@ int kernfs_add_one(struct kernfs_node *kn) | |||
592 | goto out_unlock; | 592 | goto out_unlock; |
593 | 593 | ||
594 | ret = -ENOENT; | 594 | ret = -ENOENT; |
595 | if (parent->flags & KERNFS_EMPTY_DIR) | ||
596 | goto out_unlock; | ||
597 | |||
595 | if ((parent->flags & KERNFS_ACTIVATED) && !kernfs_active(parent)) | 598 | if ((parent->flags & KERNFS_ACTIVATED) && !kernfs_active(parent)) |
596 | goto out_unlock; | 599 | goto out_unlock; |
597 | 600 | ||
@@ -783,6 +786,38 @@ struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, | |||
783 | return ERR_PTR(rc); | 786 | return ERR_PTR(rc); |
784 | } | 787 | } |
785 | 788 | ||
789 | /** | ||
790 | * kernfs_create_empty_dir - create an always empty directory | ||
791 | * @parent: parent in which to create a new directory | ||
792 | * @name: name of the new directory | ||
793 | * | ||
794 | * Returns the created node on success, ERR_PTR() value on failure. | ||
795 | */ | ||
796 | struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent, | ||
797 | const char *name) | ||
798 | { | ||
799 | struct kernfs_node *kn; | ||
800 | int rc; | ||
801 | |||
802 | /* allocate */ | ||
803 | kn = kernfs_new_node(parent, name, S_IRUGO|S_IXUGO|S_IFDIR, KERNFS_DIR); | ||
804 | if (!kn) | ||
805 | return ERR_PTR(-ENOMEM); | ||
806 | |||
807 | kn->flags |= KERNFS_EMPTY_DIR; | ||
808 | kn->dir.root = parent->dir.root; | ||
809 | kn->ns = NULL; | ||
810 | kn->priv = NULL; | ||
811 | |||
812 | /* link in */ | ||
813 | rc = kernfs_add_one(kn); | ||
814 | if (!rc) | ||
815 | return kn; | ||
816 | |||
817 | kernfs_put(kn); | ||
818 | return ERR_PTR(rc); | ||
819 | } | ||
820 | |||
786 | static struct dentry *kernfs_iop_lookup(struct inode *dir, | 821 | static struct dentry *kernfs_iop_lookup(struct inode *dir, |
787 | struct dentry *dentry, | 822 | struct dentry *dentry, |
788 | unsigned int flags) | 823 | unsigned int flags) |
@@ -1254,7 +1289,8 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, | |||
1254 | mutex_lock(&kernfs_mutex); | 1289 | mutex_lock(&kernfs_mutex); |
1255 | 1290 | ||
1256 | error = -ENOENT; | 1291 | error = -ENOENT; |
1257 | if (!kernfs_active(kn) || !kernfs_active(new_parent)) | 1292 | if (!kernfs_active(kn) || !kernfs_active(new_parent) || |
1293 | (new_parent->flags & KERNFS_EMPTY_DIR)) | ||
1258 | goto out; | 1294 | goto out; |
1259 | 1295 | ||
1260 | error = 0; | 1296 | error = 0; |
diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c index 2da8493a380b..756dd56aaf60 100644 --- a/fs/kernfs/inode.c +++ b/fs/kernfs/inode.c | |||
@@ -296,6 +296,8 @@ static void kernfs_init_inode(struct kernfs_node *kn, struct inode *inode) | |||
296 | case KERNFS_DIR: | 296 | case KERNFS_DIR: |
297 | inode->i_op = &kernfs_dir_iops; | 297 | inode->i_op = &kernfs_dir_iops; |
298 | inode->i_fop = &kernfs_dir_fops; | 298 | inode->i_fop = &kernfs_dir_fops; |
299 | if (kn->flags & KERNFS_EMPTY_DIR) | ||
300 | make_empty_dir_inode(inode); | ||
299 | break; | 301 | break; |
300 | case KERNFS_FILE: | 302 | case KERNFS_FILE: |
301 | inode->i_size = kn->attr.size; | 303 | inode->i_size = kn->attr.size; |
diff --git a/fs/libfs.c b/fs/libfs.c index 65e1feca8b98..88a4cb418756 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
@@ -1108,3 +1108,98 @@ const struct inode_operations simple_symlink_inode_operations = { | |||
1108 | .readlink = generic_readlink | 1108 | .readlink = generic_readlink |
1109 | }; | 1109 | }; |
1110 | EXPORT_SYMBOL(simple_symlink_inode_operations); | 1110 | EXPORT_SYMBOL(simple_symlink_inode_operations); |
1111 | |||
1112 | /* | ||
1113 | * Operations for a permanently empty directory. | ||
1114 | */ | ||
1115 | static struct dentry *empty_dir_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) | ||
1116 | { | ||
1117 | return ERR_PTR(-ENOENT); | ||
1118 | } | ||
1119 | |||
1120 | static int empty_dir_getattr(struct vfsmount *mnt, struct dentry *dentry, | ||
1121 | struct kstat *stat) | ||
1122 | { | ||
1123 | struct inode *inode = d_inode(dentry); | ||
1124 | generic_fillattr(inode, stat); | ||
1125 | return 0; | ||
1126 | } | ||
1127 | |||
1128 | static int empty_dir_setattr(struct dentry *dentry, struct iattr *attr) | ||
1129 | { | ||
1130 | return -EPERM; | ||
1131 | } | ||
1132 | |||
1133 | static int empty_dir_setxattr(struct dentry *dentry, const char *name, | ||
1134 | const void *value, size_t size, int flags) | ||
1135 | { | ||
1136 | return -EOPNOTSUPP; | ||
1137 | } | ||
1138 | |||
1139 | static ssize_t empty_dir_getxattr(struct dentry *dentry, const char *name, | ||
1140 | void *value, size_t size) | ||
1141 | { | ||
1142 | return -EOPNOTSUPP; | ||
1143 | } | ||
1144 | |||
1145 | static int empty_dir_removexattr(struct dentry *dentry, const char *name) | ||
1146 | { | ||
1147 | return -EOPNOTSUPP; | ||
1148 | } | ||
1149 | |||
1150 | static ssize_t empty_dir_listxattr(struct dentry *dentry, char *list, size_t size) | ||
1151 | { | ||
1152 | return -EOPNOTSUPP; | ||
1153 | } | ||
1154 | |||
1155 | static const struct inode_operations empty_dir_inode_operations = { | ||
1156 | .lookup = empty_dir_lookup, | ||
1157 | .permission = generic_permission, | ||
1158 | .setattr = empty_dir_setattr, | ||
1159 | .getattr = empty_dir_getattr, | ||
1160 | .setxattr = empty_dir_setxattr, | ||
1161 | .getxattr = empty_dir_getxattr, | ||
1162 | .removexattr = empty_dir_removexattr, | ||
1163 | .listxattr = empty_dir_listxattr, | ||
1164 | }; | ||
1165 | |||
1166 | static loff_t empty_dir_llseek(struct file *file, loff_t offset, int whence) | ||
1167 | { | ||
1168 | /* An empty directory has two entries . and .. at offsets 0 and 1 */ | ||
1169 | return generic_file_llseek_size(file, offset, whence, 2, 2); | ||
1170 | } | ||
1171 | |||
1172 | static int empty_dir_readdir(struct file *file, struct dir_context *ctx) | ||
1173 | { | ||
1174 | dir_emit_dots(file, ctx); | ||
1175 | return 0; | ||
1176 | } | ||
1177 | |||
1178 | static const struct file_operations empty_dir_operations = { | ||
1179 | .llseek = empty_dir_llseek, | ||
1180 | .read = generic_read_dir, | ||
1181 | .iterate = empty_dir_readdir, | ||
1182 | .fsync = noop_fsync, | ||
1183 | }; | ||
1184 | |||
1185 | |||
1186 | void make_empty_dir_inode(struct inode *inode) | ||
1187 | { | ||
1188 | set_nlink(inode, 2); | ||
1189 | inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; | ||
1190 | inode->i_uid = GLOBAL_ROOT_UID; | ||
1191 | inode->i_gid = GLOBAL_ROOT_GID; | ||
1192 | inode->i_rdev = 0; | ||
1193 | inode->i_size = 2; | ||
1194 | inode->i_blkbits = PAGE_SHIFT; | ||
1195 | inode->i_blocks = 0; | ||
1196 | |||
1197 | inode->i_op = &empty_dir_inode_operations; | ||
1198 | inode->i_fop = &empty_dir_operations; | ||
1199 | } | ||
1200 | |||
1201 | bool is_empty_dir_inode(struct inode *inode) | ||
1202 | { | ||
1203 | return (inode->i_fop == &empty_dir_operations) && | ||
1204 | (inode->i_op == &empty_dir_inode_operations); | ||
1205 | } | ||
diff --git a/fs/namespace.c b/fs/namespace.c index e99f1f4e00cd..c7cb8a526c05 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -2343,6 +2343,8 @@ unlock: | |||
2343 | return err; | 2343 | return err; |
2344 | } | 2344 | } |
2345 | 2345 | ||
2346 | static bool fs_fully_visible(struct file_system_type *fs_type, int *new_mnt_flags); | ||
2347 | |||
2346 | /* | 2348 | /* |
2347 | * create a new mount for userspace and request it to be added into the | 2349 | * create a new mount for userspace and request it to be added into the |
2348 | * namespace's tree | 2350 | * namespace's tree |
@@ -2374,6 +2376,10 @@ static int do_new_mount(struct path *path, const char *fstype, int flags, | |||
2374 | flags |= MS_NODEV; | 2376 | flags |= MS_NODEV; |
2375 | mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV; | 2377 | mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV; |
2376 | } | 2378 | } |
2379 | if (type->fs_flags & FS_USERNS_VISIBLE) { | ||
2380 | if (!fs_fully_visible(type, &mnt_flags)) | ||
2381 | return -EPERM; | ||
2382 | } | ||
2377 | } | 2383 | } |
2378 | 2384 | ||
2379 | mnt = vfs_kern_mount(type, flags, name, data); | 2385 | mnt = vfs_kern_mount(type, flags, name, data); |
@@ -3175,9 +3181,10 @@ bool current_chrooted(void) | |||
3175 | return chrooted; | 3181 | return chrooted; |
3176 | } | 3182 | } |
3177 | 3183 | ||
3178 | bool fs_fully_visible(struct file_system_type *type) | 3184 | static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags) |
3179 | { | 3185 | { |
3180 | struct mnt_namespace *ns = current->nsproxy->mnt_ns; | 3186 | struct mnt_namespace *ns = current->nsproxy->mnt_ns; |
3187 | int new_flags = *new_mnt_flags; | ||
3181 | struct mount *mnt; | 3188 | struct mount *mnt; |
3182 | bool visible = false; | 3189 | bool visible = false; |
3183 | 3190 | ||
@@ -3196,16 +3203,36 @@ bool fs_fully_visible(struct file_system_type *type) | |||
3196 | if (mnt->mnt.mnt_root != mnt->mnt.mnt_sb->s_root) | 3203 | if (mnt->mnt.mnt_root != mnt->mnt.mnt_sb->s_root) |
3197 | continue; | 3204 | continue; |
3198 | 3205 | ||
3199 | /* This mount is not fully visible if there are any child mounts | 3206 | /* Verify the mount flags are equal to or more permissive |
3200 | * that cover anything except for empty directories. | 3207 | * than the proposed new mount. |
3208 | */ | ||
3209 | if ((mnt->mnt.mnt_flags & MNT_LOCK_READONLY) && | ||
3210 | !(new_flags & MNT_READONLY)) | ||
3211 | continue; | ||
3212 | if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) && | ||
3213 | !(new_flags & MNT_NODEV)) | ||
3214 | continue; | ||
3215 | if ((mnt->mnt.mnt_flags & MNT_LOCK_ATIME) && | ||
3216 | ((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (new_flags & MNT_ATIME_MASK))) | ||
3217 | continue; | ||
3218 | |||
3219 | /* This mount is not fully visible if there are any | ||
3220 | * locked child mounts that cover anything except for | ||
3221 | * empty directories. | ||
3201 | */ | 3222 | */ |
3202 | list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) { | 3223 | list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) { |
3203 | struct inode *inode = child->mnt_mountpoint->d_inode; | 3224 | struct inode *inode = child->mnt_mountpoint->d_inode; |
3204 | if (!S_ISDIR(inode->i_mode)) | 3225 | /* Only worry about locked mounts */ |
3205 | goto next; | 3226 | if (!(mnt->mnt.mnt_flags & MNT_LOCKED)) |
3206 | if (inode->i_nlink > 2) | 3227 | continue; |
3228 | /* Is the directory permanetly empty? */ | ||
3229 | if (!is_empty_dir_inode(inode)) | ||
3207 | goto next; | 3230 | goto next; |
3208 | } | 3231 | } |
3232 | /* Preserve the locked attributes */ | ||
3233 | *new_mnt_flags |= mnt->mnt.mnt_flags & (MNT_LOCK_READONLY | \ | ||
3234 | MNT_LOCK_NODEV | \ | ||
3235 | MNT_LOCK_ATIME); | ||
3209 | visible = true; | 3236 | visible = true; |
3210 | goto found; | 3237 | goto found; |
3211 | next: ; | 3238 | next: ; |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index df6327a2b865..e5dee5c3188e 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -373,6 +373,10 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent, | |||
373 | WARN(1, "create '/proc/%s' by hand\n", qstr.name); | 373 | WARN(1, "create '/proc/%s' by hand\n", qstr.name); |
374 | return NULL; | 374 | return NULL; |
375 | } | 375 | } |
376 | if (is_empty_pde(*parent)) { | ||
377 | WARN(1, "attempt to add to permanently empty directory"); | ||
378 | return NULL; | ||
379 | } | ||
376 | 380 | ||
377 | ent = kzalloc(sizeof(struct proc_dir_entry) + qstr.len + 1, GFP_KERNEL); | 381 | ent = kzalloc(sizeof(struct proc_dir_entry) + qstr.len + 1, GFP_KERNEL); |
378 | if (!ent) | 382 | if (!ent) |
@@ -455,6 +459,25 @@ struct proc_dir_entry *proc_mkdir(const char *name, | |||
455 | } | 459 | } |
456 | EXPORT_SYMBOL(proc_mkdir); | 460 | EXPORT_SYMBOL(proc_mkdir); |
457 | 461 | ||
462 | struct proc_dir_entry *proc_create_mount_point(const char *name) | ||
463 | { | ||
464 | umode_t mode = S_IFDIR | S_IRUGO | S_IXUGO; | ||
465 | struct proc_dir_entry *ent, *parent = NULL; | ||
466 | |||
467 | ent = __proc_create(&parent, name, mode, 2); | ||
468 | if (ent) { | ||
469 | ent->data = NULL; | ||
470 | ent->proc_fops = NULL; | ||
471 | ent->proc_iops = NULL; | ||
472 | if (proc_register(parent, ent) < 0) { | ||
473 | kfree(ent); | ||
474 | parent->nlink--; | ||
475 | ent = NULL; | ||
476 | } | ||
477 | } | ||
478 | return ent; | ||
479 | } | ||
480 | |||
458 | struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, | 481 | struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, |
459 | struct proc_dir_entry *parent, | 482 | struct proc_dir_entry *parent, |
460 | const struct file_operations *proc_fops, | 483 | const struct file_operations *proc_fops, |
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index afe232b9df6e..bd95b9fdebb0 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -422,6 +422,10 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de) | |||
422 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | 422 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; |
423 | PROC_I(inode)->pde = de; | 423 | PROC_I(inode)->pde = de; |
424 | 424 | ||
425 | if (is_empty_pde(de)) { | ||
426 | make_empty_dir_inode(inode); | ||
427 | return inode; | ||
428 | } | ||
425 | if (de->mode) { | 429 | if (de->mode) { |
426 | inode->i_mode = de->mode; | 430 | inode->i_mode = de->mode; |
427 | inode->i_uid = de->uid; | 431 | inode->i_uid = de->uid; |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index c835b94c0cd3..aa2781095bd1 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
@@ -191,6 +191,12 @@ static inline struct proc_dir_entry *pde_get(struct proc_dir_entry *pde) | |||
191 | } | 191 | } |
192 | extern void pde_put(struct proc_dir_entry *); | 192 | extern void pde_put(struct proc_dir_entry *); |
193 | 193 | ||
194 | static inline bool is_empty_pde(const struct proc_dir_entry *pde) | ||
195 | { | ||
196 | return S_ISDIR(pde->mode) && !pde->proc_iops; | ||
197 | } | ||
198 | struct proc_dir_entry *proc_create_mount_point(const char *name); | ||
199 | |||
194 | /* | 200 | /* |
195 | * inode.c | 201 | * inode.c |
196 | */ | 202 | */ |
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index fea2561d773b..fdda62e6115e 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
@@ -19,6 +19,28 @@ static const struct inode_operations proc_sys_inode_operations; | |||
19 | static const struct file_operations proc_sys_dir_file_operations; | 19 | static const struct file_operations proc_sys_dir_file_operations; |
20 | static const struct inode_operations proc_sys_dir_operations; | 20 | static const struct inode_operations proc_sys_dir_operations; |
21 | 21 | ||
22 | /* Support for permanently empty directories */ | ||
23 | |||
24 | struct ctl_table sysctl_mount_point[] = { | ||
25 | { } | ||
26 | }; | ||
27 | |||
28 | static bool is_empty_dir(struct ctl_table_header *head) | ||
29 | { | ||
30 | return head->ctl_table[0].child == sysctl_mount_point; | ||
31 | } | ||
32 | |||
33 | static void set_empty_dir(struct ctl_dir *dir) | ||
34 | { | ||
35 | dir->header.ctl_table[0].child = sysctl_mount_point; | ||
36 | } | ||
37 | |||
38 | static void clear_empty_dir(struct ctl_dir *dir) | ||
39 | |||
40 | { | ||
41 | dir->header.ctl_table[0].child = NULL; | ||
42 | } | ||
43 | |||
22 | void proc_sys_poll_notify(struct ctl_table_poll *poll) | 44 | void proc_sys_poll_notify(struct ctl_table_poll *poll) |
23 | { | 45 | { |
24 | if (!poll) | 46 | if (!poll) |
@@ -187,6 +209,17 @@ static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header) | |||
187 | struct ctl_table *entry; | 209 | struct ctl_table *entry; |
188 | int err; | 210 | int err; |
189 | 211 | ||
212 | /* Is this a permanently empty directory? */ | ||
213 | if (is_empty_dir(&dir->header)) | ||
214 | return -EROFS; | ||
215 | |||
216 | /* Am I creating a permanently empty directory? */ | ||
217 | if (header->ctl_table == sysctl_mount_point) { | ||
218 | if (!RB_EMPTY_ROOT(&dir->root)) | ||
219 | return -EINVAL; | ||
220 | set_empty_dir(dir); | ||
221 | } | ||
222 | |||
190 | dir->header.nreg++; | 223 | dir->header.nreg++; |
191 | header->parent = dir; | 224 | header->parent = dir; |
192 | err = insert_links(header); | 225 | err = insert_links(header); |
@@ -202,6 +235,8 @@ fail: | |||
202 | erase_header(header); | 235 | erase_header(header); |
203 | put_links(header); | 236 | put_links(header); |
204 | fail_links: | 237 | fail_links: |
238 | if (header->ctl_table == sysctl_mount_point) | ||
239 | clear_empty_dir(dir); | ||
205 | header->parent = NULL; | 240 | header->parent = NULL; |
206 | drop_sysctl_table(&dir->header); | 241 | drop_sysctl_table(&dir->header); |
207 | return err; | 242 | return err; |
@@ -419,6 +454,8 @@ static struct inode *proc_sys_make_inode(struct super_block *sb, | |||
419 | inode->i_mode |= S_IFDIR; | 454 | inode->i_mode |= S_IFDIR; |
420 | inode->i_op = &proc_sys_dir_operations; | 455 | inode->i_op = &proc_sys_dir_operations; |
421 | inode->i_fop = &proc_sys_dir_file_operations; | 456 | inode->i_fop = &proc_sys_dir_file_operations; |
457 | if (is_empty_dir(head)) | ||
458 | make_empty_dir_inode(inode); | ||
422 | } | 459 | } |
423 | out: | 460 | out: |
424 | return inode; | 461 | return inode; |
diff --git a/fs/proc/root.c b/fs/proc/root.c index b7fa4bfe896a..68feb0f70e63 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c | |||
@@ -112,9 +112,6 @@ static struct dentry *proc_mount(struct file_system_type *fs_type, | |||
112 | ns = task_active_pid_ns(current); | 112 | ns = task_active_pid_ns(current); |
113 | options = data; | 113 | options = data; |
114 | 114 | ||
115 | if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type)) | ||
116 | return ERR_PTR(-EPERM); | ||
117 | |||
118 | /* Does the mounter have privilege over the pid namespace? */ | 115 | /* Does the mounter have privilege over the pid namespace? */ |
119 | if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) | 116 | if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) |
120 | return ERR_PTR(-EPERM); | 117 | return ERR_PTR(-EPERM); |
@@ -159,7 +156,7 @@ static struct file_system_type proc_fs_type = { | |||
159 | .name = "proc", | 156 | .name = "proc", |
160 | .mount = proc_mount, | 157 | .mount = proc_mount, |
161 | .kill_sb = proc_kill_sb, | 158 | .kill_sb = proc_kill_sb, |
162 | .fs_flags = FS_USERNS_MOUNT, | 159 | .fs_flags = FS_USERNS_VISIBLE | FS_USERNS_MOUNT, |
163 | }; | 160 | }; |
164 | 161 | ||
165 | void __init proc_root_init(void) | 162 | void __init proc_root_init(void) |
@@ -182,10 +179,10 @@ void __init proc_root_init(void) | |||
182 | #endif | 179 | #endif |
183 | proc_mkdir("fs", NULL); | 180 | proc_mkdir("fs", NULL); |
184 | proc_mkdir("driver", NULL); | 181 | proc_mkdir("driver", NULL); |
185 | proc_mkdir("fs/nfsd", NULL); /* somewhere for the nfsd filesystem to be mounted */ | 182 | proc_create_mount_point("fs/nfsd"); /* somewhere for the nfsd filesystem to be mounted */ |
186 | #if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE) | 183 | #if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE) |
187 | /* just give it a mountpoint */ | 184 | /* just give it a mountpoint */ |
188 | proc_mkdir("openprom", NULL); | 185 | proc_create_mount_point("openprom"); |
189 | #endif | 186 | #endif |
190 | proc_tty_init(); | 187 | proc_tty_init(); |
191 | proc_mkdir("bus", NULL); | 188 | proc_mkdir("bus", NULL); |
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index dc43b5f29305..3adcc4669fac 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c | |||
@@ -461,22 +461,18 @@ static struct file_system_type pstore_fs_type = { | |||
461 | .kill_sb = pstore_kill_sb, | 461 | .kill_sb = pstore_kill_sb, |
462 | }; | 462 | }; |
463 | 463 | ||
464 | static struct kobject *pstore_kobj; | ||
465 | |||
466 | static int __init init_pstore_fs(void) | 464 | static int __init init_pstore_fs(void) |
467 | { | 465 | { |
468 | int err = 0; | 466 | int err; |
469 | 467 | ||
470 | /* Create a convenient mount point for people to access pstore */ | 468 | /* Create a convenient mount point for people to access pstore */ |
471 | pstore_kobj = kobject_create_and_add("pstore", fs_kobj); | 469 | err = sysfs_create_mount_point(fs_kobj, "pstore"); |
472 | if (!pstore_kobj) { | 470 | if (err) |
473 | err = -ENOMEM; | ||
474 | goto out; | 471 | goto out; |
475 | } | ||
476 | 472 | ||
477 | err = register_filesystem(&pstore_fs_type); | 473 | err = register_filesystem(&pstore_fs_type); |
478 | if (err < 0) | 474 | if (err < 0) |
479 | kobject_put(pstore_kobj); | 475 | sysfs_remove_mount_point(fs_kobj, "pstore"); |
480 | 476 | ||
481 | out: | 477 | out: |
482 | return err; | 478 | return err; |
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 0b45ff42f374..94374e435025 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -121,3 +121,37 @@ int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, | |||
121 | 121 | ||
122 | return kernfs_rename_ns(kn, new_parent, kn->name, new_ns); | 122 | return kernfs_rename_ns(kn, new_parent, kn->name, new_ns); |
123 | } | 123 | } |
124 | |||
125 | /** | ||
126 | * sysfs_create_mount_point - create an always empty directory | ||
127 | * @parent_kobj: kobject that will contain this always empty directory | ||
128 | * @name: The name of the always empty directory to add | ||
129 | */ | ||
130 | int sysfs_create_mount_point(struct kobject *parent_kobj, const char *name) | ||
131 | { | ||
132 | struct kernfs_node *kn, *parent = parent_kobj->sd; | ||
133 | |||
134 | kn = kernfs_create_empty_dir(parent, name); | ||
135 | if (IS_ERR(kn)) { | ||
136 | if (PTR_ERR(kn) == -EEXIST) | ||
137 | sysfs_warn_dup(parent, name); | ||
138 | return PTR_ERR(kn); | ||
139 | } | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | EXPORT_SYMBOL_GPL(sysfs_create_mount_point); | ||
144 | |||
145 | /** | ||
146 | * sysfs_remove_mount_point - remove an always empty directory. | ||
147 | * @parent_kobj: kobject that will contain this always empty directory | ||
148 | * @name: The name of the always empty directory to remove | ||
149 | * | ||
150 | */ | ||
151 | void sysfs_remove_mount_point(struct kobject *parent_kobj, const char *name) | ||
152 | { | ||
153 | struct kernfs_node *parent = parent_kobj->sd; | ||
154 | |||
155 | kernfs_remove_by_name_ns(parent, name, NULL); | ||
156 | } | ||
157 | EXPORT_SYMBOL_GPL(sysfs_remove_mount_point); | ||
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 8a49486bf30c..1c6ac6fcee9f 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c | |||
@@ -31,9 +31,6 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, | |||
31 | bool new_sb; | 31 | bool new_sb; |
32 | 32 | ||
33 | if (!(flags & MS_KERNMOUNT)) { | 33 | if (!(flags & MS_KERNMOUNT)) { |
34 | if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type)) | ||
35 | return ERR_PTR(-EPERM); | ||
36 | |||
37 | if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET)) | 34 | if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET)) |
38 | return ERR_PTR(-EPERM); | 35 | return ERR_PTR(-EPERM); |
39 | } | 36 | } |
@@ -58,7 +55,7 @@ static struct file_system_type sysfs_fs_type = { | |||
58 | .name = "sysfs", | 55 | .name = "sysfs", |
59 | .mount = sysfs_mount, | 56 | .mount = sysfs_mount, |
60 | .kill_sb = sysfs_kill_sb, | 57 | .kill_sb = sysfs_kill_sb, |
61 | .fs_flags = FS_USERNS_MOUNT, | 58 | .fs_flags = FS_USERNS_VISIBLE | FS_USERNS_MOUNT, |
62 | }; | 59 | }; |
63 | 60 | ||
64 | int __init sysfs_init(void) | 61 | int __init sysfs_init(void) |
diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c index d92bdf3b079a..a43df11a163f 100644 --- a/fs/tracefs/inode.c +++ b/fs/tracefs/inode.c | |||
@@ -631,14 +631,12 @@ bool tracefs_initialized(void) | |||
631 | return tracefs_registered; | 631 | return tracefs_registered; |
632 | } | 632 | } |
633 | 633 | ||
634 | static struct kobject *trace_kobj; | ||
635 | |||
636 | static int __init tracefs_init(void) | 634 | static int __init tracefs_init(void) |
637 | { | 635 | { |
638 | int retval; | 636 | int retval; |
639 | 637 | ||
640 | trace_kobj = kobject_create_and_add("tracing", kernel_kobj); | 638 | retval = sysfs_create_mount_point(kernel_kobj, "tracing"); |
641 | if (!trace_kobj) | 639 | if (retval) |
642 | return -EINVAL; | 640 | return -EINVAL; |
643 | 641 | ||
644 | retval = register_filesystem(&trace_fs_type); | 642 | retval = register_filesystem(&trace_fs_type); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 3f1a84635da8..8a81fcbb0074 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1917,6 +1917,7 @@ struct file_system_type { | |||
1917 | #define FS_HAS_SUBTYPE 4 | 1917 | #define FS_HAS_SUBTYPE 4 |
1918 | #define FS_USERNS_MOUNT 8 /* Can be mounted by userns root */ | 1918 | #define FS_USERNS_MOUNT 8 /* Can be mounted by userns root */ |
1919 | #define FS_USERNS_DEV_MOUNT 16 /* A userns mount does not imply MNT_NODEV */ | 1919 | #define FS_USERNS_DEV_MOUNT 16 /* A userns mount does not imply MNT_NODEV */ |
1920 | #define FS_USERNS_VISIBLE 32 /* FS must already be visible */ | ||
1920 | #define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */ | 1921 | #define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */ |
1921 | struct dentry *(*mount) (struct file_system_type *, int, | 1922 | struct dentry *(*mount) (struct file_system_type *, int, |
1922 | const char *, void *); | 1923 | const char *, void *); |
@@ -2004,7 +2005,6 @@ extern int vfs_ustat(dev_t, struct kstatfs *); | |||
2004 | extern int freeze_super(struct super_block *super); | 2005 | extern int freeze_super(struct super_block *super); |
2005 | extern int thaw_super(struct super_block *super); | 2006 | extern int thaw_super(struct super_block *super); |
2006 | extern bool our_mnt(struct vfsmount *mnt); | 2007 | extern bool our_mnt(struct vfsmount *mnt); |
2007 | extern bool fs_fully_visible(struct file_system_type *); | ||
2008 | 2008 | ||
2009 | extern int current_umask(void); | 2009 | extern int current_umask(void); |
2010 | 2010 | ||
@@ -2816,6 +2816,8 @@ extern struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned in | |||
2816 | extern ssize_t generic_read_dir(struct file *, char __user *, size_t, loff_t *); | 2816 | extern ssize_t generic_read_dir(struct file *, char __user *, size_t, loff_t *); |
2817 | extern const struct file_operations simple_dir_operations; | 2817 | extern const struct file_operations simple_dir_operations; |
2818 | extern const struct inode_operations simple_dir_inode_operations; | 2818 | extern const struct inode_operations simple_dir_inode_operations; |
2819 | extern void make_empty_dir_inode(struct inode *inode); | ||
2820 | extern bool is_empty_dir_inode(struct inode *inode); | ||
2819 | struct tree_descr { char *name; const struct file_operations *ops; int mode; }; | 2821 | struct tree_descr { char *name; const struct file_operations *ops; int mode; }; |
2820 | struct dentry *d_alloc_name(struct dentry *, const char *); | 2822 | struct dentry *d_alloc_name(struct dentry *, const char *); |
2821 | extern int simple_fill_super(struct super_block *, unsigned long, struct tree_descr *); | 2823 | extern int simple_fill_super(struct super_block *, unsigned long, struct tree_descr *); |
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index e6b2f7db9c0c..123be25ea15a 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h | |||
@@ -45,6 +45,7 @@ enum kernfs_node_flag { | |||
45 | KERNFS_LOCKDEP = 0x0100, | 45 | KERNFS_LOCKDEP = 0x0100, |
46 | KERNFS_SUICIDAL = 0x0400, | 46 | KERNFS_SUICIDAL = 0x0400, |
47 | KERNFS_SUICIDED = 0x0800, | 47 | KERNFS_SUICIDED = 0x0800, |
48 | KERNFS_EMPTY_DIR = 0x1000, | ||
48 | }; | 49 | }; |
49 | 50 | ||
50 | /* @flags for kernfs_create_root() */ | 51 | /* @flags for kernfs_create_root() */ |
@@ -286,6 +287,8 @@ void kernfs_destroy_root(struct kernfs_root *root); | |||
286 | struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, | 287 | struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, |
287 | const char *name, umode_t mode, | 288 | const char *name, umode_t mode, |
288 | void *priv, const void *ns); | 289 | void *priv, const void *ns); |
290 | struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent, | ||
291 | const char *name); | ||
289 | struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, | 292 | struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, |
290 | const char *name, | 293 | const char *name, |
291 | umode_t mode, loff_t size, | 294 | umode_t mode, loff_t size, |
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 795d5fea5697..fa7bc29925c9 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h | |||
@@ -188,6 +188,9 @@ struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path, | |||
188 | void unregister_sysctl_table(struct ctl_table_header * table); | 188 | void unregister_sysctl_table(struct ctl_table_header * table); |
189 | 189 | ||
190 | extern int sysctl_init(void); | 190 | extern int sysctl_init(void); |
191 | |||
192 | extern struct ctl_table sysctl_mount_point[]; | ||
193 | |||
191 | #else /* CONFIG_SYSCTL */ | 194 | #else /* CONFIG_SYSCTL */ |
192 | static inline struct ctl_table_header *register_sysctl_table(struct ctl_table * table) | 195 | static inline struct ctl_table_header *register_sysctl_table(struct ctl_table * table) |
193 | { | 196 | { |
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 99382c0df17e..9f65758311a4 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h | |||
@@ -210,6 +210,10 @@ int __must_check sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name, | |||
210 | int __must_check sysfs_move_dir_ns(struct kobject *kobj, | 210 | int __must_check sysfs_move_dir_ns(struct kobject *kobj, |
211 | struct kobject *new_parent_kobj, | 211 | struct kobject *new_parent_kobj, |
212 | const void *new_ns); | 212 | const void *new_ns); |
213 | int __must_check sysfs_create_mount_point(struct kobject *parent_kobj, | ||
214 | const char *name); | ||
215 | void sysfs_remove_mount_point(struct kobject *parent_kobj, | ||
216 | const char *name); | ||
213 | 217 | ||
214 | int __must_check sysfs_create_file_ns(struct kobject *kobj, | 218 | int __must_check sysfs_create_file_ns(struct kobject *kobj, |
215 | const struct attribute *attr, | 219 | const struct attribute *attr, |
@@ -298,6 +302,17 @@ static inline int sysfs_move_dir_ns(struct kobject *kobj, | |||
298 | return 0; | 302 | return 0; |
299 | } | 303 | } |
300 | 304 | ||
305 | static inline int sysfs_create_mount_point(struct kobject *parent_kobj, | ||
306 | const char *name) | ||
307 | { | ||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | static inline void sysfs_remove_mount_point(struct kobject *parent_kobj, | ||
312 | const char *name) | ||
313 | { | ||
314 | } | ||
315 | |||
301 | static inline int sysfs_create_file_ns(struct kobject *kobj, | 316 | static inline int sysfs_create_file_ns(struct kobject *kobj, |
302 | const struct attribute *attr, | 317 | const struct attribute *attr, |
303 | const void *ns) | 318 | const void *ns) |
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 9ef9fc8a774b..f89d9292eee6 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -1939,8 +1939,6 @@ static struct file_system_type cgroup_fs_type = { | |||
1939 | .kill_sb = cgroup_kill_sb, | 1939 | .kill_sb = cgroup_kill_sb, |
1940 | }; | 1940 | }; |
1941 | 1941 | ||
1942 | static struct kobject *cgroup_kobj; | ||
1943 | |||
1944 | /** | 1942 | /** |
1945 | * task_cgroup_path - cgroup path of a task in the first cgroup hierarchy | 1943 | * task_cgroup_path - cgroup path of a task in the first cgroup hierarchy |
1946 | * @task: target task | 1944 | * @task: target task |
@@ -5070,13 +5068,13 @@ int __init cgroup_init(void) | |||
5070 | ss->bind(init_css_set.subsys[ssid]); | 5068 | ss->bind(init_css_set.subsys[ssid]); |
5071 | } | 5069 | } |
5072 | 5070 | ||
5073 | cgroup_kobj = kobject_create_and_add("cgroup", fs_kobj); | 5071 | err = sysfs_create_mount_point(fs_kobj, "cgroup"); |
5074 | if (!cgroup_kobj) | 5072 | if (err) |
5075 | return -ENOMEM; | 5073 | return err; |
5076 | 5074 | ||
5077 | err = register_filesystem(&cgroup_fs_type); | 5075 | err = register_filesystem(&cgroup_fs_type); |
5078 | if (err < 0) { | 5076 | if (err < 0) { |
5079 | kobject_put(cgroup_kobj); | 5077 | sysfs_remove_mount_point(fs_kobj, "cgroup"); |
5080 | return err; | 5078 | return err; |
5081 | } | 5079 | } |
5082 | 5080 | ||
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 812fcc3fd390..19b62b522158 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -1538,12 +1538,6 @@ static struct ctl_table vm_table[] = { | |||
1538 | { } | 1538 | { } |
1539 | }; | 1539 | }; |
1540 | 1540 | ||
1541 | #if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE) | ||
1542 | static struct ctl_table binfmt_misc_table[] = { | ||
1543 | { } | ||
1544 | }; | ||
1545 | #endif | ||
1546 | |||
1547 | static struct ctl_table fs_table[] = { | 1541 | static struct ctl_table fs_table[] = { |
1548 | { | 1542 | { |
1549 | .procname = "inode-nr", | 1543 | .procname = "inode-nr", |
@@ -1697,7 +1691,7 @@ static struct ctl_table fs_table[] = { | |||
1697 | { | 1691 | { |
1698 | .procname = "binfmt_misc", | 1692 | .procname = "binfmt_misc", |
1699 | .mode = 0555, | 1693 | .mode = 0555, |
1700 | .child = binfmt_misc_table, | 1694 | .child = sysctl_mount_point, |
1701 | }, | 1695 | }, |
1702 | #endif | 1696 | #endif |
1703 | { | 1697 | { |
diff --git a/security/inode.c b/security/inode.c index 91503b79c5f8..0e37e4fba8fa 100644 --- a/security/inode.c +++ b/security/inode.c | |||
@@ -215,19 +215,17 @@ void securityfs_remove(struct dentry *dentry) | |||
215 | } | 215 | } |
216 | EXPORT_SYMBOL_GPL(securityfs_remove); | 216 | EXPORT_SYMBOL_GPL(securityfs_remove); |
217 | 217 | ||
218 | static struct kobject *security_kobj; | ||
219 | |||
220 | static int __init securityfs_init(void) | 218 | static int __init securityfs_init(void) |
221 | { | 219 | { |
222 | int retval; | 220 | int retval; |
223 | 221 | ||
224 | security_kobj = kobject_create_and_add("security", kernel_kobj); | 222 | retval = sysfs_create_mount_point(kernel_kobj, "security"); |
225 | if (!security_kobj) | 223 | if (retval) |
226 | return -EINVAL; | 224 | return retval; |
227 | 225 | ||
228 | retval = register_filesystem(&fs_type); | 226 | retval = register_filesystem(&fs_type); |
229 | if (retval) | 227 | if (retval) |
230 | kobject_put(security_kobj); | 228 | sysfs_remove_mount_point(kernel_kobj, "security"); |
231 | return retval; | 229 | return retval; |
232 | } | 230 | } |
233 | 231 | ||
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index d2787cca1fcb..3d2201413028 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -1853,7 +1853,6 @@ static struct file_system_type sel_fs_type = { | |||
1853 | }; | 1853 | }; |
1854 | 1854 | ||
1855 | struct vfsmount *selinuxfs_mount; | 1855 | struct vfsmount *selinuxfs_mount; |
1856 | static struct kobject *selinuxfs_kobj; | ||
1857 | 1856 | ||
1858 | static int __init init_sel_fs(void) | 1857 | static int __init init_sel_fs(void) |
1859 | { | 1858 | { |
@@ -1862,13 +1861,13 @@ static int __init init_sel_fs(void) | |||
1862 | if (!selinux_enabled) | 1861 | if (!selinux_enabled) |
1863 | return 0; | 1862 | return 0; |
1864 | 1863 | ||
1865 | selinuxfs_kobj = kobject_create_and_add("selinux", fs_kobj); | 1864 | err = sysfs_create_mount_point(fs_kobj, "selinux"); |
1866 | if (!selinuxfs_kobj) | 1865 | if (err) |
1867 | return -ENOMEM; | 1866 | return err; |
1868 | 1867 | ||
1869 | err = register_filesystem(&sel_fs_type); | 1868 | err = register_filesystem(&sel_fs_type); |
1870 | if (err) { | 1869 | if (err) { |
1871 | kobject_put(selinuxfs_kobj); | 1870 | sysfs_remove_mount_point(fs_kobj, "selinux"); |
1872 | return err; | 1871 | return err; |
1873 | } | 1872 | } |
1874 | 1873 | ||
@@ -1887,7 +1886,7 @@ __initcall(init_sel_fs); | |||
1887 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE | 1886 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE |
1888 | void exit_sel_fs(void) | 1887 | void exit_sel_fs(void) |
1889 | { | 1888 | { |
1890 | kobject_put(selinuxfs_kobj); | 1889 | sysfs_remove_mount_point(fs_kobj, "selinux"); |
1891 | kern_unmount(selinuxfs_mount); | 1890 | kern_unmount(selinuxfs_mount); |
1892 | unregister_filesystem(&sel_fs_type); | 1891 | unregister_filesystem(&sel_fs_type); |
1893 | } | 1892 | } |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 5e0a64ebdf23..2716d02119f3 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -2314,16 +2314,16 @@ static const struct file_operations smk_revoke_subj_ops = { | |||
2314 | .llseek = generic_file_llseek, | 2314 | .llseek = generic_file_llseek, |
2315 | }; | 2315 | }; |
2316 | 2316 | ||
2317 | static struct kset *smackfs_kset; | ||
2318 | /** | 2317 | /** |
2319 | * smk_init_sysfs - initialize /sys/fs/smackfs | 2318 | * smk_init_sysfs - initialize /sys/fs/smackfs |
2320 | * | 2319 | * |
2321 | */ | 2320 | */ |
2322 | static int smk_init_sysfs(void) | 2321 | static int smk_init_sysfs(void) |
2323 | { | 2322 | { |
2324 | smackfs_kset = kset_create_and_add("smackfs", NULL, fs_kobj); | 2323 | int err; |
2325 | if (!smackfs_kset) | 2324 | err = sysfs_create_mount_point(fs_kobj, "smackfs"); |
2326 | return -ENOMEM; | 2325 | if (err) |
2326 | return err; | ||
2327 | return 0; | 2327 | return 0; |
2328 | } | 2328 | } |
2329 | 2329 | ||