diff options
Diffstat (limited to 'include/linux')
-rw-r--r-- | include/linux/cgroup.h | 3 | ||||
-rw-r--r-- | include/linux/debugfs.h | 8 | ||||
-rw-r--r-- | include/linux/errno.h | 1 | ||||
-rw-r--r-- | include/linux/fs.h | 47 | ||||
-rw-r--r-- | include/linux/fs_context.h | 215 | ||||
-rw-r--r-- | include/linux/fs_parser.h | 119 | ||||
-rw-r--r-- | include/linux/fsinfo.h | 41 | ||||
-rw-r--r-- | include/linux/kernfs.h | 43 | ||||
-rw-r--r-- | include/linux/lsm_hooks.h | 84 | ||||
-rw-r--r-- | include/linux/module.h | 6 | ||||
-rw-r--r-- | include/linux/mount.h | 10 | ||||
-rw-r--r-- | include/linux/mtd/super.h | 4 | ||||
-rw-r--r-- | include/linux/ramfs.h | 4 | ||||
-rw-r--r-- | include/linux/security.h | 70 | ||||
-rw-r--r-- | include/linux/shmem_fs.h | 3 | ||||
-rw-r--r-- | include/linux/syscalls.h | 13 |
16 files changed, 598 insertions, 73 deletions
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 9d12757a65b0..bb0c7da50ed2 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -865,10 +865,11 @@ copy_cgroup_ns(unsigned long flags, struct user_namespace *user_ns, #endif /* !CONFIG_CGROUPS */ -static inline void get_cgroup_ns(struct cgroup_namespace *ns) +static inline struct cgroup_namespace *get_cgroup_ns(struct cgroup_namespace *ns) { if (ns) refcount_inc(&ns->count); + return ns; } static inline void put_cgroup_ns(struct cgroup_namespace *ns) diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index 3b0ba54cc4d5..a02de1b397ca 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -75,11 +75,11 @@ struct dentry *debugfs_create_dir(const char *name, struct dentry *parent); struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent, const char *dest); -typedef struct vfsmount *(*debugfs_automount_t)(struct dentry *, void *); +typedef struct vfsmount *(*debugfs_automount_t)(struct dentry *, void *, size_t); struct dentry *debugfs_create_automount(const char *name, struct dentry *parent, debugfs_automount_t f, - void *data); + void *data, size_t data_size); void debugfs_remove(struct dentry *dentry); void debugfs_remove_recursive(struct dentry *dentry); @@ -204,8 +204,8 @@ static inline struct dentry *debugfs_create_symlink(const char *name, static inline struct dentry *debugfs_create_automount(const char *name, struct dentry *parent, - struct vfsmount *(*f)(void *), - void *data) + struct vfsmount *(*f)(void *, size_t), + void *data, size_t data_size) { return ERR_PTR(-ENODEV); } diff --git a/include/linux/errno.h b/include/linux/errno.h index 3cba627577d6..d73f597a2484 100644 --- a/include/linux/errno.h +++ b/include/linux/errno.h @@ -18,6 +18,7 @@ #define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */ #define EPROBE_DEFER 517 /* Driver requests probe retry */ #define EOPENSTALE 518 /* open found a stale dentry */ +#define ENOPARAM 519 /* Parameter not supported */ /* Defined for the NFSv3 protocol */ #define EBADHANDLE 521 /* Illegal NFS file handle */ diff --git a/include/linux/fs.h b/include/linux/fs.h index fd41ec161e6e..62451269d951 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -62,6 +62,10 @@ struct workqueue_struct; struct iov_iter; struct fscrypt_info; struct fscrypt_operations; +struct fs_context; +struct fs_parameter_description; +struct fsinfo_kparams; +enum fsinfo_attribute; extern void __init inode_init(void); extern void __init inode_init_early(void); @@ -158,10 +162,13 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, #define FMODE_NONOTIFY ((__force fmode_t)0x4000000) /* File is capable of returning -EAGAIN if I/O will block */ -#define FMODE_NOWAIT ((__force fmode_t)0x8000000) +#define FMODE_NOWAIT ((__force fmode_t)0x8000000) + +/* File represents mount that needs unmounting */ +#define FMODE_NEED_UNMOUNT ((__force fmode_t)0x10000000) /* File does not contribute to nr_files count */ -#define FMODE_NOACCOUNT ((__force fmode_t)0x20000000) +#define FMODE_NOACCOUNT ((__force fmode_t)0x20000000) /* * Flag for rw_copy_check_uvector and compat_rw_copy_check_uvector @@ -1896,7 +1903,8 @@ struct super_operations { int (*thaw_super) (struct super_block *); int (*unfreeze_fs) (struct super_block *); int (*statfs) (struct dentry *, struct kstatfs *); - int (*remount_fs) (struct super_block *, int *, char *); + int (*fsinfo) (struct path *, struct fsinfo_kparams *); + int (*remount_fs) (struct super_block *, int *, char *, size_t); void (*umount_begin) (struct super_block *); int (*show_options)(struct seq_file *, struct dentry *); @@ -2157,8 +2165,10 @@ struct file_system_type { #define FS_HAS_SUBTYPE 4 #define FS_USERNS_MOUNT 8 /* Can be mounted by userns root */ #define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */ + int (*init_fs_context)(struct fs_context *, struct dentry *); + const struct fs_parameter_description *parameters; struct dentry *(*mount) (struct file_system_type *, int, - const char *, void *); + const char *, void *, size_t); void (*kill_sb) (struct super_block *); struct module *owner; struct file_system_type * next; @@ -2177,26 +2187,27 @@ struct file_system_type { #define MODULE_ALIAS_FS(NAME) MODULE_ALIAS("fs-" NAME) extern struct dentry *mount_ns(struct file_system_type *fs_type, - int flags, void *data, void *ns, struct user_namespace *user_ns, - int (*fill_super)(struct super_block *, void *, int)); + int flags, void *data, size_t data_size, + void *ns, struct user_namespace *user_ns, + int (*fill_super)(struct super_block *, void *, size_t, int)); #ifdef CONFIG_BLOCK extern struct dentry *mount_bdev(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, - int (*fill_super)(struct super_block *, void *, int)); + int flags, const char *dev_name, void *data, size_t data_size, + int (*fill_super)(struct super_block *, void *, size_t, int)); #else static inline struct dentry *mount_bdev(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, - int (*fill_super)(struct super_block *, void *, int)) + int flags, const char *dev_name, void *data, size_t data_size, + int (*fill_super)(struct super_block *, void *, size_t, int)) { return ERR_PTR(-ENODEV); } #endif extern struct dentry *mount_single(struct file_system_type *fs_type, - int flags, void *data, - int (*fill_super)(struct super_block *, void *, int)); + int flags, void *data, size_t data_size, + int (*fill_super)(struct super_block *, void *, size_t, int)); extern struct dentry *mount_nodev(struct file_system_type *fs_type, - int flags, void *data, - int (*fill_super)(struct super_block *, void *, int)); + int flags, void *data, size_t data_size, + int (*fill_super)(struct super_block *, void *, size_t, int)); extern struct dentry *mount_subtree(struct vfsmount *mnt, const char *path); void generic_shutdown_super(struct super_block *sb); #ifdef CONFIG_BLOCK @@ -2212,8 +2223,12 @@ void kill_litter_super(struct super_block *sb); void deactivate_super(struct super_block *sb); void deactivate_locked_super(struct super_block *sb); int set_anon_super(struct super_block *s, void *data); +int set_anon_super_fc(struct super_block *s, struct fs_context *fc); int get_anon_bdev(dev_t *); void free_anon_bdev(dev_t); +struct super_block *sget_fc(struct fs_context *fc, + int (*test)(struct super_block *, struct fs_context *), + int (*set)(struct super_block *, struct fs_context *)); struct super_block *sget_userns(struct file_system_type *type, int (*test)(struct super_block *,void *), int (*set)(struct super_block *,void *), @@ -2256,8 +2271,7 @@ mount_pseudo(struct file_system_type *fs_type, char *name, extern int register_filesystem(struct file_system_type *); extern int unregister_filesystem(struct file_system_type *); -extern struct vfsmount *kern_mount_data(struct file_system_type *, void *data); -#define kern_mount(type) kern_mount_data(type, NULL) +extern struct vfsmount *kern_mount(struct file_system_type *); extern void kern_unmount(struct vfsmount *mnt); extern int may_umount_tree(struct vfsmount *); extern int may_umount(struct vfsmount *); @@ -2270,6 +2284,7 @@ extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *, extern int vfs_statfs(const struct path *, struct kstatfs *); extern int user_statfs(const char __user *, struct kstatfs *); extern int fd_statfs(int, struct kstatfs *); +extern int vfs_fsinfo(struct path *, struct fsinfo_kparams *); extern int freeze_super(struct super_block *super); extern int thaw_super(struct super_block *super); extern bool our_mnt(struct vfsmount *mnt); diff --git a/include/linux/fs_context.h b/include/linux/fs_context.h new file mode 100644 index 000000000000..bb584db982ff --- /dev/null +++ b/include/linux/fs_context.h @@ -0,0 +1,215 @@ +/* Filesystem superblock creation and reconfiguration context. + * + * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#ifndef _LINUX_FS_CONTEXT_H +#define _LINUX_FS_CONTEXT_H + +#include <linux/kernel.h> +#include <linux/refcount.h> +#include <linux/errno.h> +#include <linux/mutex.h> + +struct cred; +struct dentry; +struct file_operations; +struct file_system_type; +struct mnt_namespace; +struct net; +struct pid_namespace; +struct super_block; +struct user_namespace; +struct vfsmount; +struct path; + +enum fs_context_purpose { + FS_CONTEXT_FOR_USER_MOUNT, /* New superblock for user-specified mount */ + FS_CONTEXT_FOR_KERNEL_MOUNT, /* New superblock for kernel-internal mount */ + FS_CONTEXT_FOR_SUBMOUNT, /* New superblock for automatic submount */ + FS_CONTEXT_FOR_ROOT_MOUNT, /* New superblock for internal root mount */ + FS_CONTEXT_FOR_RECONFIGURE, /* Superblock reconfiguration (remount) */ + FS_CONTEXT_FOR_UMOUNT, /* Reconfiguration to R/O for unmount */ + FS_CONTEXT_FOR_EMERGENCY_RO, /* Emergency reconfiguration to R/O */ +}; + +/* + * Userspace usage phase for fsopen/fspick. + */ +enum fs_context_phase { + FS_CONTEXT_CREATE_PARAMS, /* Loading params for sb creation */ + FS_CONTEXT_CREATING, /* A superblock is being created */ + FS_CONTEXT_AWAITING_MOUNT, /* Superblock created, awaiting fsmount() */ + FS_CONTEXT_AWAITING_RECONF, /* Awaiting initialisation for reconfiguration */ + FS_CONTEXT_RECONF_PARAMS, /* Loading params for reconfiguration */ + FS_CONTEXT_RECONFIGURING, /* Reconfiguring the superblock */ + FS_CONTEXT_FAILED, /* Failed to correctly transition a context */ +}; + +/* + * Type of parameter value. + */ +enum fs_value_type { + fs_value_is_undefined, + fs_value_is_flag, /* Value not given a value */ + fs_value_is_string, /* Value is a string */ + fs_value_is_blob, /* Value is a binary blob */ + fs_value_is_filename, /* Value is a filename* + dirfd */ + fs_value_is_filename_empty, /* Value is a filename* + dirfd + AT_EMPTY_PATH */ + fs_value_is_file, /* Value is a file* */ +}; + +/* + * Configuration parameter. + */ +struct fs_parameter { + const char *key; /* Parameter name */ + enum fs_value_type type:8; /* The type of value here */ + union { + char *string; + void *blob; + struct filename *name; + struct file *file; + }; + size_t size; + int dirfd; +}; + +/* + * Filesystem context for holding the parameters used in the creation or + * reconfiguration of a superblock. + * + * Superblock creation fills in ->root whereas reconfiguration begins with this + * already set. + * + * See Documentation/filesystems/mounting.txt + */ +struct fs_context { + const struct fs_context_operations *ops; + struct mutex uapi_mutex; /* Userspace access mutex */ + struct file_system_type *fs_type; + void *fs_private; /* The filesystem's context */ + struct dentry *root; /* The root and superblock */ + struct user_namespace *user_ns; /* The user namespace for this mount */ + struct net *net_ns; /* The network namespace for this mount */ + const struct cred *cred; /* The mounter's credentials */ + struct fc_log *log; /* Logging buffer */ + char *source; /* The source name (eg. dev path) */ + char *subtype; /* The subtype to set on the superblock */ + void *security; /* The LSM context */ + void *s_fs_info; /* Proposed s_fs_info */ + unsigned int sb_flags; /* Proposed superblock flags (SB_*) */ + unsigned int sb_flags_mask; /* Superblock flags that were changed */ + unsigned int lsm_flags; /* Information flags from the fs to the LSM */ + enum fs_context_purpose purpose:8; + enum fs_context_phase phase:8; /* The phase the context is in */ + bool sloppy:1; /* T if unrecognised options are okay */ + bool silent:1; /* T if "o silent" specified */ + bool need_free:1; /* Need to call ops->free() */ +}; + +struct fs_context_operations { + void (*free)(struct fs_context *fc); + int (*dup)(struct fs_context *fc, struct fs_context *src_fc); + int (*parse_param)(struct fs_context *fc, struct fs_parameter *param); + int (*parse_monolithic)(struct fs_context *fc, void *data, size_t data_size); + int (*validate)(struct fs_context *fc); + int (*get_tree)(struct fs_context *fc); + int (*reconfigure)(struct fs_context *fc); +}; + +/* + * fs_context manipulation functions. + */ +extern struct fs_context *vfs_new_fs_context(struct file_system_type *fs_type, + struct dentry *reference, + unsigned int sb_flags, + unsigned int sb_flags_mask, + enum fs_context_purpose purpose); +extern struct fs_context *vfs_dup_fs_context(struct fs_context *src, + enum fs_context_purpose purpose); +extern int vfs_parse_fs_param(struct fs_context *fc, struct fs_parameter *param); +extern int vfs_parse_fs_string(struct fs_context *fc, const char *key, + const char *value, size_t v_size); +extern int generic_parse_monolithic(struct fs_context *fc, void *data, size_t data_size); +extern int vfs_get_tree(struct fs_context *fc); +extern void put_fs_context(struct fs_context *fc); + +/* + * sget() wrapper to be called from the ->get_tree() op. + */ +enum vfs_get_super_keying { + vfs_get_single_super, /* Only one such superblock may exist */ + vfs_get_keyed_super, /* Superblocks with different s_fs_info keys may exist */ + vfs_get_independent_super, /* Multiple independent superblocks may exist */ +}; +extern int vfs_get_super(struct fs_context *fc, + enum vfs_get_super_keying keying, + int (*fill_super)(struct super_block *sb, + struct fs_context *fc)); + +extern const struct file_operations fscontext_fops; + +/* + * Mount error, warning and informational message logging. This structure is + * shareable between a mount and a subordinate mount. + */ +struct fc_log { + refcount_t usage; + u8 head; /* Insertion index in buffer[] */ + u8 tail; /* Removal index in buffer[] */ + u8 need_free; /* Mask of kfree'able items in buffer[] */ + struct module *owner; /* Owner module for strings that don't then need freeing */ + char *buffer[8]; +}; + +extern __attribute__((format(printf, 2, 3))) +void logfc(struct fs_context *fc, const char *fmt, ...); + +/** + * infof - Store supplementary informational message + * @fc: The context in which to log the informational message + * @fmt: The format string + * + * Store the supplementary informational message for the process if the process + * has enabled the facility. + */ +#define infof(fc, fmt, ...) ({ logfc(fc, "i "fmt, ## __VA_ARGS__); }) + +/** + * warnf - Store supplementary warning message + * @fc: The context in which to log the error message + * @fmt: The format string + * + * Store the supplementary warning message for the process if the process has + * enabled the facility. + */ +#define warnf(fc, fmt, ...) ({ logfc(fc, "w "fmt, ## __VA_ARGS__); }) + +/** + * errorf - Store supplementary error message + * @fc: The context in which to log the error message + * @fmt: The format string + * + * Store the supplementary error message for the process if the process has + * enabled the facility. + */ +#define errorf(fc, fmt, ...) ({ logfc(fc, "e "fmt, ## __VA_ARGS__); }) + +/** + * invalf - Store supplementary invalid argument error message + * @fc: The context in which to log the error message + * @fmt: The format string + * + * Store the supplementary error message for the process if the process has + * enabled the facility and return -EINVAL. + */ +#define invalf(fc, fmt, ...) ({ errorf(fc, fmt, ## __VA_ARGS__); -EINVAL; }) + +#endif /* _LINUX_FS_CONTEXT_H */ diff --git a/include/linux/fs_parser.h b/include/linux/fs_parser.h new file mode 100644 index 000000000000..e21792a6fc33 --- /dev/null +++ b/include/linux/fs_parser.h @@ -0,0 +1,119 @@ +/* Filesystem parameter description and parser + * + * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#ifndef _LINUX_FS_PARSER_H +#define _LINUX_FS_PARSER_H + +#include <linux/fs_context.h> + +struct path; + +struct constant_table { + const char *name; + int value; +}; + +#define fsconfig_key_removed 0xff /* Parameter name is no longer valid */ + +/* + * The type of parameter expected. + */ +enum fs_parameter_type { + __fs_param_wasnt_defined, + fs_param_is_flag, + fs_param_is_bool, + fs_param_is_u32, + fs_param_is_u32_octal, + fs_param_is_u32_hex, + fs_param_is_s32, + fs_param_is_u64, + fs_param_is_enum, + fs_param_is_string, + fs_param_is_blob, + fs_param_is_blockdev, + fs_param_is_path, + fs_param_is_fd, + nr__fs_parameter_type, +}; + +/* + * Specification of the type of value a parameter wants. + */ +struct fs_parameter_spec { + enum fs_parameter_type type:8; /* The desired parameter type */ + u8 flags; +#define fs_param_v_optional 0x01 /* The value is optional */ +#define fs_param_neg_with_no 0x02 /* "noxxx" is negative param */ +#define fs_param_neg_with_empty 0x04 /* "xxx=" is negative param */ +#define fs_param_deprecated 0x08 /* The param is deprecated */ +}; + +struct fs_parameter_enum { + u8 param_id; + char name[14]; + u8 value; +}; + +struct fs_parameter_description { + const char name[16]; /* Name for logging purposes */ + u8 nr_params; /* Number of parameter IDs */ + u8 nr_alt_keys; /* Number of alt_keys[] */ + u8 nr_enums; /* Number of enum value names */ + u8 source_param; /* Index of source parameter */ + bool no_source; /* Set if no source is expected */ + const char *const *keys; /* Sorted list of key names, one per nr_params */ + const struct constant_table *alt_keys; /* Sorted list of alternate key names */ + const struct fs_parameter_spec *specs; /* List of param specifications */ + const struct fs_parameter_enum *enums; /* Enum values */ +}; + +/* + * Result of parse. + */ +struct fs_parse_result { + struct fs_parameter_spec t; + u8 key; /* Looked up key ID */ + bool negated; /* T if param was "noxxx" */ + bool has_value; /* T if value supplied to param */ + union { + bool boolean; /* For spec_bool */ + int int_32; /* For spec_s32/spec_enum */ + unsigned int uint_32; /* For spec_u32{,_octal,_hex}/spec_enum */ + u64 uint_64; /* For spec_u64 */ + }; +}; + +extern int fs_parse(struct fs_context *fc, + const struct fs_parameter_description *desc, + struct fs_parameter *value, + struct fs_parse_result *result); +extern int fs_lookup_param(struct fs_context *fc, + struct fs_parameter *param, + bool want_bdev, + struct path *_path); + +extern int __lookup_constant(const struct constant_table tbl[], size_t tbl_size, + const char *name, int not_found); +#define lookup_constant(t, n, nf) __lookup_constant(t, ARRAY_SIZE(t), (n), (nf)) + +#ifdef CONFIG_VALIDATE_FS_PARSER +extern bool validate_constant_table(const struct constant_table *tbl, size_t tbl_size, + int low, int high, int special); +extern bool fs_validate_description(const struct fs_parameter_description *desc); +#else +static inline bool validate_constant_table(const struct constant_table *tbl, size_t tbl_size, + int low, int high, int special) +{ return true; } +static inline bool fs_validate_description(const struct fs_parameter_description *desc) +{ return true; } +#endif + +#endif /* _LINUX_FS_PARSER_H */ diff --git a/include/linux/fsinfo.h b/include/linux/fsinfo.h new file mode 100644 index 000000000000..e488701c5c04 --- /dev/null +++ b/include/linux/fsinfo.h @@ -0,0 +1,41 @@ +/* Filesystem information query + * + * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#ifndef _LINUX_FSINFO_H +#define _LINUX_FSINFO_H + +#include <uapi/linux/fsinfo.h> + +struct fsinfo_kparams { + __u32 at_flags; /* AT_SYMLINK_NOFOLLOW and similar */ + enum fsinfo_attribute request; /* What is being asking for */ + __u32 Nth; /* Instance of it (some may have multiple) */ + __u32 Mth; /* Subinstance */ + bool string_val; /* T if variable-length string value */ + void *buffer; /* Where to place the reply */ + size_t buf_size; /* Size of the buffer */ +}; + +extern int generic_fsinfo(struct path *, struct fsinfo_kparams *); + +static inline void fsinfo_set_cap(struct fsinfo_capabilities *c, + enum fsinfo_capability cap) +{ + c->capabilities[cap / 8] |= 1 << (cap % 8); +} + +static inline void fsinfo_clear_cap(struct fsinfo_capabilities *c, + enum fsinfo_capability cap) +{ + c->capabilities[cap / 8] &= ~(1 << (cap % 8)); +} + +#endif /* _LINUX_FSINFO_H */ diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 5b36b1287a5a..625c19ce86bb 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -17,6 +17,7 @@ #include <linux/atomic.h> #include <linux/uidgid.h> #include <linux/wait.h> +#include <linux/fs_context.h> struct file; struct dentry; @@ -25,7 +26,10 @@ struct seq_file; struct vm_area_struct; struct super_block; struct file_system_type; +struct fs_context; +struct fsinfo_kparams; +struct kernfs_fs_context; struct kernfs_open_node; struct kernfs_iattrs; @@ -167,8 +171,9 @@ struct kernfs_node { * kernfs_node parameter. */ struct kernfs_syscall_ops { - int (*remount_fs)(struct kernfs_root *root, int *flags, char *data); + int (*reconfigure)(struct kernfs_root *root, struct fs_context *fc); int (*show_options)(struct seq_file *sf, struct kernfs_root *root); + int (*fsinfo)(struct kernfs_root *root, struct fsinfo_kparams *params); int (*mkdir)(struct kernfs_node *parent, const char *name, umode_t mode); @@ -268,6 +273,18 @@ struct kernfs_ops { #endif }; +/* + * The kernfs superblock creation/mount parameter context. + */ +struct kernfs_fs_context { + struct kernfs_root *root; /* Root of the hierarchy being mounted */ + void *ns_tag; /* Namespace tag of the mount (or NULL) */ + unsigned long magic; /* File system specific magic number */ + + /* The following are set/used by kernfs_mount() */ + bool new_sb_created; /* Set to T if we allocated a new sb */ +}; + #ifdef CONFIG_KERNFS static inline enum kernfs_node_type kernfs_type(struct kernfs_node *kn) @@ -353,11 +370,11 @@ int kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr); void kernfs_notify(struct kernfs_node *kn); const void *kernfs_super_ns(struct super_block *sb); -struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, - struct kernfs_root *root, unsigned long magic, - bool *new_sb_created, const void *ns); +int kernfs_get_tree(struct fs_context *fc); +void kernfs_free_fs_context(struct fs_context *fc); void kernfs_kill_sb(struct super_block *sb); struct super_block *kernfs_pin_sb(struct kernfs_root *root, const void *ns); +int kernfs_reconfigure(struct fs_context *fc); void kernfs_init(void); @@ -459,11 +476,10 @@ static inline void kernfs_notify(struct kernfs_node *kn) { } static inline const void *kernfs_super_ns(struct super_block *sb) { return NULL; } -static inline struct dentry * -kernfs_mount_ns(struct file_system_type *fs_type, int flags, - struct kernfs_root *root, unsigned long magic, - bool *new_sb_created, const void *ns) -{ return ERR_PTR(-ENOSYS); } +static inline int kernfs_get_tree(struct fs_context *fc) +{ return -ENOSYS; } + +static inline void kernfs_free_fs_context(struct fs_context *fc) { } static inline void kernfs_kill_sb(struct super_block *sb) { } @@ -546,13 +562,4 @@ static inline int kernfs_rename(struct kernfs_node *kn, return kernfs_rename_ns(kn, new_parent, new_name, NULL); } -static inline struct dentry * -kernfs_mount(struct file_system_type *fs_type, int flags, - struct kernfs_root *root, unsigned long magic, - bool *new_sb_created) -{ - return kernfs_mount_ns(fs_type, flags, root, - magic, new_sb_created, NULL); -} - #endif /* __LINUX_KERNFS_H */ diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index aaeb7fa24dc4..e99495acb037 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -76,6 +76,49 @@ * changes on the process such as clearing out non-inheritable signal * state. This is called immediately after commit_creds(). * + * Security hooks for mount using fs_context. + * [See also Documentation/filesystems/mounting.txt] + * + * @fs_context_alloc: + * Allocate and attach a security structure to sc->security. This pointer + * is initialised to NULL by the caller. + * @fc indicates the new filesystem context. + * @reference indicates the source dentry of a submount or start of reconfig. + * @fs_context_dup: + * Allocate and attach a security structure to sc->security. This pointer + * is initialised to NULL by the caller. + * @fc indicates the new filesystem context. + * @src_fc indicates the original filesystem context. + * @fs_context_free: + * Clean up a filesystem context. + * @fc indicates the filesystem context. + * @fs_context_parse_param: + * Userspace provided a parameter to configure a superblock. The LSM may + * reject it with an error and may use it for itself, in which case it + * should return 0; otherwise it should return -ENOPARAM to pass it on to + * the filesystem. + * @fc indicates the filesystem context. + * @param The parameter + * @fs_context_validate: + * Validate the filesystem context preparatory to applying it. This is + * done after all the options have been parsed. + * @fc indicates the filesystem context. + * @sb_get_tree: + * Assign the security to a newly created superblock. + * @fc indicates the filesystem context. + * @fc->root indicates the root that will be mounted. + * @fc->root->d_sb points to the superblock. + * @sb_reconfigure: + * Apply reconfiguration to the security on a superblock. + * @fc indicates the filesystem context. + * @fc->root indicates a dentry in the mount. + * @fc->root->d_sb points to the superblock. + * @sb_mountpoint: + * Equivalent of sb_mount, but with an fs_context. + * @fc indicates the filesystem context. + * @mountpoint indicates the path on which the mount will take place. + * @mnt_flags indicates the MNT_* flags specified. + * * Security hooks for filesystem operations. * * @sb_alloc_security: @@ -104,6 +147,7 @@ * @type contains the filesystem type. * @flags contains the mount flags. * @data contains the filesystem-specific data. + * @data_size contains the size of the data. * Return 0 if permission is granted. * @sb_copy_data: * Allow mount option data to be copied prior to parsing by the filesystem, @@ -113,14 +157,9 @@ * specific options to avoid having to make filesystems aware of them. * @type the type of filesystem being mounted. * @orig the original mount data copied from userspace. + * @orig_data is the size of the original data * @copy copied data which will be passed to the security module. * Returns 0 if the copy was successful. - * @sb_remount: - * Extracts security system specific mount options and verifies no changes - * are being made to those options. - * @sb superblock being remounted - * @data contains the filesystem-specific data. - * Return 0 if permission is granted. * @sb_umount: * Check permission before the @mnt file system is unmounted. * @mnt contains the mounted file system. @@ -144,6 +183,10 @@ * Parse a string of security data filling in the opts structure * @options string containing all mount options known by the LSM * @opts binary data structure usable by the LSM + * @move_mount: + * Check permission before a mount is moved. + * @from_path indicates the mount that is going to be moved. + * @to_path indicates the mountpoint that will be mounted upon. * @dentry_init_security: * Compute a context for a dentry as the inode is not yet available * since NFSv4 has no label backed by an EA anyway. @@ -1459,15 +1502,24 @@ union security_list_options { void (*bprm_committing_creds)(struct linux_binprm *bprm); void (*bprm_committed_creds)(struct linux_binprm *bprm); + int (*fs_context_alloc)(struct fs_context *fc, struct dentry *reference); + int (*fs_context_dup)(struct fs_context *fc, struct fs_context *src_sc); + void (*fs_context_free)(struct fs_context *fc); + int (*fs_context_parse_param)(struct fs_context *fc, struct fs_parameter *param); + int (*fs_context_validate)(struct fs_context *fc); + int (*sb_get_tree)(struct fs_context *fc); + void (*sb_reconfigure)(struct fs_context *fc); + int (*sb_mountpoint)(struct fs_context *fc, struct path *mountpoint, + unsigned int mnt_flags); + int (*sb_alloc_security)(struct super_block *sb); void (*sb_free_security)(struct super_block *sb); - int (*sb_copy_data)(char *orig, char *copy); - int (*sb_remount)(struct super_block *sb, void *data); - int (*sb_kern_mount)(struct super_block *sb, int flags, void *data); + int (*sb_copy_data)(char *orig, size_t orig_size, char *copy); int (*sb_show_options)(struct seq_file *m, struct super_block *sb); int (*sb_statfs)(struct dentry *dentry); int (*sb_mount)(const char *dev_name, const struct path *path, - const char *type, unsigned long flags, void *data); + const char *type, unsigned long flags, + void *data, size_t data_size); int (*sb_umount)(struct vfsmount *mnt, int flags); int (*sb_pivotroot)(const struct path *old_path, const struct path *new_path); int (*sb_set_mnt_opts)(struct super_block *sb, @@ -1479,6 +1531,7 @@ union security_list_options { unsigned long kern_flags, unsigned long *set_kern_flags); int (*sb_parse_opts_str)(char *options, struct security_mnt_opts *opts); + int (*move_mount)(const struct path *from_path, const struct path *to_path); int (*dentry_init_security)(struct dentry *dentry, int mode, const struct qstr *name, void **ctx, u32 *ctxlen); @@ -1798,11 +1851,17 @@ struct security_hook_heads { struct hlist_head bprm_check_security; struct hlist_head bprm_committing_creds; struct hlist_head bprm_committed_creds; + struct hlist_head fs_context_alloc; + struct hlist_head fs_context_dup; + struct hlist_head fs_context_free; + struct hlist_head fs_context_parse_param; + struct hlist_head fs_context_validate; + struct hlist_head sb_get_tree; + struct hlist_head sb_reconfigure; + struct hlist_head sb_mountpoint; struct hlist_head sb_alloc_security; struct hlist_head sb_free_security; struct hlist_head sb_copy_data; - struct hlist_head sb_remount; - struct hlist_head sb_kern_mount; struct hlist_head sb_show_options; struct hlist_head sb_statfs; struct hlist_head sb_mount; @@ -1811,6 +1870,7 @@ struct security_hook_heads { struct hlist_head sb_set_mnt_opts; struct hlist_head sb_clone_mnt_opts; struct hlist_head sb_parse_opts_str; + struct hlist_head move_mount; struct hlist_head dentry_init_security; struct hlist_head dentry_create_files_as; #ifdef CONFIG_SECURITY_PATH diff --git a/include/linux/module.h b/include/linux/module.h index fce6b4335e36..b9b4394ee0c7 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -682,6 +682,12 @@ static inline bool is_module_text_address(unsigned long addr) return false; } +static inline bool within_module_core(unsigned long addr, + const struct module *mod) +{ + return false; +} + /* Get/put a kernel symbol (calls should be symmetric) */ #define symbol_get(x) ({ extern typeof(x) x __attribute__((weak)); &(x); }) #define symbol_put(x) do { } while (0) diff --git a/include/linux/mount.h b/include/linux/mount.h index 45b1f56c6c2f..41b6b080ffd0 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -21,6 +21,7 @@ struct super_block; struct vfsmount; struct dentry; struct mnt_namespace; +struct fs_context; #define MNT_NOSUID 0x01 #define MNT_NODEV 0x02 @@ -81,19 +82,22 @@ extern void mnt_drop_write_file(struct file *file); extern void mntput(struct vfsmount *mnt); extern struct vfsmount *mntget(struct vfsmount *mnt); extern struct vfsmount *mnt_clone_internal(const struct path *path); -extern int __mnt_is_readonly(struct vfsmount *mnt); +extern bool __mnt_is_readonly(struct vfsmount *mnt); extern bool mnt_may_suid(struct vfsmount *mnt); struct path; extern struct vfsmount *clone_private_mount(const struct path *path); struct file_system_type; +extern struct vfsmount *vfs_create_mount(struct fs_context *fc, + unsigned int mnt_flags); extern struct vfsmount *vfs_kern_mount(struct file_system_type *type, int flags, const char *name, - void *data); + void *data, size_t data_size); extern struct vfsmount *vfs_submount(const struct dentry *mountpoint, struct file_system_type *type, - const char *name, void *data); + const char *name, + void *data, size_t data_size); extern void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list); extern void mark_mounts_for_expiry(struct list_head *mounts); diff --git a/include/linux/mtd/super.h b/include/linux/mtd/super.h index f456230f9330..3f37c7cd711c 100644 --- a/include/linux/mtd/super.h +++ b/include/linux/mtd/super.h @@ -19,8 +19,8 @@ #include <linux/mount.h> extern struct dentry *mount_mtd(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, - int (*fill_super)(struct super_block *, void *, int)); + const char *dev_name, void *data, size_t data_size, + int (*fill_super)(struct super_block *, void *, size_t, int)); extern void kill_mtd_super(struct super_block *sb); diff --git a/include/linux/ramfs.h b/include/linux/ramfs.h index 5ef7d54caac2..6d64e6be9928 100644 --- a/include/linux/ramfs.h +++ b/include/linux/ramfs.h @@ -5,7 +5,7 @@ struct inode *ramfs_get_inode(struct super_block *sb, const struct inode *dir, umode_t mode, dev_t dev); extern struct dentry *ramfs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data); + int flags, const char *dev_name, void *data, size_t data_size); #ifdef CONFIG_MMU static inline int @@ -21,6 +21,6 @@ extern const struct file_operations ramfs_file_operations; extern const struct vm_operations_struct generic_file_vm_ops; extern int __init init_ramfs_fs(void); -int ramfs_fill_super(struct super_block *sb, void *data, int silent); +int ramfs_fill_super(struct super_block *sb, void *data, size_t data_size, int silent); #endif diff --git a/include/linux/security.h b/include/linux/security.h index d170a5b031f3..ac0ef467d25e 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -53,12 +53,15 @@ struct msg_msg; struct xattr; struct xfrm_sec_ctx; struct mm_struct; +struct fs_context; +struct fs_parameter; +enum fs_value_type; /* If capable should audit the security request */ #define SECURITY_CAP_NOAUDIT 0 #define SECURITY_CAP_AUDIT 1 -/* LSM Agnostic defines for sb_set_mnt_opts */ +/* LSM Agnostic defines for fs_context::lsm_flags */ #define SECURITY_LSM_NATIVE_LABELS 1 struct ctl_table; @@ -246,15 +249,22 @@ int security_bprm_set_creds(struct linux_binprm *bprm); int security_bprm_check(struct linux_binprm *bprm); void security_bprm_committing_creds(struct linux_binprm *bprm); void security_bprm_committed_creds(struct linux_binprm *bprm); +int security_fs_context_alloc(struct fs_context *fc, struct dentry *reference); +int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc); +void security_fs_context_free(struct fs_context *fc); +int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param); +int security_fs_context_validate(struct fs_context *fc); +int security_sb_get_tree(struct fs_context *fc); +void security_sb_reconfigure(struct fs_context *fc); +int security_sb_mountpoint(struct fs_context *fc, struct path *mountpoint, + unsigned int mnt_flags); int security_sb_alloc(struct super_block *sb); void security_sb_free(struct super_block *sb); -int security_sb_copy_data(char *orig, char *copy); -int security_sb_remount(struct super_block *sb, void *data); -int security_sb_kern_mount(struct super_block *sb, int flags, void *data); +int security_sb_copy_data(char *orig, size_t orig_size, char *copy); int security_sb_show_options(struct seq_file *m, struct super_block *sb); int security_sb_statfs(struct dentry *dentry); int security_sb_mount(const char *dev_name, const struct path *path, - const char *type, unsigned long flags, void *data); + const char *type, unsigned long flags, void *data, size_t data_size); int security_sb_umount(struct vfsmount *mnt, int flags); int security_sb_pivotroot(const struct path *old_path, const struct path *new_path); int security_sb_set_mnt_opts(struct super_block *sb, @@ -266,6 +276,7 @@ int security_sb_clone_mnt_opts(const struct super_block *oldsb, unsigned long kern_flags, unsigned long *set_kern_flags); int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts); +int security_move_mount(const struct path *from_path, const struct path *to_path); int security_dentry_init_security(struct dentry *dentry, int mode, const struct qstr *name, void **ctx, u32 *ctxlen); @@ -547,25 +558,50 @@ static inline void security_bprm_committed_creds(struct linux_binprm *bprm) { } -static inline int security_sb_alloc(struct super_block *sb) +static inline int security_fs_context_alloc(struct fs_context *fc, + struct dentry *reference) { return 0; } - -static inline void security_sb_free(struct super_block *sb) -{ } - -static inline int security_sb_copy_data(char *orig, char *copy) +static inline int security_fs_context_dup(struct fs_context *fc, + struct fs_context *src_fc) +{ + return 0; +} +static inline void security_fs_context_free(struct fs_context *fc) +{ +} +static inline int security_fs_context_parse_param(struct fs_context *fc, + struct fs_parameter *param) +{ + return -ENOPARAM; +} +static inline int security_fs_context_validate(struct fs_context *fc) +{ + return 0; +} +static inline int security_sb_get_tree(struct fs_context *fc) +{ + return 0; +} +static inline void security_sb_reconfigure(struct fs_context *fc) +{ +} +static inline int security_sb_mountpoint(struct fs_context *fc, struct path *mountpoint, + unsigned int mnt_flags) { return 0; } -static inline int security_sb_remount(struct super_block *sb, void *data) +static inline int security_sb_alloc(struct super_block *sb) { return 0; } -static inline int security_sb_kern_mount(struct super_block *sb, int flags, void *data) +static inline void security_sb_free(struct super_block *sb) +{ } + +static inline int security_sb_copy_data(char *orig, size_t orig_size, char *copy) { return 0; } @@ -583,7 +619,7 @@ static inline int security_sb_statfs(struct dentry *dentry) static inline int security_sb_mount(const char *dev_name, const struct path *path, const char *type, unsigned long flags, - void *data) + void *data, size_t data_size) { return 0; } @@ -620,6 +656,12 @@ static inline int security_sb_parse_opts_str(char *options, struct security_mnt_ return 0; } +static inline int security_move_mount(const struct path *from_path, + const struct path *to_path) +{ + return 0; +} + static inline int security_inode_alloc(struct inode *inode) { return 0; diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h index f155dc607112..66772728cb74 100644 --- a/include/linux/shmem_fs.h +++ b/include/linux/shmem_fs.h @@ -49,7 +49,8 @@ static inline struct shmem_inode_info *SHMEM_I(struct inode *inode) * Functions in mm/shmem.c called directly from elsewhere: */ extern int shmem_init(void); -extern int shmem_fill_super(struct super_block *sb, void *data, int silent); +extern int shmem_fill_super(struct super_block *sb, void *data, size_t data_size, + int silent); extern struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags); extern struct file *shmem_kernel_file_setup(const char *name, loff_t size, diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 2ac3d13a915b..82682b69435e 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -50,6 +50,7 @@ struct stat64; struct statfs; struct statfs64; struct statx; +struct fsinfo_params; struct __sysctl_args; struct sysinfo; struct timespec; @@ -907,6 +908,18 @@ asmlinkage long sys_statx(int dfd, const char __user *path, unsigned flags, unsigned mask, struct statx __user *buffer); asmlinkage long sys_rseq(struct rseq __user *rseq, uint32_t rseq_len, int flags, uint32_t sig); +asmlinkage long sys_open_tree(int dfd, const char __user *path, unsigned flags); +asmlinkage long sys_move_mount(int from_dfd, const char __user *from_path, + int to_dfd, const char __user *to_path, + unsigned int ms_flags); +asmlinkage long sys_fsopen(const char __user *fs_name, unsigned int flags); +asmlinkage long sys_fsconfig(int fs_fd, unsigned int cmd, const char __user *key, + const void __user *value, int aux); +asmlinkage long sys_fsmount(int fs_fd, unsigned int flags, unsigned int ms_flags); +asmlinkage long sys_fspick(int dfd, const char __user *path, unsigned int flags); +asmlinkage long sys_fsinfo(int dfd, const char __user *path, + struct fsinfo_params __user *params, + void __user *buffer, size_t buf_size); /* * Architecture-specific system calls |