diff options
Diffstat (limited to 'include/linux/fs.h')
| -rw-r--r-- | include/linux/fs.h | 190 | 
1 files changed, 145 insertions, 45 deletions
diff --git a/include/linux/fs.h b/include/linux/fs.h index 43ba79ddbd68..ec8f3ddf4a6a 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -39,6 +39,8 @@  #include <linux/fs_types.h>  #include <linux/build_bug.h>  #include <linux/stddef.h> +#include <linux/mount.h> +#include <linux/cred.h>  #include <asm/byteorder.h>  #include <uapi/linux/fs.h> @@ -1572,6 +1574,52 @@ static inline void i_gid_write(struct inode *inode, gid_t gid)  	inode->i_gid = make_kgid(inode->i_sb->s_user_ns, gid);  } +static inline kuid_t kuid_into_mnt(struct user_namespace *mnt_userns, +				   kuid_t kuid) +{ +	return make_kuid(mnt_userns, __kuid_val(kuid)); +} + +static inline kgid_t kgid_into_mnt(struct user_namespace *mnt_userns, +				   kgid_t kgid) +{ +	return make_kgid(mnt_userns, __kgid_val(kgid)); +} + +static inline kuid_t i_uid_into_mnt(struct user_namespace *mnt_userns, +				    const struct inode *inode) +{ +	return kuid_into_mnt(mnt_userns, inode->i_uid); +} + +static inline kgid_t i_gid_into_mnt(struct user_namespace *mnt_userns, +				    const struct inode *inode) +{ +	return kgid_into_mnt(mnt_userns, inode->i_gid); +} + +static inline kuid_t kuid_from_mnt(struct user_namespace *mnt_userns, +				   kuid_t kuid) +{ +	return KUIDT_INIT(from_kuid(mnt_userns, kuid)); +} + +static inline kgid_t kgid_from_mnt(struct user_namespace *mnt_userns, +				   kgid_t kgid) +{ +	return KGIDT_INIT(from_kgid(mnt_userns, kgid)); +} + +static inline kuid_t fsuid_into_mnt(struct user_namespace *mnt_userns) +{ +	return kuid_from_mnt(mnt_userns, current_fsuid()); +} + +static inline kgid_t fsgid_into_mnt(struct user_namespace *mnt_userns) +{ +	return kgid_from_mnt(mnt_userns, current_fsgid()); +} +  extern struct timespec64 current_time(struct inode *inode);  /* @@ -1714,28 +1762,48 @@ static inline bool sb_start_intwrite_trylock(struct super_block *sb)  	return __sb_start_write_trylock(sb, SB_FREEZE_FS);  } - -extern bool inode_owner_or_capable(const struct inode *inode); +bool inode_owner_or_capable(struct user_namespace *mnt_userns, +			    const struct inode *inode);  /*   * VFS helper functions..   */ -extern int vfs_create(struct inode *, struct dentry *, umode_t, bool); -extern int vfs_mkdir(struct inode *, struct dentry *, umode_t); -extern int vfs_mknod(struct inode *, struct dentry *, umode_t, dev_t); -extern int vfs_symlink(struct inode *, struct dentry *, const char *); -extern int vfs_link(struct dentry *, struct inode *, struct dentry *, struct inode **); -extern int vfs_rmdir(struct inode *, struct dentry *); -extern int vfs_unlink(struct inode *, struct dentry *, struct inode **); -extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *, struct inode **, unsigned int); +int vfs_create(struct user_namespace *, struct inode *, +	       struct dentry *, umode_t, bool); +int vfs_mkdir(struct user_namespace *, struct inode *, +	      struct dentry *, umode_t); +int vfs_mknod(struct user_namespace *, struct inode *, struct dentry *, +              umode_t, dev_t); +int vfs_symlink(struct user_namespace *, struct inode *, +		struct dentry *, const char *); +int vfs_link(struct dentry *, struct user_namespace *, struct inode *, +	     struct dentry *, struct inode **); +int vfs_rmdir(struct user_namespace *, struct inode *, struct dentry *); +int vfs_unlink(struct user_namespace *, struct inode *, struct dentry *, +	       struct inode **); + +struct renamedata { +	struct user_namespace *old_mnt_userns; +	struct inode *old_dir; +	struct dentry *old_dentry; +	struct user_namespace *new_mnt_userns; +	struct inode *new_dir; +	struct dentry *new_dentry; +	struct inode **delegated_inode; +	unsigned int flags; +} __randomize_layout; -static inline int vfs_whiteout(struct inode *dir, struct dentry *dentry) +int vfs_rename(struct renamedata *); + +static inline int vfs_whiteout(struct user_namespace *mnt_userns, +			       struct inode *dir, struct dentry *dentry)  { -	return vfs_mknod(dir, dentry, S_IFCHR | WHITEOUT_MODE, WHITEOUT_DEV); +	return vfs_mknod(mnt_userns, dir, dentry, S_IFCHR | WHITEOUT_MODE, +			 WHITEOUT_DEV);  } -extern struct dentry *vfs_tmpfile(struct dentry *dentry, umode_t mode, -				  int open_flag); +struct dentry *vfs_tmpfile(struct user_namespace *mnt_userns, +			   struct dentry *dentry, umode_t mode, int open_flag);  int vfs_mkobj(struct dentry *, umode_t,  		int (*f)(struct dentry *, umode_t, void *), @@ -1757,8 +1825,8 @@ extern long compat_ptr_ioctl(struct file *file, unsigned int cmd,  /*   * VFS file helper functions.   */ -extern void inode_init_owner(struct inode *inode, const struct inode *dir, -			umode_t mode); +void inode_init_owner(struct user_namespace *mnt_userns, struct inode *inode, +		      const struct inode *dir, umode_t mode);  extern bool may_open_dev(const struct path *path);  /* @@ -1862,22 +1930,28 @@ struct file_operations {  struct inode_operations {  	struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);  	const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *); -	int (*permission) (struct inode *, int); +	int (*permission) (struct user_namespace *, struct inode *, int);  	struct posix_acl * (*get_acl)(struct inode *, int);  	int (*readlink) (struct dentry *, char __user *,int); -	int (*create) (struct inode *,struct dentry *, umode_t, bool); +	int (*create) (struct user_namespace *, struct inode *,struct dentry *, +		       umode_t, bool);  	int (*link) (struct dentry *,struct inode *,struct dentry *);  	int (*unlink) (struct inode *,struct dentry *); -	int (*symlink) (struct inode *,struct dentry *,const char *); -	int (*mkdir) (struct inode *,struct dentry *,umode_t); +	int (*symlink) (struct user_namespace *, struct inode *,struct dentry *, +			const char *); +	int (*mkdir) (struct user_namespace *, struct inode *,struct dentry *, +		      umode_t);  	int (*rmdir) (struct inode *,struct dentry *); -	int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t); -	int (*rename) (struct inode *, struct dentry *, +	int (*mknod) (struct user_namespace *, struct inode *,struct dentry *, +		      umode_t,dev_t); +	int (*rename) (struct user_namespace *, struct inode *, struct dentry *,  			struct inode *, struct dentry *, unsigned int); -	int (*setattr) (struct dentry *, struct iattr *); -	int (*getattr) (const struct path *, struct kstat *, u32, unsigned int); +	int (*setattr) (struct user_namespace *, struct dentry *, +			struct iattr *); +	int (*getattr) (struct user_namespace *, const struct path *, +			struct kstat *, u32, unsigned int);  	ssize_t (*listxattr) (struct dentry *, char *, size_t);  	int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,  		      u64 len); @@ -1885,8 +1959,10 @@ struct inode_operations {  	int (*atomic_open)(struct inode *, struct dentry *,  			   struct file *, unsigned open_flag,  			   umode_t create_mode); -	int (*tmpfile) (struct inode *, struct dentry *, umode_t); -	int (*set_acl)(struct inode *, struct posix_acl *, int); +	int (*tmpfile) (struct user_namespace *, struct inode *, +			struct dentry *, umode_t); +	int (*set_acl)(struct user_namespace *, struct inode *, +		       struct posix_acl *, int);  } ____cacheline_aligned;  static inline ssize_t call_read_iter(struct file *file, struct kiocb *kio, @@ -2035,9 +2111,11 @@ static inline bool sb_rdonly(const struct super_block *sb) { return sb->s_flags  #define IS_WHITEOUT(inode)	(S_ISCHR(inode->i_mode) && \  				 (inode)->i_rdev == WHITEOUT_DEV) -static inline bool HAS_UNMAPPED_ID(struct inode *inode) +static inline bool HAS_UNMAPPED_ID(struct user_namespace *mnt_userns, +				   struct inode *inode)  { -	return !uid_valid(inode->i_uid) || !gid_valid(inode->i_gid); +	return !uid_valid(i_uid_into_mnt(mnt_userns, inode)) || +	       !gid_valid(i_gid_into_mnt(mnt_userns, inode));  }  static inline enum rw_hint file_write_hint(struct file *file) @@ -2254,6 +2332,7 @@ struct file_system_type {  #define FS_HAS_SUBTYPE		4  #define FS_USERNS_MOUNT		8	/* Can be mounted by userns root */  #define FS_DISALLOW_NOTIFY_PERM	16	/* Disable fanotify permission events */ +#define FS_ALLOW_IDMAP         32      /* FS has been updated to handle vfs idmappings. */  #define FS_THP_SUPPORT		8192	/* Remove once all fs converted */  #define FS_RENAME_DOES_D_MOVE	32768	/* FS will handle d_move() during rename() internally. */  	int (*init_fs_context)(struct fs_context *); @@ -2540,9 +2619,13 @@ struct filename {  };  static_assert(offsetof(struct filename, iname) % sizeof(long) == 0); +static inline struct user_namespace *file_mnt_user_ns(struct file *file) +{ +	return mnt_user_ns(file->f_path.mnt); +}  extern long vfs_truncate(const struct path *, loff_t); -extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs, -		       struct file *filp); +int do_truncate(struct user_namespace *, struct dentry *, loff_t start, +		unsigned int time_attrs, struct file *filp);  extern int vfs_fallocate(struct file *file, int mode, loff_t offset,  			loff_t len);  extern long do_sys_open(int dfd, const char __user *filename, int flags, @@ -2779,10 +2862,22 @@ static inline int bmap(struct inode *inode,  sector_t *block)  }  #endif -extern int notify_change(struct dentry *, struct iattr *, struct inode **); -extern int inode_permission(struct inode *, int); -extern int generic_permission(struct inode *, int); -extern int __check_sticky(struct inode *dir, struct inode *inode); +int notify_change(struct user_namespace *, struct dentry *, +		  struct iattr *, struct inode **); +int inode_permission(struct user_namespace *, struct inode *, int); +int generic_permission(struct user_namespace *, struct inode *, int); +static inline int file_permission(struct file *file, int mask) +{ +	return inode_permission(file_mnt_user_ns(file), +				file_inode(file), mask); +} +static inline int path_permission(const struct path *path, int mask) +{ +	return inode_permission(mnt_user_ns(path->mnt), +				d_inode(path->dentry), mask); +} +int __check_sticky(struct user_namespace *mnt_userns, struct inode *dir, +		   struct inode *inode);  static inline bool execute_ok(struct inode *inode)  { @@ -2985,8 +3080,8 @@ extern ssize_t generic_write_checks(struct kiocb *, struct iov_iter *);  extern int generic_write_check_limits(struct file *file, loff_t pos,  		loff_t *count);  extern int generic_file_rw_checks(struct file *file_in, struct file *file_out); -extern ssize_t generic_file_buffered_read(struct kiocb *iocb, -		struct iov_iter *to, ssize_t already_read); +ssize_t filemap_read(struct kiocb *iocb, struct iov_iter *to, +		ssize_t already_read);  extern ssize_t generic_file_read_iter(struct kiocb *, struct iov_iter *);  extern ssize_t __generic_file_write_iter(struct kiocb *, struct iov_iter *);  extern ssize_t generic_file_write_iter(struct kiocb *, struct iov_iter *); @@ -3113,7 +3208,7 @@ extern int __page_symlink(struct inode *inode, const char *symname, int len,  extern int page_symlink(struct inode *inode, const char *symname, int len);  extern const struct inode_operations page_symlink_inode_operations;  extern void kfree_link(void *); -extern void generic_fillattr(struct inode *, struct kstat *); +void generic_fillattr(struct user_namespace *, struct inode *, struct kstat *);  extern int vfs_getattr_nosec(const struct path *, struct kstat *, u32, unsigned int);  extern int vfs_getattr(const struct path *, struct kstat *, u32, unsigned int);  void __inode_add_bytes(struct inode *inode, loff_t bytes); @@ -3163,15 +3258,18 @@ extern int dcache_dir_open(struct inode *, struct file *);  extern int dcache_dir_close(struct inode *, struct file *);  extern loff_t dcache_dir_lseek(struct file *, loff_t, int);  extern int dcache_readdir(struct file *, struct dir_context *); -extern int simple_setattr(struct dentry *, struct iattr *); -extern int simple_getattr(const struct path *, struct kstat *, u32, unsigned int); +extern int simple_setattr(struct user_namespace *, struct dentry *, +			  struct iattr *); +extern int simple_getattr(struct user_namespace *, const struct path *, +			  struct kstat *, u32, unsigned int);  extern int simple_statfs(struct dentry *, struct kstatfs *);  extern int simple_open(struct inode *inode, struct file *file);  extern int simple_link(struct dentry *, struct inode *, struct dentry *);  extern int simple_unlink(struct inode *, struct dentry *);  extern int simple_rmdir(struct inode *, struct dentry *); -extern int simple_rename(struct inode *, struct dentry *, -			 struct inode *, struct dentry *, unsigned int); +extern int simple_rename(struct user_namespace *, struct inode *, +			 struct dentry *, struct inode *, struct dentry *, +			 unsigned int);  extern void simple_recursive_removal(struct dentry *,                                void (*callback)(struct dentry *));  extern int noop_fsync(struct file *, loff_t, loff_t, int); @@ -3229,9 +3327,10 @@ extern int buffer_migrate_page_norefs(struct address_space *,  #define buffer_migrate_page_norefs NULL  #endif -extern int setattr_prepare(struct dentry *, struct iattr *); +int setattr_prepare(struct user_namespace *, struct dentry *, struct iattr *);  extern int inode_newsize_ok(const struct inode *, loff_t offset); -extern void setattr_copy(struct inode *inode, const struct iattr *attr); +void setattr_copy(struct user_namespace *, struct inode *inode, +		  const struct iattr *attr);  extern int file_update_time(struct file *file); @@ -3395,12 +3494,13 @@ static inline bool is_sxid(umode_t mode)  	return (mode & S_ISUID) || ((mode & S_ISGID) && (mode & S_IXGRP));  } -static inline int check_sticky(struct inode *dir, struct inode *inode) +static inline int check_sticky(struct user_namespace *mnt_userns, +			       struct inode *dir, struct inode *inode)  {  	if (!(dir->i_mode & S_ISVTX))  		return 0; -	return __check_sticky(dir, inode); +	return __check_sticky(mnt_userns, dir, inode);  }  static inline void inode_has_no_xattr(struct inode *inode)  | 
