mirror of https://gitee.com/openkylin/linux.git
idmapped-mounts-v5.12
-----BEGIN PGP SIGNATURE-----
iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCYCegywAKCRCRxhvAZXjc
ouJ6AQDlf+7jCQlQdeKKoN9QDFfMzG1ooemat36EpRRTONaGuAD8D9A4sUsG4+5f
4IU5Lj9oY4DEmF8HenbWK2ZHsesL2Qg=
=yPaw
-----END PGP SIGNATURE-----
Merge tag 'idmapped-mounts-v5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux
Pull idmapped mounts from Christian Brauner:
"This introduces idmapped mounts which has been in the making for some
time. Simply put, different mounts can expose the same file or
directory with different ownership. This initial implementation comes
with ports for fat, ext4 and with Christoph's port for xfs with more
filesystems being actively worked on by independent people and
maintainers.
Idmapping mounts handle a wide range of long standing use-cases. Here
are just a few:
- Idmapped mounts make it possible to easily share files between
multiple users or multiple machines especially in complex
scenarios. For example, idmapped mounts will be used in the
implementation of portable home directories in
systemd-homed.service(8) where they allow users to move their home
directory to an external storage device and use it on multiple
computers where they are assigned different uids and gids. This
effectively makes it possible to assign random uids and gids at
login time.
- It is possible to share files from the host with unprivileged
containers without having to change ownership permanently through
chown(2).
- It is possible to idmap a container's rootfs and without having to
mangle every file. For example, Chromebooks use it to share the
user's Download folder with their unprivileged containers in their
Linux subsystem.
- It is possible to share files between containers with
non-overlapping idmappings.
- Filesystem that lack a proper concept of ownership such as fat can
use idmapped mounts to implement discretionary access (DAC)
permission checking.
- They allow users to efficiently changing ownership on a per-mount
basis without having to (recursively) chown(2) all files. In
contrast to chown (2) changing ownership of large sets of files is
instantenous with idmapped mounts. This is especially useful when
ownership of a whole root filesystem of a virtual machine or
container is changed. With idmapped mounts a single syscall
mount_setattr syscall will be sufficient to change the ownership of
all files.
- Idmapped mounts always take the current ownership into account as
idmappings specify what a given uid or gid is supposed to be mapped
to. This contrasts with the chown(2) syscall which cannot by itself
take the current ownership of the files it changes into account. It
simply changes the ownership to the specified uid and gid. This is
especially problematic when recursively chown(2)ing a large set of
files which is commong with the aforementioned portable home
directory and container and vm scenario.
- Idmapped mounts allow to change ownership locally, restricting it
to specific mounts, and temporarily as the ownership changes only
apply as long as the mount exists.
Several userspace projects have either already put up patches and
pull-requests for this feature or will do so should you decide to pull
this:
- systemd: In a wide variety of scenarios but especially right away
in their implementation of portable home directories.
https://systemd.io/HOME_DIRECTORY/
- container runtimes: containerd, runC, LXD:To share data between
host and unprivileged containers, unprivileged and privileged
containers, etc. The pull request for idmapped mounts support in
containerd, the default Kubernetes runtime is already up for quite
a while now: https://github.com/containerd/containerd/pull/4734
- The virtio-fs developers and several users have expressed interest
in using this feature with virtual machines once virtio-fs is
ported.
- ChromeOS: Sharing host-directories with unprivileged containers.
I've tightly synced with all those projects and all of those listed
here have also expressed their need/desire for this feature on the
mailing list. For more info on how people use this there's a bunch of
talks about this too. Here's just two recent ones:
https://www.cncf.io/wp-content/uploads/2020/12/Rootless-Containers-in-Gitpod.pdf
https://fosdem.org/2021/schedule/event/containers_idmap/
This comes with an extensive xfstests suite covering both ext4 and
xfs:
https://git.kernel.org/brauner/xfstests-dev/h/idmapped_mounts
It covers truncation, creation, opening, xattrs, vfscaps, setid
execution, setgid inheritance and more both with idmapped and
non-idmapped mounts. It already helped to discover an unrelated xfs
setgid inheritance bug which has since been fixed in mainline. It will
be sent for inclusion with the xfstests project should you decide to
merge this.
In order to support per-mount idmappings vfsmounts are marked with
user namespaces. The idmapping of the user namespace will be used to
map the ids of vfs objects when they are accessed through that mount.
By default all vfsmounts are marked with the initial user namespace.
The initial user namespace is used to indicate that a mount is not
idmapped. All operations behave as before and this is verified in the
testsuite.
Based on prior discussions we want to attach the whole user namespace
and not just a dedicated idmapping struct. This allows us to reuse all
the helpers that already exist for dealing with idmappings instead of
introducing a whole new range of helpers. In addition, if we decide in
the future that we are confident enough to enable unprivileged users
to setup idmapped mounts the permission checking can take into account
whether the caller is privileged in the user namespace the mount is
currently marked with.
The user namespace the mount will be marked with can be specified by
passing a file descriptor refering to the user namespace as an
argument to the new mount_setattr() syscall together with the new
MOUNT_ATTR_IDMAP flag. The system call follows the openat2() pattern
of extensibility.
The following conditions must be met in order to create an idmapped
mount:
- The caller must currently have the CAP_SYS_ADMIN capability in the
user namespace the underlying filesystem has been mounted in.
- The underlying filesystem must support idmapped mounts.
- The mount must not already be idmapped. This also implies that the
idmapping of a mount cannot be altered once it has been idmapped.
- The mount must be a detached/anonymous mount, i.e. it must have
been created by calling open_tree() with the OPEN_TREE_CLONE flag
and it must not already have been visible in the filesystem.
The last two points guarantee easier semantics for userspace and the
kernel and make the implementation significantly simpler.
By default vfsmounts are marked with the initial user namespace and no
behavioral or performance changes are observed.
The manpage with a detailed description can be found here:
1d7b902e28
In order to support idmapped mounts, filesystems need to be changed
and mark themselves with the FS_ALLOW_IDMAP flag in fs_flags. The
patches to convert individual filesystem are not very large or
complicated overall as can be seen from the included fat, ext4, and
xfs ports. Patches for other filesystems are actively worked on and
will be sent out separately. The xfstestsuite can be used to verify
that port has been done correctly.
The mount_setattr() syscall is motivated independent of the idmapped
mounts patches and it's been around since July 2019. One of the most
valuable features of the new mount api is the ability to perform
mounts based on file descriptors only.
Together with the lookup restrictions available in the openat2()
RESOLVE_* flag namespace which we added in v5.6 this is the first time
we are close to hardened and race-free (e.g. symlinks) mounting and
path resolution.
While userspace has started porting to the new mount api to mount
proper filesystems and create new bind-mounts it is currently not
possible to change mount options of an already existing bind mount in
the new mount api since the mount_setattr() syscall is missing.
With the addition of the mount_setattr() syscall we remove this last
restriction and userspace can now fully port to the new mount api,
covering every use-case the old mount api could. We also add the
crucial ability to recursively change mount options for a whole mount
tree, both removing and adding mount options at the same time. This
syscall has been requested multiple times by various people and
projects.
There is a simple tool available at
https://github.com/brauner/mount-idmapped
that allows to create idmapped mounts so people can play with this
patch series. I'll add support for the regular mount binary should you
decide to pull this in the following weeks:
Here's an example to a simple idmapped mount of another user's home
directory:
u1001@f2-vm:/$ sudo ./mount --idmap both:1000:1001:1 /home/ubuntu/ /mnt
u1001@f2-vm:/$ ls -al /home/ubuntu/
total 28
drwxr-xr-x 2 ubuntu ubuntu 4096 Oct 28 22:07 .
drwxr-xr-x 4 root root 4096 Oct 28 04:00 ..
-rw------- 1 ubuntu ubuntu 3154 Oct 28 22:12 .bash_history
-rw-r--r-- 1 ubuntu ubuntu 220 Feb 25 2020 .bash_logout
-rw-r--r-- 1 ubuntu ubuntu 3771 Feb 25 2020 .bashrc
-rw-r--r-- 1 ubuntu ubuntu 807 Feb 25 2020 .profile
-rw-r--r-- 1 ubuntu ubuntu 0 Oct 16 16:11 .sudo_as_admin_successful
-rw------- 1 ubuntu ubuntu 1144 Oct 28 00:43 .viminfo
u1001@f2-vm:/$ ls -al /mnt/
total 28
drwxr-xr-x 2 u1001 u1001 4096 Oct 28 22:07 .
drwxr-xr-x 29 root root 4096 Oct 28 22:01 ..
-rw------- 1 u1001 u1001 3154 Oct 28 22:12 .bash_history
-rw-r--r-- 1 u1001 u1001 220 Feb 25 2020 .bash_logout
-rw-r--r-- 1 u1001 u1001 3771 Feb 25 2020 .bashrc
-rw-r--r-- 1 u1001 u1001 807 Feb 25 2020 .profile
-rw-r--r-- 1 u1001 u1001 0 Oct 16 16:11 .sudo_as_admin_successful
-rw------- 1 u1001 u1001 1144 Oct 28 00:43 .viminfo
u1001@f2-vm:/$ touch /mnt/my-file
u1001@f2-vm:/$ setfacl -m u:1001:rwx /mnt/my-file
u1001@f2-vm:/$ sudo setcap -n 1001 cap_net_raw+ep /mnt/my-file
u1001@f2-vm:/$ ls -al /mnt/my-file
-rw-rwxr--+ 1 u1001 u1001 0 Oct 28 22:14 /mnt/my-file
u1001@f2-vm:/$ ls -al /home/ubuntu/my-file
-rw-rwxr--+ 1 ubuntu ubuntu 0 Oct 28 22:14 /home/ubuntu/my-file
u1001@f2-vm:/$ getfacl /mnt/my-file
getfacl: Removing leading '/' from absolute path names
# file: mnt/my-file
# owner: u1001
# group: u1001
user::rw-
user:u1001:rwx
group::rw-
mask::rwx
other::r--
u1001@f2-vm:/$ getfacl /home/ubuntu/my-file
getfacl: Removing leading '/' from absolute path names
# file: home/ubuntu/my-file
# owner: ubuntu
# group: ubuntu
user::rw-
user:ubuntu:rwx
group::rw-
mask::rwx
other::r--"
* tag 'idmapped-mounts-v5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux: (41 commits)
xfs: remove the possibly unused mp variable in xfs_file_compat_ioctl
xfs: support idmapped mounts
ext4: support idmapped mounts
fat: handle idmapped mounts
tests: add mount_setattr() selftests
fs: introduce MOUNT_ATTR_IDMAP
fs: add mount_setattr()
fs: add attr_flags_to_mnt_flags helper
fs: split out functions to hold writers
namespace: only take read lock in do_reconfigure_mnt()
mount: make {lock,unlock}_mount_hash() static
namespace: take lock_mount_hash() directly when changing flags
nfs: do not export idmapped mounts
overlayfs: do not mount on top of idmapped mounts
ecryptfs: do not mount on top of idmapped mounts
ima: handle idmapped mounts
apparmor: handle idmapped mounts
fs: make helpers idmap mount aware
exec: handle idmapped mounts
would_dump: handle idmapped mounts
...
This commit is contained in:
commit
7d6beb71da
|
@ -126,9 +126,10 @@ prototypes::
|
|||
int (*get)(const struct xattr_handler *handler, struct dentry *dentry,
|
||||
struct inode *inode, const char *name, void *buffer,
|
||||
size_t size);
|
||||
int (*set)(const struct xattr_handler *handler, struct dentry *dentry,
|
||||
struct inode *inode, const char *name, const void *buffer,
|
||||
size_t size, int flags);
|
||||
int (*set)(const struct xattr_handler *handler,
|
||||
struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry, struct inode *inode, const char *name,
|
||||
const void *buffer, size_t size, int flags);
|
||||
|
||||
locking rules:
|
||||
all may block
|
||||
|
|
|
@ -717,6 +717,8 @@ be removed. Switch while you still can; the old one won't stay.
|
|||
**mandatory**
|
||||
|
||||
->setxattr() and xattr_handler.set() get dentry and inode passed separately.
|
||||
The xattr_handler.set() gets passed the user namespace of the mount the inode
|
||||
is seen from so filesystems can idmap the i_uid and i_gid accordingly.
|
||||
dentry might be yet to be attached to inode, so do _not_ use its ->d_inode
|
||||
in the instances. Rationale: !@#!@# security_d_instantiate() needs to be
|
||||
called before we attach dentry to inode and !@#!@##!@$!$#!@#$!@$!@$ smack
|
||||
|
|
|
@ -418,28 +418,29 @@ As of kernel 2.6.22, the following members are defined:
|
|||
.. code-block:: c
|
||||
|
||||
struct inode_operations {
|
||||
int (*create) (struct inode *,struct dentry *, umode_t, bool);
|
||||
int (*create) (struct user_namespace *, struct inode *,struct dentry *, umode_t, bool);
|
||||
struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
|
||||
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 (*readlink) (struct dentry *, char __user *,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);
|
||||
int (*get_acl)(struct inode *, 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);
|
||||
void (*update_time)(struct inode *, struct timespec *, int);
|
||||
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 (*tmpfile) (struct user_namespace *, struct inode *, struct dentry *, umode_t);
|
||||
int (*set_acl)(struct user_namespace *, struct inode *, struct posix_acl *, int);
|
||||
};
|
||||
|
||||
Again, all methods are called without any locks being held, unless
|
||||
|
|
|
@ -481,3 +481,4 @@
|
|||
549 common faccessat2 sys_faccessat2
|
||||
550 common process_madvise sys_process_madvise
|
||||
551 common epoll_pwait2 sys_epoll_pwait2
|
||||
552 common mount_setattr sys_mount_setattr
|
||||
|
|
|
@ -455,3 +455,4 @@
|
|||
439 common faccessat2 sys_faccessat2
|
||||
440 common process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2
|
||||
442 common mount_setattr sys_mount_setattr
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
#define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE + 5)
|
||||
#define __ARM_NR_COMPAT_END (__ARM_NR_COMPAT_BASE + 0x800)
|
||||
|
||||
#define __NR_compat_syscalls 442
|
||||
#define __NR_compat_syscalls 443
|
||||
#endif
|
||||
|
||||
#define __ARCH_WANT_SYS_CLONE
|
||||
|
|
|
@ -891,6 +891,8 @@ __SYSCALL(__NR_faccessat2, sys_faccessat2)
|
|||
__SYSCALL(__NR_process_madvise, sys_process_madvise)
|
||||
#define __NR_epoll_pwait2 441
|
||||
__SYSCALL(__NR_epoll_pwait2, compat_sys_epoll_pwait2)
|
||||
#define __NR_mount_setattr 442
|
||||
__SYSCALL(__NR_mount_setattr, sys_mount_setattr)
|
||||
|
||||
/*
|
||||
* Please add new compat syscalls above this comment and update
|
||||
|
|
|
@ -362,3 +362,4 @@
|
|||
439 common faccessat2 sys_faccessat2
|
||||
440 common process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2
|
||||
442 common mount_setattr sys_mount_setattr
|
||||
|
|
|
@ -441,3 +441,4 @@
|
|||
439 common faccessat2 sys_faccessat2
|
||||
440 common process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2
|
||||
442 common mount_setattr sys_mount_setattr
|
||||
|
|
|
@ -447,3 +447,4 @@
|
|||
439 common faccessat2 sys_faccessat2
|
||||
440 common process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2
|
||||
442 common mount_setattr sys_mount_setattr
|
||||
|
|
|
@ -380,3 +380,4 @@
|
|||
439 n32 faccessat2 sys_faccessat2
|
||||
440 n32 process_madvise sys_process_madvise
|
||||
441 n32 epoll_pwait2 compat_sys_epoll_pwait2
|
||||
442 n32 mount_setattr sys_mount_setattr
|
||||
|
|
|
@ -356,3 +356,4 @@
|
|||
439 n64 faccessat2 sys_faccessat2
|
||||
440 n64 process_madvise sys_process_madvise
|
||||
441 n64 epoll_pwait2 sys_epoll_pwait2
|
||||
442 n64 mount_setattr sys_mount_setattr
|
||||
|
|
|
@ -429,3 +429,4 @@
|
|||
439 o32 faccessat2 sys_faccessat2
|
||||
440 o32 process_madvise sys_process_madvise
|
||||
441 o32 epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
|
||||
442 o32 mount_setattr sys_mount_setattr
|
||||
|
|
|
@ -439,3 +439,4 @@
|
|||
439 common faccessat2 sys_faccessat2
|
||||
440 common process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
|
||||
442 common mount_setattr sys_mount_setattr
|
||||
|
|
|
@ -521,3 +521,4 @@
|
|||
439 common faccessat2 sys_faccessat2
|
||||
440 common process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
|
||||
442 common mount_setattr sys_mount_setattr
|
||||
|
|
|
@ -91,14 +91,15 @@ spufs_new_inode(struct super_block *sb, umode_t mode)
|
|||
}
|
||||
|
||||
static int
|
||||
spufs_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
spufs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
|
||||
struct iattr *attr)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
|
||||
if ((attr->ia_valid & ATTR_SIZE) &&
|
||||
(attr->ia_size != inode->i_size))
|
||||
return -EINVAL;
|
||||
setattr_copy(inode, attr);
|
||||
setattr_copy(&init_user_ns, inode, attr);
|
||||
mark_inode_dirty(inode);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -444,3 +444,4 @@
|
|||
439 common faccessat2 sys_faccessat2 sys_faccessat2
|
||||
440 common process_madvise sys_process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
|
||||
442 common mount_setattr sys_mount_setattr sys_mount_setattr
|
||||
|
|
|
@ -444,3 +444,4 @@
|
|||
439 common faccessat2 sys_faccessat2
|
||||
440 common process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2
|
||||
442 common mount_setattr sys_mount_setattr
|
||||
|
|
|
@ -487,3 +487,4 @@
|
|||
439 common faccessat2 sys_faccessat2
|
||||
440 common process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
|
||||
442 common mount_setattr sys_mount_setattr
|
||||
|
|
|
@ -446,3 +446,4 @@
|
|||
439 i386 faccessat2 sys_faccessat2
|
||||
440 i386 process_madvise sys_process_madvise
|
||||
441 i386 epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
|
||||
442 i386 mount_setattr sys_mount_setattr
|
||||
|
|
|
@ -363,6 +363,7 @@
|
|||
439 common faccessat2 sys_faccessat2
|
||||
440 common process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2
|
||||
442 common mount_setattr sys_mount_setattr
|
||||
|
||||
#
|
||||
# Due to a historical design error, certain syscalls are numbered differently
|
||||
|
|
|
@ -412,3 +412,4 @@
|
|||
439 common faccessat2 sys_faccessat2
|
||||
440 common process_madvise sys_process_madvise
|
||||
441 common epoll_pwait2 sys_epoll_pwait2
|
||||
442 common mount_setattr sys_mount_setattr
|
||||
|
|
|
@ -355,7 +355,8 @@ static inline bool is_binderfs_control_device(const struct dentry *dentry)
|
|||
return info->control_dentry == dentry;
|
||||
}
|
||||
|
||||
static int binderfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
static int binderfs_rename(struct user_namespace *mnt_userns,
|
||||
struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
unsigned int flags)
|
||||
{
|
||||
|
@ -363,7 +364,8 @@ static int binderfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
is_binderfs_control_device(new_dentry))
|
||||
return -EPERM;
|
||||
|
||||
return simple_rename(old_dir, old_dentry, new_dir, new_dentry, flags);
|
||||
return simple_rename(&init_user_ns, old_dir, old_dentry, new_dir,
|
||||
new_dentry, flags);
|
||||
}
|
||||
|
||||
static int binderfs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
|
|
|
@ -162,7 +162,7 @@ static int dev_mkdir(const char *name, umode_t mode)
|
|||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
|
||||
err = vfs_mkdir(d_inode(path.dentry), dentry, mode);
|
||||
err = vfs_mkdir(&init_user_ns, d_inode(path.dentry), dentry, mode);
|
||||
if (!err)
|
||||
/* mark as kernel-created inode */
|
||||
d_inode(dentry)->i_private = &thread;
|
||||
|
@ -212,7 +212,8 @@ static int handle_create(const char *nodename, umode_t mode, kuid_t uid,
|
|||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
|
||||
err = vfs_mknod(d_inode(path.dentry), dentry, mode, dev->devt);
|
||||
err = vfs_mknod(&init_user_ns, d_inode(path.dentry), dentry, mode,
|
||||
dev->devt);
|
||||
if (!err) {
|
||||
struct iattr newattrs;
|
||||
|
||||
|
@ -221,7 +222,7 @@ static int handle_create(const char *nodename, umode_t mode, kuid_t uid,
|
|||
newattrs.ia_gid = gid;
|
||||
newattrs.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID;
|
||||
inode_lock(d_inode(dentry));
|
||||
notify_change(dentry, &newattrs, NULL);
|
||||
notify_change(&init_user_ns, dentry, &newattrs, NULL);
|
||||
inode_unlock(d_inode(dentry));
|
||||
|
||||
/* mark as kernel-created inode */
|
||||
|
@ -242,7 +243,8 @@ static int dev_rmdir(const char *name)
|
|||
return PTR_ERR(dentry);
|
||||
if (d_really_is_positive(dentry)) {
|
||||
if (d_inode(dentry)->i_private == &thread)
|
||||
err = vfs_rmdir(d_inode(parent.dentry), dentry);
|
||||
err = vfs_rmdir(&init_user_ns, d_inode(parent.dentry),
|
||||
dentry);
|
||||
else
|
||||
err = -EPERM;
|
||||
} else {
|
||||
|
@ -328,9 +330,10 @@ static int handle_remove(const char *nodename, struct device *dev)
|
|||
newattrs.ia_valid =
|
||||
ATTR_UID|ATTR_GID|ATTR_MODE;
|
||||
inode_lock(d_inode(dentry));
|
||||
notify_change(dentry, &newattrs, NULL);
|
||||
notify_change(&init_user_ns, dentry, &newattrs, NULL);
|
||||
inode_unlock(d_inode(dentry));
|
||||
err = vfs_unlink(d_inode(parent.dentry), dentry, NULL);
|
||||
err = vfs_unlink(&init_user_ns, d_inode(parent.dentry),
|
||||
dentry, NULL);
|
||||
if (!err || err == -ENOENT)
|
||||
deleted = 1;
|
||||
}
|
||||
|
|
|
@ -239,6 +239,7 @@ static int v9fs_xattr_get_acl(const struct xattr_handler *handler,
|
|||
}
|
||||
|
||||
static int v9fs_xattr_set_acl(const struct xattr_handler *handler,
|
||||
struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry, struct inode *inode,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
|
@ -258,7 +259,7 @@ static int v9fs_xattr_set_acl(const struct xattr_handler *handler,
|
|||
|
||||
if (S_ISLNK(inode->i_mode))
|
||||
return -EOPNOTSUPP;
|
||||
if (!inode_owner_or_capable(inode))
|
||||
if (!inode_owner_or_capable(&init_user_ns, inode))
|
||||
return -EPERM;
|
||||
if (value) {
|
||||
/* update the cached acl value */
|
||||
|
@ -279,7 +280,8 @@ static int v9fs_xattr_set_acl(const struct xattr_handler *handler,
|
|||
struct iattr iattr = { 0 };
|
||||
struct posix_acl *old_acl = acl;
|
||||
|
||||
retval = posix_acl_update_mode(inode, &iattr.ia_mode, &acl);
|
||||
retval = posix_acl_update_mode(&init_user_ns, inode,
|
||||
&iattr.ia_mode, &acl);
|
||||
if (retval)
|
||||
goto err_out;
|
||||
if (!acl) {
|
||||
|
@ -297,7 +299,7 @@ static int v9fs_xattr_set_acl(const struct xattr_handler *handler,
|
|||
* What is the following setxattr update the
|
||||
* mode ?
|
||||
*/
|
||||
v9fs_vfs_setattr_dotl(dentry, &iattr);
|
||||
v9fs_vfs_setattr_dotl(&init_user_ns, dentry, &iattr);
|
||||
}
|
||||
break;
|
||||
case ACL_TYPE_DEFAULT:
|
||||
|
|
|
@ -135,7 +135,8 @@ extern struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
|
|||
unsigned int flags);
|
||||
extern int v9fs_vfs_unlink(struct inode *i, struct dentry *d);
|
||||
extern int v9fs_vfs_rmdir(struct inode *i, struct dentry *d);
|
||||
extern int v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
extern int v9fs_vfs_rename(struct user_namespace *mnt_userns,
|
||||
struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
unsigned int flags);
|
||||
extern struct inode *v9fs_inode_from_fid(struct v9fs_session_info *v9ses,
|
||||
|
|
|
@ -59,7 +59,8 @@ void v9fs_inode2stat(struct inode *inode, struct p9_wstat *stat);
|
|||
int v9fs_uflags2omode(int uflags, int extended);
|
||||
|
||||
void v9fs_blank_wstat(struct p9_wstat *wstat);
|
||||
int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *);
|
||||
int v9fs_vfs_setattr_dotl(struct user_namespace *, struct dentry *,
|
||||
struct iattr *);
|
||||
int v9fs_file_fsync_dotl(struct file *filp, loff_t start, loff_t end,
|
||||
int datasync);
|
||||
int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode);
|
||||
|
|
|
@ -251,7 +251,7 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses,
|
|||
{
|
||||
int err = 0;
|
||||
|
||||
inode_init_owner(inode, NULL, mode);
|
||||
inode_init_owner(&init_user_ns,inode, NULL, mode);
|
||||
inode->i_blocks = 0;
|
||||
inode->i_rdev = rdev;
|
||||
inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
|
||||
|
@ -676,8 +676,8 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
|
|||
*/
|
||||
|
||||
static int
|
||||
v9fs_vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
bool excl)
|
||||
v9fs_vfs_create(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode, bool excl)
|
||||
{
|
||||
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
|
||||
u32 perm = unixmode2p9mode(v9ses, mode);
|
||||
|
@ -702,7 +702,8 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
|||
*
|
||||
*/
|
||||
|
||||
static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
static int v9fs_vfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode)
|
||||
{
|
||||
int err;
|
||||
u32 perm;
|
||||
|
@ -907,9 +908,9 @@ int v9fs_vfs_rmdir(struct inode *i, struct dentry *d)
|
|||
*/
|
||||
|
||||
int
|
||||
v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
unsigned int flags)
|
||||
v9fs_vfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
|
||||
struct dentry *old_dentry, struct inode *new_dir,
|
||||
struct dentry *new_dentry, unsigned int flags)
|
||||
{
|
||||
int retval;
|
||||
struct inode *old_inode;
|
||||
|
@ -1016,8 +1017,8 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
*/
|
||||
|
||||
static int
|
||||
v9fs_vfs_getattr(const struct path *path, struct kstat *stat,
|
||||
u32 request_mask, unsigned int flags)
|
||||
v9fs_vfs_getattr(struct user_namespace *mnt_userns, const struct path *path,
|
||||
struct kstat *stat, u32 request_mask, unsigned int flags)
|
||||
{
|
||||
struct dentry *dentry = path->dentry;
|
||||
struct v9fs_session_info *v9ses;
|
||||
|
@ -1027,7 +1028,7 @@ v9fs_vfs_getattr(const struct path *path, struct kstat *stat,
|
|||
p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry);
|
||||
v9ses = v9fs_dentry2v9ses(dentry);
|
||||
if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
|
||||
generic_fillattr(d_inode(dentry), stat);
|
||||
generic_fillattr(&init_user_ns, d_inode(dentry), stat);
|
||||
return 0;
|
||||
}
|
||||
fid = v9fs_fid_lookup(dentry);
|
||||
|
@ -1040,7 +1041,7 @@ v9fs_vfs_getattr(const struct path *path, struct kstat *stat,
|
|||
return PTR_ERR(st);
|
||||
|
||||
v9fs_stat2inode(st, d_inode(dentry), dentry->d_sb, 0);
|
||||
generic_fillattr(d_inode(dentry), stat);
|
||||
generic_fillattr(&init_user_ns, d_inode(dentry), stat);
|
||||
|
||||
p9stat_free(st);
|
||||
kfree(st);
|
||||
|
@ -1054,7 +1055,8 @@ v9fs_vfs_getattr(const struct path *path, struct kstat *stat,
|
|||
*
|
||||
*/
|
||||
|
||||
static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
|
||||
static int v9fs_vfs_setattr(struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry, struct iattr *iattr)
|
||||
{
|
||||
int retval, use_dentry = 0;
|
||||
struct v9fs_session_info *v9ses;
|
||||
|
@ -1062,7 +1064,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
|
|||
struct p9_wstat wstat;
|
||||
|
||||
p9_debug(P9_DEBUG_VFS, "\n");
|
||||
retval = setattr_prepare(dentry, iattr);
|
||||
retval = setattr_prepare(&init_user_ns, dentry, iattr);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
|
@ -1118,7 +1120,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
|
|||
|
||||
v9fs_invalidate_inode_attr(d_inode(dentry));
|
||||
|
||||
setattr_copy(d_inode(dentry), iattr);
|
||||
setattr_copy(&init_user_ns, d_inode(dentry), iattr);
|
||||
mark_inode_dirty(d_inode(dentry));
|
||||
return 0;
|
||||
}
|
||||
|
@ -1295,7 +1297,8 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
|
|||
*/
|
||||
|
||||
static int
|
||||
v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
|
||||
v9fs_vfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, const char *symname)
|
||||
{
|
||||
p9_debug(P9_DEBUG_VFS, " %lu,%pd,%s\n",
|
||||
dir->i_ino, dentry, symname);
|
||||
|
@ -1348,7 +1351,8 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
|
|||
*/
|
||||
|
||||
static int
|
||||
v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev)
|
||||
v9fs_vfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode, dev_t rdev)
|
||||
{
|
||||
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
|
||||
int retval;
|
||||
|
|
|
@ -33,8 +33,8 @@
|
|||
#include "acl.h"
|
||||
|
||||
static int
|
||||
v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
|
||||
dev_t rdev);
|
||||
v9fs_vfs_mknod_dotl(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t omode, dev_t rdev);
|
||||
|
||||
/**
|
||||
* v9fs_get_fsgid_for_create - Helper function to get the gid for creating a
|
||||
|
@ -218,10 +218,10 @@ int v9fs_open_to_dotl_flags(int flags)
|
|||
*/
|
||||
|
||||
static int
|
||||
v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
|
||||
bool excl)
|
||||
v9fs_vfs_create_dotl(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t omode, bool excl)
|
||||
{
|
||||
return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0);
|
||||
return v9fs_vfs_mknod_dotl(mnt_userns, dir, dentry, omode, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -367,8 +367,9 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
|
|||
*
|
||||
*/
|
||||
|
||||
static int v9fs_vfs_mkdir_dotl(struct inode *dir,
|
||||
struct dentry *dentry, umode_t omode)
|
||||
static int v9fs_vfs_mkdir_dotl(struct user_namespace *mnt_userns,
|
||||
struct inode *dir, struct dentry *dentry,
|
||||
umode_t omode)
|
||||
{
|
||||
int err;
|
||||
struct v9fs_session_info *v9ses;
|
||||
|
@ -457,8 +458,9 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
|
|||
}
|
||||
|
||||
static int
|
||||
v9fs_vfs_getattr_dotl(const struct path *path, struct kstat *stat,
|
||||
u32 request_mask, unsigned int flags)
|
||||
v9fs_vfs_getattr_dotl(struct user_namespace *mnt_userns,
|
||||
const struct path *path, struct kstat *stat,
|
||||
u32 request_mask, unsigned int flags)
|
||||
{
|
||||
struct dentry *dentry = path->dentry;
|
||||
struct v9fs_session_info *v9ses;
|
||||
|
@ -468,7 +470,7 @@ v9fs_vfs_getattr_dotl(const struct path *path, struct kstat *stat,
|
|||
p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry);
|
||||
v9ses = v9fs_dentry2v9ses(dentry);
|
||||
if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
|
||||
generic_fillattr(d_inode(dentry), stat);
|
||||
generic_fillattr(&init_user_ns, d_inode(dentry), stat);
|
||||
return 0;
|
||||
}
|
||||
fid = v9fs_fid_lookup(dentry);
|
||||
|
@ -485,7 +487,7 @@ v9fs_vfs_getattr_dotl(const struct path *path, struct kstat *stat,
|
|||
return PTR_ERR(st);
|
||||
|
||||
v9fs_stat2inode_dotl(st, d_inode(dentry), 0);
|
||||
generic_fillattr(d_inode(dentry), stat);
|
||||
generic_fillattr(&init_user_ns, d_inode(dentry), stat);
|
||||
/* Change block size to what the server returned */
|
||||
stat->blksize = st->st_blksize;
|
||||
|
||||
|
@ -540,7 +542,8 @@ static int v9fs_mapped_iattr_valid(int iattr_valid)
|
|||
*
|
||||
*/
|
||||
|
||||
int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
|
||||
int v9fs_vfs_setattr_dotl(struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry, struct iattr *iattr)
|
||||
{
|
||||
int retval, use_dentry = 0;
|
||||
struct p9_fid *fid = NULL;
|
||||
|
@ -549,7 +552,7 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
|
|||
|
||||
p9_debug(P9_DEBUG_VFS, "\n");
|
||||
|
||||
retval = setattr_prepare(dentry, iattr);
|
||||
retval = setattr_prepare(&init_user_ns, dentry, iattr);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
|
@ -590,7 +593,7 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
|
|||
truncate_setsize(inode, iattr->ia_size);
|
||||
|
||||
v9fs_invalidate_inode_attr(inode);
|
||||
setattr_copy(inode, iattr);
|
||||
setattr_copy(&init_user_ns, inode, iattr);
|
||||
mark_inode_dirty(inode);
|
||||
if (iattr->ia_valid & ATTR_MODE) {
|
||||
/* We also want to update ACL when we update mode bits */
|
||||
|
@ -684,8 +687,8 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode,
|
|||
}
|
||||
|
||||
static int
|
||||
v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
|
||||
const char *symname)
|
||||
v9fs_vfs_symlink_dotl(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, const char *symname)
|
||||
{
|
||||
int err;
|
||||
kgid_t gid;
|
||||
|
@ -824,8 +827,8 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
|
|||
*
|
||||
*/
|
||||
static int
|
||||
v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
|
||||
dev_t rdev)
|
||||
v9fs_vfs_mknod_dotl(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t omode, dev_t rdev)
|
||||
{
|
||||
int err;
|
||||
kgid_t gid;
|
||||
|
|
|
@ -157,6 +157,7 @@ static int v9fs_xattr_handler_get(const struct xattr_handler *handler,
|
|||
}
|
||||
|
||||
static int v9fs_xattr_handler_set(const struct xattr_handler *handler,
|
||||
struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry, struct inode *inode,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
|
|
|
@ -144,7 +144,8 @@ struct adfs_discmap {
|
|||
/* Inode stuff */
|
||||
struct inode *adfs_iget(struct super_block *sb, struct object_info *obj);
|
||||
int adfs_write_inode(struct inode *inode, struct writeback_control *wbc);
|
||||
int adfs_notify_change(struct dentry *dentry, struct iattr *attr);
|
||||
int adfs_notify_change(struct user_namespace *mnt_userns, struct dentry *dentry,
|
||||
struct iattr *attr);
|
||||
|
||||
/* map.c */
|
||||
int adfs_map_lookup(struct super_block *sb, u32 frag_id, unsigned int offset);
|
||||
|
|
|
@ -292,14 +292,15 @@ adfs_iget(struct super_block *sb, struct object_info *obj)
|
|||
* later.
|
||||
*/
|
||||
int
|
||||
adfs_notify_change(struct dentry *dentry, struct iattr *attr)
|
||||
adfs_notify_change(struct user_namespace *mnt_userns, struct dentry *dentry,
|
||||
struct iattr *attr)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
unsigned int ia_valid = attr->ia_valid;
|
||||
int error;
|
||||
|
||||
error = setattr_prepare(dentry, attr);
|
||||
error = setattr_prepare(&init_user_ns, dentry, attr);
|
||||
|
||||
/*
|
||||
* we can't change the UID or GID of any file -
|
||||
|
|
|
@ -167,27 +167,33 @@ extern const struct export_operations affs_export_ops;
|
|||
extern int affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len);
|
||||
extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int);
|
||||
extern int affs_unlink(struct inode *dir, struct dentry *dentry);
|
||||
extern int affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool);
|
||||
extern int affs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
|
||||
extern int affs_create(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode, bool);
|
||||
extern int affs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode);
|
||||
extern int affs_rmdir(struct inode *dir, struct dentry *dentry);
|
||||
extern int affs_link(struct dentry *olddentry, struct inode *dir,
|
||||
struct dentry *dentry);
|
||||
extern int affs_symlink(struct inode *dir, struct dentry *dentry,
|
||||
const char *symname);
|
||||
extern int affs_rename2(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
unsigned int flags);
|
||||
extern int affs_symlink(struct user_namespace *mnt_userns,
|
||||
struct inode *dir, struct dentry *dentry,
|
||||
const char *symname);
|
||||
extern int affs_rename2(struct user_namespace *mnt_userns,
|
||||
struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
unsigned int flags);
|
||||
|
||||
/* inode.c */
|
||||
|
||||
extern struct inode *affs_new_inode(struct inode *dir);
|
||||
extern int affs_notify_change(struct dentry *dentry, struct iattr *attr);
|
||||
extern int affs_notify_change(struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry, struct iattr *attr);
|
||||
extern void affs_evict_inode(struct inode *inode);
|
||||
extern struct inode *affs_iget(struct super_block *sb,
|
||||
unsigned long ino);
|
||||
extern int affs_write_inode(struct inode *inode,
|
||||
struct writeback_control *wbc);
|
||||
extern int affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s32 type);
|
||||
extern int affs_add_entry(struct inode *dir, struct inode *inode,
|
||||
struct dentry *dentry, s32 type);
|
||||
|
||||
/* file.c */
|
||||
|
||||
|
|
|
@ -216,14 +216,15 @@ affs_write_inode(struct inode *inode, struct writeback_control *wbc)
|
|||
}
|
||||
|
||||
int
|
||||
affs_notify_change(struct dentry *dentry, struct iattr *attr)
|
||||
affs_notify_change(struct user_namespace *mnt_userns, struct dentry *dentry,
|
||||
struct iattr *attr)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
int error;
|
||||
|
||||
pr_debug("notify_change(%lu,0x%x)\n", inode->i_ino, attr->ia_valid);
|
||||
|
||||
error = setattr_prepare(dentry, attr);
|
||||
error = setattr_prepare(&init_user_ns, dentry, attr);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
|
@ -249,7 +250,7 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr)
|
|||
affs_truncate(inode);
|
||||
}
|
||||
|
||||
setattr_copy(inode, attr);
|
||||
setattr_copy(&init_user_ns, inode, attr);
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
if (attr->ia_valid & ATTR_MODE)
|
||||
|
|
|
@ -242,7 +242,8 @@ affs_unlink(struct inode *dir, struct dentry *dentry)
|
|||
}
|
||||
|
||||
int
|
||||
affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl)
|
||||
affs_create(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode, bool excl)
|
||||
{
|
||||
struct super_block *sb = dir->i_sb;
|
||||
struct inode *inode;
|
||||
|
@ -273,7 +274,8 @@ affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl)
|
|||
}
|
||||
|
||||
int
|
||||
affs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
affs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode)
|
||||
{
|
||||
struct inode *inode;
|
||||
int error;
|
||||
|
@ -311,7 +313,8 @@ affs_rmdir(struct inode *dir, struct dentry *dentry)
|
|||
}
|
||||
|
||||
int
|
||||
affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
|
||||
affs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, const char *symname)
|
||||
{
|
||||
struct super_block *sb = dir->i_sb;
|
||||
struct buffer_head *bh;
|
||||
|
@ -500,9 +503,9 @@ affs_xrename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
return retval;
|
||||
}
|
||||
|
||||
int affs_rename2(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
unsigned int flags)
|
||||
int affs_rename2(struct user_namespace *mnt_userns, struct inode *old_dir,
|
||||
struct dentry *old_dentry, struct inode *new_dir,
|
||||
struct dentry *new_dentry, unsigned int flags)
|
||||
{
|
||||
|
||||
if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
|
||||
|
|
34
fs/afs/dir.c
34
fs/afs/dir.c
|
@ -28,18 +28,19 @@ static int afs_lookup_one_filldir(struct dir_context *ctx, const char *name, int
|
|||
loff_t fpos, u64 ino, unsigned dtype);
|
||||
static int afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen,
|
||||
loff_t fpos, u64 ino, unsigned dtype);
|
||||
static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
bool excl);
|
||||
static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
|
||||
static int afs_create(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode, bool excl);
|
||||
static int afs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode);
|
||||
static int afs_rmdir(struct inode *dir, struct dentry *dentry);
|
||||
static int afs_unlink(struct inode *dir, struct dentry *dentry);
|
||||
static int afs_link(struct dentry *from, struct inode *dir,
|
||||
struct dentry *dentry);
|
||||
static int afs_symlink(struct inode *dir, struct dentry *dentry,
|
||||
const char *content);
|
||||
static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
unsigned int flags);
|
||||
static int afs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, const char *content);
|
||||
static int afs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
|
||||
struct dentry *old_dentry, struct inode *new_dir,
|
||||
struct dentry *new_dentry, unsigned int flags);
|
||||
static int afs_dir_releasepage(struct page *page, gfp_t gfp_flags);
|
||||
static void afs_dir_invalidatepage(struct page *page, unsigned int offset,
|
||||
unsigned int length);
|
||||
|
@ -1325,7 +1326,8 @@ static const struct afs_operation_ops afs_mkdir_operation = {
|
|||
/*
|
||||
* create a directory on an AFS filesystem
|
||||
*/
|
||||
static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
static int afs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode)
|
||||
{
|
||||
struct afs_operation *op;
|
||||
struct afs_vnode *dvnode = AFS_FS_I(dir);
|
||||
|
@ -1619,8 +1621,8 @@ static const struct afs_operation_ops afs_create_operation = {
|
|||
/*
|
||||
* create a regular file on an AFS filesystem
|
||||
*/
|
||||
static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
bool excl)
|
||||
static int afs_create(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode, bool excl)
|
||||
{
|
||||
struct afs_operation *op;
|
||||
struct afs_vnode *dvnode = AFS_FS_I(dir);
|
||||
|
@ -1741,8 +1743,8 @@ static const struct afs_operation_ops afs_symlink_operation = {
|
|||
/*
|
||||
* create a symlink in an AFS filesystem
|
||||
*/
|
||||
static int afs_symlink(struct inode *dir, struct dentry *dentry,
|
||||
const char *content)
|
||||
static int afs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, const char *content)
|
||||
{
|
||||
struct afs_operation *op;
|
||||
struct afs_vnode *dvnode = AFS_FS_I(dir);
|
||||
|
@ -1876,9 +1878,9 @@ static const struct afs_operation_ops afs_rename_operation = {
|
|||
/*
|
||||
* rename a file in an AFS filesystem and/or move it between directories
|
||||
*/
|
||||
static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
unsigned int flags)
|
||||
static int afs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
|
||||
struct dentry *old_dentry, struct inode *new_dir,
|
||||
struct dentry *new_dentry, unsigned int flags)
|
||||
{
|
||||
struct afs_operation *op;
|
||||
struct afs_vnode *orig_dvnode, *new_dvnode, *vnode;
|
||||
|
|
|
@ -734,8 +734,8 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
|
|||
/*
|
||||
* read the attributes of an inode
|
||||
*/
|
||||
int afs_getattr(const struct path *path, struct kstat *stat,
|
||||
u32 request_mask, unsigned int query_flags)
|
||||
int afs_getattr(struct user_namespace *mnt_userns, const struct path *path,
|
||||
struct kstat *stat, u32 request_mask, unsigned int query_flags)
|
||||
{
|
||||
struct inode *inode = d_inode(path->dentry);
|
||||
struct afs_vnode *vnode = AFS_FS_I(inode);
|
||||
|
@ -745,7 +745,7 @@ int afs_getattr(const struct path *path, struct kstat *stat,
|
|||
|
||||
do {
|
||||
read_seqbegin_or_lock(&vnode->cb_lock, &seq);
|
||||
generic_fillattr(inode, stat);
|
||||
generic_fillattr(&init_user_ns, inode, stat);
|
||||
if (test_bit(AFS_VNODE_SILLY_DELETED, &vnode->flags) &&
|
||||
stat->nlink > 0)
|
||||
stat->nlink -= 1;
|
||||
|
@ -857,7 +857,8 @@ static const struct afs_operation_ops afs_setattr_operation = {
|
|||
/*
|
||||
* set the attributes of an inode
|
||||
*/
|
||||
int afs_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
int afs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
|
||||
struct iattr *attr)
|
||||
{
|
||||
struct afs_operation *op;
|
||||
struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry));
|
||||
|
|
|
@ -1149,8 +1149,9 @@ extern struct inode *afs_iget(struct afs_operation *, struct afs_vnode_param *);
|
|||
extern struct inode *afs_root_iget(struct super_block *, struct key *);
|
||||
extern bool afs_check_validity(struct afs_vnode *);
|
||||
extern int afs_validate(struct afs_vnode *, struct key *);
|
||||
extern int afs_getattr(const struct path *, struct kstat *, u32, unsigned int);
|
||||
extern int afs_setattr(struct dentry *, struct iattr *);
|
||||
extern int afs_getattr(struct user_namespace *mnt_userns, const struct path *,
|
||||
struct kstat *, u32, unsigned int);
|
||||
extern int afs_setattr(struct user_namespace *mnt_userns, struct dentry *, struct iattr *);
|
||||
extern void afs_evict_inode(struct inode *);
|
||||
extern int afs_drop_inode(struct inode *);
|
||||
|
||||
|
@ -1361,7 +1362,7 @@ extern void afs_zap_permits(struct rcu_head *);
|
|||
extern struct key *afs_request_key(struct afs_cell *);
|
||||
extern struct key *afs_request_key_rcu(struct afs_cell *);
|
||||
extern int afs_check_permit(struct afs_vnode *, struct key *, afs_access_t *);
|
||||
extern int afs_permission(struct inode *, int);
|
||||
extern int afs_permission(struct user_namespace *, struct inode *, int);
|
||||
extern void __exit afs_clean_up_permit_cache(void);
|
||||
|
||||
/*
|
||||
|
|
|
@ -396,7 +396,8 @@ int afs_check_permit(struct afs_vnode *vnode, struct key *key,
|
|||
* - AFS ACLs are attached to directories only, and a file is controlled by its
|
||||
* parent directory's ACL
|
||||
*/
|
||||
int afs_permission(struct inode *inode, int mask)
|
||||
int afs_permission(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
int mask)
|
||||
{
|
||||
struct afs_vnode *vnode = AFS_FS_I(inode);
|
||||
afs_access_t access;
|
||||
|
|
|
@ -120,6 +120,7 @@ static const struct afs_operation_ops afs_store_acl_operation = {
|
|||
* Set a file's AFS3 ACL.
|
||||
*/
|
||||
static int afs_xattr_set_acl(const struct xattr_handler *handler,
|
||||
struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry,
|
||||
struct inode *inode, const char *name,
|
||||
const void *buffer, size_t size, int flags)
|
||||
|
@ -248,6 +249,7 @@ static const struct afs_operation_ops yfs_store_opaque_acl2_operation = {
|
|||
* Set a file's YFS ACL.
|
||||
*/
|
||||
static int afs_xattr_set_yfs(const struct xattr_handler *handler,
|
||||
struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry,
|
||||
struct inode *inode, const char *name,
|
||||
const void *buffer, size_t size, int flags)
|
||||
|
|
126
fs/attr.c
126
fs/attr.c
|
@ -18,27 +18,55 @@
|
|||
#include <linux/evm.h>
|
||||
#include <linux/ima.h>
|
||||
|
||||
static bool chown_ok(const struct inode *inode, kuid_t uid)
|
||||
/**
|
||||
* chown_ok - verify permissions to chown inode
|
||||
* @mnt_userns: user namespace of the mount @inode was found from
|
||||
* @inode: inode to check permissions on
|
||||
* @uid: uid to chown @inode to
|
||||
*
|
||||
* If the inode has been found through an idmapped mount the user namespace of
|
||||
* the vfsmount must be passed through @mnt_userns. This function will then
|
||||
* take care to map the inode according to @mnt_userns before checking
|
||||
* permissions. On non-idmapped mounts or if permission checking is to be
|
||||
* performed on the raw inode simply passs init_user_ns.
|
||||
*/
|
||||
static bool chown_ok(struct user_namespace *mnt_userns,
|
||||
const struct inode *inode,
|
||||
kuid_t uid)
|
||||
{
|
||||
if (uid_eq(current_fsuid(), inode->i_uid) &&
|
||||
uid_eq(uid, inode->i_uid))
|
||||
kuid_t kuid = i_uid_into_mnt(mnt_userns, inode);
|
||||
if (uid_eq(current_fsuid(), kuid) && uid_eq(uid, kuid))
|
||||
return true;
|
||||
if (capable_wrt_inode_uidgid(inode, CAP_CHOWN))
|
||||
if (capable_wrt_inode_uidgid(mnt_userns, inode, CAP_CHOWN))
|
||||
return true;
|
||||
if (uid_eq(inode->i_uid, INVALID_UID) &&
|
||||
if (uid_eq(kuid, INVALID_UID) &&
|
||||
ns_capable(inode->i_sb->s_user_ns, CAP_CHOWN))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool chgrp_ok(const struct inode *inode, kgid_t gid)
|
||||
/**
|
||||
* chgrp_ok - verify permissions to chgrp inode
|
||||
* @mnt_userns: user namespace of the mount @inode was found from
|
||||
* @inode: inode to check permissions on
|
||||
* @gid: gid to chown @inode to
|
||||
*
|
||||
* If the inode has been found through an idmapped mount the user namespace of
|
||||
* the vfsmount must be passed through @mnt_userns. This function will then
|
||||
* take care to map the inode according to @mnt_userns before checking
|
||||
* permissions. On non-idmapped mounts or if permission checking is to be
|
||||
* performed on the raw inode simply passs init_user_ns.
|
||||
*/
|
||||
static bool chgrp_ok(struct user_namespace *mnt_userns,
|
||||
const struct inode *inode, kgid_t gid)
|
||||
{
|
||||
if (uid_eq(current_fsuid(), inode->i_uid) &&
|
||||
(in_group_p(gid) || gid_eq(gid, inode->i_gid)))
|
||||
kgid_t kgid = i_gid_into_mnt(mnt_userns, inode);
|
||||
if (uid_eq(current_fsuid(), i_uid_into_mnt(mnt_userns, inode)) &&
|
||||
(in_group_p(gid) || gid_eq(gid, kgid)))
|
||||
return true;
|
||||
if (capable_wrt_inode_uidgid(inode, CAP_CHOWN))
|
||||
if (capable_wrt_inode_uidgid(mnt_userns, inode, CAP_CHOWN))
|
||||
return true;
|
||||
if (gid_eq(inode->i_gid, INVALID_GID) &&
|
||||
if (gid_eq(kgid, INVALID_GID) &&
|
||||
ns_capable(inode->i_sb->s_user_ns, CAP_CHOWN))
|
||||
return true;
|
||||
return false;
|
||||
|
@ -46,6 +74,7 @@ static bool chgrp_ok(const struct inode *inode, kgid_t gid)
|
|||
|
||||
/**
|
||||
* setattr_prepare - check if attribute changes to a dentry are allowed
|
||||
* @mnt_userns: user namespace of the mount the inode was found from
|
||||
* @dentry: dentry to check
|
||||
* @attr: attributes to change
|
||||
*
|
||||
|
@ -55,10 +84,17 @@ static bool chgrp_ok(const struct inode *inode, kgid_t gid)
|
|||
* SGID bit from mode if user is not allowed to set it. Also file capabilities
|
||||
* and IMA extended attributes are cleared if ATTR_KILL_PRIV is set.
|
||||
*
|
||||
* If the inode has been found through an idmapped mount the user namespace of
|
||||
* the vfsmount must be passed through @mnt_userns. This function will then
|
||||
* take care to map the inode according to @mnt_userns before checking
|
||||
* permissions. On non-idmapped mounts or if permission checking is to be
|
||||
* performed on the raw inode simply passs init_user_ns.
|
||||
*
|
||||
* Should be called as the first thing in ->setattr implementations,
|
||||
* possibly after taking additional locks.
|
||||
*/
|
||||
int setattr_prepare(struct dentry *dentry, struct iattr *attr)
|
||||
int setattr_prepare(struct user_namespace *mnt_userns, struct dentry *dentry,
|
||||
struct iattr *attr)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
unsigned int ia_valid = attr->ia_valid;
|
||||
|
@ -78,27 +114,27 @@ int setattr_prepare(struct dentry *dentry, struct iattr *attr)
|
|||
goto kill_priv;
|
||||
|
||||
/* Make sure a caller can chown. */
|
||||
if ((ia_valid & ATTR_UID) && !chown_ok(inode, attr->ia_uid))
|
||||
if ((ia_valid & ATTR_UID) && !chown_ok(mnt_userns, inode, attr->ia_uid))
|
||||
return -EPERM;
|
||||
|
||||
/* Make sure caller can chgrp. */
|
||||
if ((ia_valid & ATTR_GID) && !chgrp_ok(inode, attr->ia_gid))
|
||||
if ((ia_valid & ATTR_GID) && !chgrp_ok(mnt_userns, inode, attr->ia_gid))
|
||||
return -EPERM;
|
||||
|
||||
/* Make sure a caller can chmod. */
|
||||
if (ia_valid & ATTR_MODE) {
|
||||
if (!inode_owner_or_capable(inode))
|
||||
if (!inode_owner_or_capable(mnt_userns, inode))
|
||||
return -EPERM;
|
||||
/* Also check the setgid bit! */
|
||||
if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
|
||||
inode->i_gid) &&
|
||||
!capable_wrt_inode_uidgid(inode, CAP_FSETID))
|
||||
if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
|
||||
i_gid_into_mnt(mnt_userns, inode)) &&
|
||||
!capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FSETID))
|
||||
attr->ia_mode &= ~S_ISGID;
|
||||
}
|
||||
|
||||
/* Check for setting the inode time. */
|
||||
if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) {
|
||||
if (!inode_owner_or_capable(inode))
|
||||
if (!inode_owner_or_capable(mnt_userns, inode))
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
|
@ -107,7 +143,7 @@ int setattr_prepare(struct dentry *dentry, struct iattr *attr)
|
|||
if (ia_valid & ATTR_KILL_PRIV) {
|
||||
int error;
|
||||
|
||||
error = security_inode_killpriv(dentry);
|
||||
error = security_inode_killpriv(mnt_userns, dentry);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
@ -162,20 +198,33 @@ EXPORT_SYMBOL(inode_newsize_ok);
|
|||
|
||||
/**
|
||||
* setattr_copy - copy simple metadata updates into the generic inode
|
||||
* @mnt_userns: user namespace of the mount the inode was found from
|
||||
* @inode: the inode to be updated
|
||||
* @attr: the new attributes
|
||||
*
|
||||
* setattr_copy must be called with i_mutex held.
|
||||
*
|
||||
* setattr_copy updates the inode's metadata with that specified
|
||||
* in attr. Noticeably missing is inode size update, which is more complex
|
||||
* in attr on idmapped mounts. If file ownership is changed setattr_copy
|
||||
* doesn't map ia_uid and ia_gid. It will asssume the caller has already
|
||||
* provided the intended values. Necessary permission checks to determine
|
||||
* whether or not the S_ISGID property needs to be removed are performed with
|
||||
* the correct idmapped mount permission helpers.
|
||||
* Noticeably missing is inode size update, which is more complex
|
||||
* as it requires pagecache updates.
|
||||
*
|
||||
* If the inode has been found through an idmapped mount the user namespace of
|
||||
* the vfsmount must be passed through @mnt_userns. This function will then
|
||||
* take care to map the inode according to @mnt_userns before checking
|
||||
* permissions. On non-idmapped mounts or if permission checking is to be
|
||||
* performed on the raw inode simply passs init_user_ns.
|
||||
*
|
||||
* The inode is not marked as dirty after this operation. The rationale is
|
||||
* that for "simple" filesystems, the struct inode is the inode storage.
|
||||
* The caller is free to mark the inode dirty afterwards if needed.
|
||||
*/
|
||||
void setattr_copy(struct inode *inode, const struct iattr *attr)
|
||||
void setattr_copy(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
const struct iattr *attr)
|
||||
{
|
||||
unsigned int ia_valid = attr->ia_valid;
|
||||
|
||||
|
@ -191,9 +240,9 @@ void setattr_copy(struct inode *inode, const struct iattr *attr)
|
|||
inode->i_ctime = attr->ia_ctime;
|
||||
if (ia_valid & ATTR_MODE) {
|
||||
umode_t mode = attr->ia_mode;
|
||||
|
||||
if (!in_group_p(inode->i_gid) &&
|
||||
!capable_wrt_inode_uidgid(inode, CAP_FSETID))
|
||||
kgid_t kgid = i_gid_into_mnt(mnt_userns, inode);
|
||||
if (!in_group_p(kgid) &&
|
||||
!capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FSETID))
|
||||
mode &= ~S_ISGID;
|
||||
inode->i_mode = mode;
|
||||
}
|
||||
|
@ -202,6 +251,7 @@ EXPORT_SYMBOL(setattr_copy);
|
|||
|
||||
/**
|
||||
* notify_change - modify attributes of a filesytem object
|
||||
* @mnt_userns: user namespace of the mount the inode was found from
|
||||
* @dentry: object affected
|
||||
* @attr: new attributes
|
||||
* @delegated_inode: returns inode, if the inode is delegated
|
||||
|
@ -214,13 +264,23 @@ EXPORT_SYMBOL(setattr_copy);
|
|||
* retry. Because breaking a delegation may take a long time, the
|
||||
* caller should drop the i_mutex before doing so.
|
||||
*
|
||||
* If file ownership is changed notify_change() doesn't map ia_uid and
|
||||
* ia_gid. It will asssume the caller has already provided the intended values.
|
||||
*
|
||||
* Alternatively, a caller may pass NULL for delegated_inode. This may
|
||||
* be appropriate for callers that expect the underlying filesystem not
|
||||
* to be NFS exported. Also, passing NULL is fine for callers holding
|
||||
* the file open for write, as there can be no conflicting delegation in
|
||||
* that case.
|
||||
*
|
||||
* If the inode has been found through an idmapped mount the user namespace of
|
||||
* the vfsmount must be passed through @mnt_userns. This function will then
|
||||
* take care to map the inode according to @mnt_userns before checking
|
||||
* permissions. On non-idmapped mounts or if permission checking is to be
|
||||
* performed on the raw inode simply passs init_user_ns.
|
||||
*/
|
||||
int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **delegated_inode)
|
||||
int notify_change(struct user_namespace *mnt_userns, struct dentry *dentry,
|
||||
struct iattr *attr, struct inode **delegated_inode)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
umode_t mode = inode->i_mode;
|
||||
|
@ -243,8 +303,8 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
|
|||
if (IS_IMMUTABLE(inode))
|
||||
return -EPERM;
|
||||
|
||||
if (!inode_owner_or_capable(inode)) {
|
||||
error = inode_permission(inode, MAY_WRITE);
|
||||
if (!inode_owner_or_capable(mnt_userns, inode)) {
|
||||
error = inode_permission(mnt_userns, inode, MAY_WRITE);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
@ -320,9 +380,11 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
|
|||
/* Don't allow modifications of files with invalid uids or
|
||||
* gids unless those uids & gids are being made valid.
|
||||
*/
|
||||
if (!(ia_valid & ATTR_UID) && !uid_valid(inode->i_uid))
|
||||
if (!(ia_valid & ATTR_UID) &&
|
||||
!uid_valid(i_uid_into_mnt(mnt_userns, inode)))
|
||||
return -EOVERFLOW;
|
||||
if (!(ia_valid & ATTR_GID) && !gid_valid(inode->i_gid))
|
||||
if (!(ia_valid & ATTR_GID) &&
|
||||
!gid_valid(i_gid_into_mnt(mnt_userns, inode)))
|
||||
return -EOVERFLOW;
|
||||
|
||||
error = security_inode_setattr(dentry, attr);
|
||||
|
@ -333,13 +395,13 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
|
|||
return error;
|
||||
|
||||
if (inode->i_op->setattr)
|
||||
error = inode->i_op->setattr(dentry, attr);
|
||||
error = inode->i_op->setattr(mnt_userns, dentry, attr);
|
||||
else
|
||||
error = simple_setattr(dentry, attr);
|
||||
error = simple_setattr(mnt_userns, dentry, attr);
|
||||
|
||||
if (!error) {
|
||||
fsnotify_change(dentry, ia_valid);
|
||||
ima_inode_post_setattr(dentry);
|
||||
ima_inode_post_setattr(mnt_userns, dentry);
|
||||
evm_inode_post_setattr(dentry, ia_valid);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,10 +10,12 @@
|
|||
|
||||
#include "autofs_i.h"
|
||||
|
||||
static int autofs_dir_symlink(struct inode *, struct dentry *, const char *);
|
||||
static int autofs_dir_symlink(struct user_namespace *, struct inode *,
|
||||
struct dentry *, const char *);
|
||||
static int autofs_dir_unlink(struct inode *, struct dentry *);
|
||||
static int autofs_dir_rmdir(struct inode *, struct dentry *);
|
||||
static int autofs_dir_mkdir(struct inode *, struct dentry *, umode_t);
|
||||
static int autofs_dir_mkdir(struct user_namespace *, struct inode *,
|
||||
struct dentry *, umode_t);
|
||||
static long autofs_root_ioctl(struct file *, unsigned int, unsigned long);
|
||||
#ifdef CONFIG_COMPAT
|
||||
static long autofs_root_compat_ioctl(struct file *,
|
||||
|
@ -524,9 +526,9 @@ static struct dentry *autofs_lookup(struct inode *dir,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int autofs_dir_symlink(struct inode *dir,
|
||||
struct dentry *dentry,
|
||||
const char *symname)
|
||||
static int autofs_dir_symlink(struct user_namespace *mnt_userns,
|
||||
struct inode *dir, struct dentry *dentry,
|
||||
const char *symname)
|
||||
{
|
||||
struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb);
|
||||
struct autofs_info *ino = autofs_dentry_ino(dentry);
|
||||
|
@ -715,8 +717,9 @@ static int autofs_dir_rmdir(struct inode *dir, struct dentry *dentry)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int autofs_dir_mkdir(struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode)
|
||||
static int autofs_dir_mkdir(struct user_namespace *mnt_userns,
|
||||
struct inode *dir, struct dentry *dentry,
|
||||
umode_t mode)
|
||||
{
|
||||
struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb);
|
||||
struct autofs_info *ino = autofs_dentry_ino(dentry);
|
||||
|
|
|
@ -27,8 +27,9 @@ static const struct file_operations bad_file_ops =
|
|||
.open = bad_file_open,
|
||||
};
|
||||
|
||||
static int bad_inode_create (struct inode *dir, struct dentry *dentry,
|
||||
umode_t mode, bool excl)
|
||||
static int bad_inode_create(struct user_namespace *mnt_userns,
|
||||
struct inode *dir, struct dentry *dentry,
|
||||
umode_t mode, bool excl)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -50,14 +51,15 @@ static int bad_inode_unlink(struct inode *dir, struct dentry *dentry)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
static int bad_inode_symlink (struct inode *dir, struct dentry *dentry,
|
||||
const char *symname)
|
||||
static int bad_inode_symlink(struct user_namespace *mnt_userns,
|
||||
struct inode *dir, struct dentry *dentry,
|
||||
const char *symname)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int bad_inode_mkdir(struct inode *dir, struct dentry *dentry,
|
||||
umode_t mode)
|
||||
static int bad_inode_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -67,13 +69,14 @@ static int bad_inode_rmdir (struct inode *dir, struct dentry *dentry)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
static int bad_inode_mknod (struct inode *dir, struct dentry *dentry,
|
||||
umode_t mode, dev_t rdev)
|
||||
static int bad_inode_mknod(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode, dev_t rdev)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int bad_inode_rename2(struct inode *old_dir, struct dentry *old_dentry,
|
||||
static int bad_inode_rename2(struct user_namespace *mnt_userns,
|
||||
struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
unsigned int flags)
|
||||
{
|
||||
|
@ -86,18 +89,21 @@ static int bad_inode_readlink(struct dentry *dentry, char __user *buffer,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
static int bad_inode_permission(struct inode *inode, int mask)
|
||||
static int bad_inode_permission(struct user_namespace *mnt_userns,
|
||||
struct inode *inode, int mask)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int bad_inode_getattr(const struct path *path, struct kstat *stat,
|
||||
static int bad_inode_getattr(struct user_namespace *mnt_userns,
|
||||
const struct path *path, struct kstat *stat,
|
||||
u32 request_mask, unsigned int query_flags)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int bad_inode_setattr(struct dentry *direntry, struct iattr *attrs)
|
||||
static int bad_inode_setattr(struct user_namespace *mnt_userns,
|
||||
struct dentry *direntry, struct iattr *attrs)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -140,13 +146,15 @@ static int bad_inode_atomic_open(struct inode *inode, struct dentry *dentry,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
static int bad_inode_tmpfile(struct inode *inode, struct dentry *dentry,
|
||||
static int bad_inode_tmpfile(struct user_namespace *mnt_userns,
|
||||
struct inode *inode, struct dentry *dentry,
|
||||
umode_t mode)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int bad_inode_set_acl(struct inode *inode, struct posix_acl *acl,
|
||||
static int bad_inode_set_acl(struct user_namespace *mnt_userns,
|
||||
struct inode *inode, struct posix_acl *acl,
|
||||
int type)
|
||||
{
|
||||
return -EIO;
|
||||
|
|
12
fs/bfs/dir.c
12
fs/bfs/dir.c
|
@ -75,8 +75,8 @@ const struct file_operations bfs_dir_operations = {
|
|||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
||||
static int bfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
bool excl)
|
||||
static int bfs_create(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode, bool excl)
|
||||
{
|
||||
int err;
|
||||
struct inode *inode;
|
||||
|
@ -96,7 +96,7 @@ static int bfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
|||
}
|
||||
set_bit(ino, info->si_imap);
|
||||
info->si_freei--;
|
||||
inode_init_owner(inode, dir, mode);
|
||||
inode_init_owner(&init_user_ns, inode, dir, mode);
|
||||
inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
|
||||
inode->i_blocks = 0;
|
||||
inode->i_op = &bfs_file_inops;
|
||||
|
@ -199,9 +199,9 @@ static int bfs_unlink(struct inode *dir, struct dentry *dentry)
|
|||
return error;
|
||||
}
|
||||
|
||||
static int bfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
unsigned int flags)
|
||||
static int bfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
|
||||
struct dentry *old_dentry, struct inode *new_dir,
|
||||
struct dentry *new_dentry, unsigned int flags)
|
||||
{
|
||||
struct inode *old_inode, *new_inode;
|
||||
struct buffer_head *old_bh, *new_bh;
|
||||
|
|
|
@ -107,13 +107,15 @@ static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
||||
int btrfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
struct posix_acl *acl, int type)
|
||||
{
|
||||
int ret;
|
||||
umode_t old_mode = inode->i_mode;
|
||||
|
||||
if (type == ACL_TYPE_ACCESS && acl) {
|
||||
ret = posix_acl_update_mode(inode, &inode->i_mode, &acl);
|
||||
ret = posix_acl_update_mode(&init_user_ns, inode,
|
||||
&inode->i_mode, &acl);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -3635,7 +3635,8 @@ static inline int __btrfs_fs_compat_ro(struct btrfs_fs_info *fs_info, u64 flag)
|
|||
/* acl.c */
|
||||
#ifdef CONFIG_BTRFS_FS_POSIX_ACL
|
||||
struct posix_acl *btrfs_get_acl(struct inode *inode, int type);
|
||||
int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
|
||||
int btrfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
struct posix_acl *acl, int type);
|
||||
int btrfs_init_acl(struct btrfs_trans_handle *trans,
|
||||
struct inode *inode, struct inode *dir);
|
||||
#else
|
||||
|
|
|
@ -5212,7 +5212,8 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
static int btrfs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
|
||||
struct iattr *attr)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
|
@ -5221,7 +5222,7 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
|
|||
if (btrfs_root_readonly(root))
|
||||
return -EROFS;
|
||||
|
||||
err = setattr_prepare(dentry, attr);
|
||||
err = setattr_prepare(&init_user_ns, dentry, attr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -5232,12 +5233,13 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
|
|||
}
|
||||
|
||||
if (attr->ia_valid) {
|
||||
setattr_copy(inode, attr);
|
||||
setattr_copy(&init_user_ns, inode, attr);
|
||||
inode_inc_iversion(inode);
|
||||
err = btrfs_dirty_inode(inode);
|
||||
|
||||
if (!err && attr->ia_valid & ATTR_MODE)
|
||||
err = posix_acl_chmod(inode, inode->i_mode);
|
||||
err = posix_acl_chmod(&init_user_ns, inode,
|
||||
inode->i_mode);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -6357,7 +6359,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
|
|||
if (ret != 0)
|
||||
goto fail_unlock;
|
||||
|
||||
inode_init_owner(inode, dir, mode);
|
||||
inode_init_owner(&init_user_ns, inode, dir, mode);
|
||||
inode_set_bytes(inode, 0);
|
||||
|
||||
inode->i_mtime = current_time(inode);
|
||||
|
@ -6518,8 +6520,8 @@ static int btrfs_add_nondir(struct btrfs_trans_handle *trans,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
|
||||
umode_t mode, dev_t rdev)
|
||||
static int btrfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode, dev_t rdev)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
|
||||
struct btrfs_trans_handle *trans;
|
||||
|
@ -6582,8 +6584,8 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int btrfs_create(struct inode *dir, struct dentry *dentry,
|
||||
umode_t mode, bool excl)
|
||||
static int btrfs_create(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode, bool excl)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
|
||||
struct btrfs_trans_handle *trans;
|
||||
|
@ -6727,7 +6729,8 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
static int btrfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
|
||||
struct inode *inode = NULL;
|
||||
|
@ -9017,7 +9020,8 @@ int __init btrfs_init_cachep(void)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int btrfs_getattr(const struct path *path, struct kstat *stat,
|
||||
static int btrfs_getattr(struct user_namespace *mnt_userns,
|
||||
const struct path *path, struct kstat *stat,
|
||||
u32 request_mask, unsigned int flags)
|
||||
{
|
||||
u64 delalloc_bytes;
|
||||
|
@ -9043,7 +9047,7 @@ static int btrfs_getattr(const struct path *path, struct kstat *stat,
|
|||
STATX_ATTR_IMMUTABLE |
|
||||
STATX_ATTR_NODUMP);
|
||||
|
||||
generic_fillattr(inode, stat);
|
||||
generic_fillattr(&init_user_ns, inode, stat);
|
||||
stat->dev = BTRFS_I(inode)->root->anon_dev;
|
||||
|
||||
spin_lock(&BTRFS_I(inode)->lock);
|
||||
|
@ -9534,9 +9538,9 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int btrfs_rename2(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
unsigned int flags)
|
||||
static int btrfs_rename2(struct user_namespace *mnt_userns, struct inode *old_dir,
|
||||
struct dentry *old_dentry, struct inode *new_dir,
|
||||
struct dentry *new_dentry, unsigned int flags)
|
||||
{
|
||||
if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
|
||||
return -EINVAL;
|
||||
|
@ -9744,8 +9748,8 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, long nr,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
|
||||
const char *symname)
|
||||
static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, const char *symname)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
|
||||
struct btrfs_trans_handle *trans;
|
||||
|
@ -10079,7 +10083,8 @@ static int btrfs_set_page_dirty(struct page *page)
|
|||
return __set_page_dirty_nobuffers(page);
|
||||
}
|
||||
|
||||
static int btrfs_permission(struct inode *inode, int mask)
|
||||
static int btrfs_permission(struct user_namespace *mnt_userns,
|
||||
struct inode *inode, int mask)
|
||||
{
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
umode_t mode = inode->i_mode;
|
||||
|
@ -10091,10 +10096,11 @@ static int btrfs_permission(struct inode *inode, int mask)
|
|||
if (BTRFS_I(inode)->flags & BTRFS_INODE_READONLY)
|
||||
return -EACCES;
|
||||
}
|
||||
return generic_permission(inode, mask);
|
||||
return generic_permission(&init_user_ns, inode, mask);
|
||||
}
|
||||
|
||||
static int btrfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
|
||||
struct btrfs_trans_handle *trans;
|
||||
|
|
|
@ -213,7 +213,7 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
|
|||
const char *comp = NULL;
|
||||
u32 binode_flags;
|
||||
|
||||
if (!inode_owner_or_capable(inode))
|
||||
if (!inode_owner_or_capable(&init_user_ns, inode))
|
||||
return -EPERM;
|
||||
|
||||
if (btrfs_root_readonly(root))
|
||||
|
@ -429,7 +429,7 @@ static int btrfs_ioctl_fssetxattr(struct file *file, void __user *arg)
|
|||
unsigned old_i_flags;
|
||||
int ret = 0;
|
||||
|
||||
if (!inode_owner_or_capable(inode))
|
||||
if (!inode_owner_or_capable(&init_user_ns, inode))
|
||||
return -EPERM;
|
||||
|
||||
if (btrfs_root_readonly(root))
|
||||
|
@ -925,13 +925,14 @@ static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir)
|
|||
BUG_ON(d_inode(victim->d_parent) != dir);
|
||||
audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
|
||||
|
||||
error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
|
||||
error = inode_permission(&init_user_ns, dir, MAY_WRITE | MAY_EXEC);
|
||||
if (error)
|
||||
return error;
|
||||
if (IS_APPEND(dir))
|
||||
return -EPERM;
|
||||
if (check_sticky(dir, d_inode(victim)) || IS_APPEND(d_inode(victim)) ||
|
||||
IS_IMMUTABLE(d_inode(victim)) || IS_SWAPFILE(d_inode(victim)))
|
||||
if (check_sticky(&init_user_ns, dir, d_inode(victim)) ||
|
||||
IS_APPEND(d_inode(victim)) || IS_IMMUTABLE(d_inode(victim)) ||
|
||||
IS_SWAPFILE(d_inode(victim)))
|
||||
return -EPERM;
|
||||
if (isdir) {
|
||||
if (!d_is_dir(victim))
|
||||
|
@ -954,7 +955,7 @@ static inline int btrfs_may_create(struct inode *dir, struct dentry *child)
|
|||
return -EEXIST;
|
||||
if (IS_DEADDIR(dir))
|
||||
return -ENOENT;
|
||||
return inode_permission(dir, MAY_WRITE | MAY_EXEC);
|
||||
return inode_permission(&init_user_ns, dir, MAY_WRITE | MAY_EXEC);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1871,7 +1872,7 @@ static noinline int __btrfs_ioctl_snap_create(struct file *file,
|
|||
btrfs_info(BTRFS_I(file_inode(file))->root->fs_info,
|
||||
"Snapshot src from another FS");
|
||||
ret = -EXDEV;
|
||||
} else if (!inode_owner_or_capable(src_inode)) {
|
||||
} else if (!inode_owner_or_capable(&init_user_ns, src_inode)) {
|
||||
/*
|
||||
* Subvolume creation is not restricted, but snapshots
|
||||
* are limited to own subvolumes only
|
||||
|
@ -1991,7 +1992,7 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file,
|
|||
u64 flags;
|
||||
int ret = 0;
|
||||
|
||||
if (!inode_owner_or_capable(inode))
|
||||
if (!inode_owner_or_capable(&init_user_ns, inode))
|
||||
return -EPERM;
|
||||
|
||||
ret = mnt_want_write_file(file);
|
||||
|
@ -2547,7 +2548,8 @@ static int btrfs_search_path_in_tree_user(struct inode *inode,
|
|||
ret = PTR_ERR(temp_inode);
|
||||
goto out_put;
|
||||
}
|
||||
ret = inode_permission(temp_inode, MAY_READ | MAY_EXEC);
|
||||
ret = inode_permission(&init_user_ns, temp_inode,
|
||||
MAY_READ | MAY_EXEC);
|
||||
iput(temp_inode);
|
||||
if (ret) {
|
||||
ret = -EACCES;
|
||||
|
@ -3077,7 +3079,8 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
|
|||
if (root == dest)
|
||||
goto out_dput;
|
||||
|
||||
err = inode_permission(inode, MAY_WRITE | MAY_EXEC);
|
||||
err = inode_permission(&init_user_ns, inode,
|
||||
MAY_WRITE | MAY_EXEC);
|
||||
if (err)
|
||||
goto out_dput;
|
||||
}
|
||||
|
@ -3148,7 +3151,7 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
|
|||
* running and allows defrag on files open in read-only mode.
|
||||
*/
|
||||
if (!capable(CAP_SYS_ADMIN) &&
|
||||
inode_permission(inode, MAY_WRITE)) {
|
||||
inode_permission(&init_user_ns, inode, MAY_WRITE)) {
|
||||
ret = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
@ -4460,7 +4463,7 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file,
|
|||
int ret = 0;
|
||||
int received_uuid_changed;
|
||||
|
||||
if (!inode_owner_or_capable(inode))
|
||||
if (!inode_owner_or_capable(&init_user_ns, inode))
|
||||
return -EPERM;
|
||||
|
||||
ret = mnt_want_write_file(file);
|
||||
|
|
|
@ -62,7 +62,7 @@ struct inode *btrfs_new_test_inode(void)
|
|||
BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY;
|
||||
BTRFS_I(inode)->location.objectid = BTRFS_FIRST_FREE_OBJECTID;
|
||||
BTRFS_I(inode)->location.offset = 0;
|
||||
inode_init_owner(inode, NULL, S_IFREG);
|
||||
inode_init_owner(&init_user_ns, inode, NULL, S_IFREG);
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
|
|
@ -362,6 +362,7 @@ static int btrfs_xattr_handler_get(const struct xattr_handler *handler,
|
|||
}
|
||||
|
||||
static int btrfs_xattr_handler_set(const struct xattr_handler *handler,
|
||||
struct user_namespace *mnt_userns,
|
||||
struct dentry *unused, struct inode *inode,
|
||||
const char *name, const void *buffer,
|
||||
size_t size, int flags)
|
||||
|
@ -371,6 +372,7 @@ static int btrfs_xattr_handler_set(const struct xattr_handler *handler,
|
|||
}
|
||||
|
||||
static int btrfs_xattr_handler_set_prop(const struct xattr_handler *handler,
|
||||
struct user_namespace *mnt_userns,
|
||||
struct dentry *unused, struct inode *inode,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
|
|
|
@ -470,14 +470,14 @@ static int cachefiles_attr_changed(struct fscache_object *_object)
|
|||
_debug("discard tail %llx", oi_size);
|
||||
newattrs.ia_valid = ATTR_SIZE;
|
||||
newattrs.ia_size = oi_size & PAGE_MASK;
|
||||
ret = notify_change(object->backer, &newattrs, NULL);
|
||||
ret = notify_change(&init_user_ns, object->backer, &newattrs, NULL);
|
||||
if (ret < 0)
|
||||
goto truncate_failed;
|
||||
}
|
||||
|
||||
newattrs.ia_valid = ATTR_SIZE;
|
||||
newattrs.ia_size = ni_size;
|
||||
ret = notify_change(object->backer, &newattrs, NULL);
|
||||
ret = notify_change(&init_user_ns, object->backer, &newattrs, NULL);
|
||||
|
||||
truncate_failed:
|
||||
inode_unlock(d_inode(object->backer));
|
||||
|
|
|
@ -311,7 +311,8 @@ static int cachefiles_bury_object(struct cachefiles_cache *cache,
|
|||
cachefiles_io_error(cache, "Unlink security error");
|
||||
} else {
|
||||
trace_cachefiles_unlink(object, rep, why);
|
||||
ret = vfs_unlink(d_inode(dir), rep, NULL);
|
||||
ret = vfs_unlink(&init_user_ns, d_inode(dir), rep,
|
||||
NULL);
|
||||
|
||||
if (preemptive)
|
||||
cachefiles_mark_object_buried(cache, rep, why);
|
||||
|
@ -412,9 +413,16 @@ static int cachefiles_bury_object(struct cachefiles_cache *cache,
|
|||
if (ret < 0) {
|
||||
cachefiles_io_error(cache, "Rename security error %d", ret);
|
||||
} else {
|
||||
struct renamedata rd = {
|
||||
.old_mnt_userns = &init_user_ns,
|
||||
.old_dir = d_inode(dir),
|
||||
.old_dentry = rep,
|
||||
.new_mnt_userns = &init_user_ns,
|
||||
.new_dir = d_inode(cache->graveyard),
|
||||
.new_dentry = grave,
|
||||
};
|
||||
trace_cachefiles_rename(object, rep, grave, why);
|
||||
ret = vfs_rename(d_inode(dir), rep,
|
||||
d_inode(cache->graveyard), grave, NULL, 0);
|
||||
ret = vfs_rename(&rd);
|
||||
if (ret != 0 && ret != -ENOMEM)
|
||||
cachefiles_io_error(cache,
|
||||
"Rename failed with error %d", ret);
|
||||
|
@ -561,7 +569,7 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent,
|
|||
if (ret < 0)
|
||||
goto create_error;
|
||||
start = jiffies;
|
||||
ret = vfs_mkdir(d_inode(dir), next, 0);
|
||||
ret = vfs_mkdir(&init_user_ns, d_inode(dir), next, 0);
|
||||
cachefiles_hist(cachefiles_mkdir_histogram, start);
|
||||
if (!key)
|
||||
trace_cachefiles_mkdir(object, next, ret);
|
||||
|
@ -597,7 +605,8 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent,
|
|||
if (ret < 0)
|
||||
goto create_error;
|
||||
start = jiffies;
|
||||
ret = vfs_create(d_inode(dir), next, S_IFREG, true);
|
||||
ret = vfs_create(&init_user_ns, d_inode(dir), next,
|
||||
S_IFREG, true);
|
||||
cachefiles_hist(cachefiles_create_histogram, start);
|
||||
trace_cachefiles_create(object, next, ret);
|
||||
if (ret < 0)
|
||||
|
@ -791,7 +800,7 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
|
|||
ret = security_path_mkdir(&path, subdir, 0700);
|
||||
if (ret < 0)
|
||||
goto mkdir_error;
|
||||
ret = vfs_mkdir(d_inode(dir), subdir, 0700);
|
||||
ret = vfs_mkdir(&init_user_ns, d_inode(dir), subdir, 0700);
|
||||
if (ret < 0)
|
||||
goto mkdir_error;
|
||||
|
||||
|
|
|
@ -39,8 +39,8 @@ int cachefiles_check_object_type(struct cachefiles_object *object)
|
|||
_enter("%p{%s}", object, type);
|
||||
|
||||
/* attempt to install a type label directly */
|
||||
ret = vfs_setxattr(dentry, cachefiles_xattr_cache, type, 2,
|
||||
XATTR_CREATE);
|
||||
ret = vfs_setxattr(&init_user_ns, dentry, cachefiles_xattr_cache, type,
|
||||
2, XATTR_CREATE);
|
||||
if (ret == 0) {
|
||||
_debug("SET"); /* we succeeded */
|
||||
goto error;
|
||||
|
@ -54,7 +54,8 @@ int cachefiles_check_object_type(struct cachefiles_object *object)
|
|||
}
|
||||
|
||||
/* read the current type label */
|
||||
ret = vfs_getxattr(dentry, cachefiles_xattr_cache, xtype, 3);
|
||||
ret = vfs_getxattr(&init_user_ns, dentry, cachefiles_xattr_cache, xtype,
|
||||
3);
|
||||
if (ret < 0) {
|
||||
if (ret == -ERANGE)
|
||||
goto bad_type_length;
|
||||
|
@ -110,9 +111,8 @@ int cachefiles_set_object_xattr(struct cachefiles_object *object,
|
|||
_debug("SET #%u", auxdata->len);
|
||||
|
||||
clear_bit(FSCACHE_COOKIE_AUX_UPDATED, &object->fscache.cookie->flags);
|
||||
ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
|
||||
&auxdata->type, auxdata->len,
|
||||
XATTR_CREATE);
|
||||
ret = vfs_setxattr(&init_user_ns, dentry, cachefiles_xattr_cache,
|
||||
&auxdata->type, auxdata->len, XATTR_CREATE);
|
||||
if (ret < 0 && ret != -ENOMEM)
|
||||
cachefiles_io_error_obj(
|
||||
object,
|
||||
|
@ -140,9 +140,8 @@ int cachefiles_update_object_xattr(struct cachefiles_object *object,
|
|||
_debug("SET #%u", auxdata->len);
|
||||
|
||||
clear_bit(FSCACHE_COOKIE_AUX_UPDATED, &object->fscache.cookie->flags);
|
||||
ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
|
||||
&auxdata->type, auxdata->len,
|
||||
XATTR_REPLACE);
|
||||
ret = vfs_setxattr(&init_user_ns, dentry, cachefiles_xattr_cache,
|
||||
&auxdata->type, auxdata->len, XATTR_REPLACE);
|
||||
if (ret < 0 && ret != -ENOMEM)
|
||||
cachefiles_io_error_obj(
|
||||
object,
|
||||
|
@ -171,7 +170,7 @@ int cachefiles_check_auxdata(struct cachefiles_object *object)
|
|||
if (!auxbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
xlen = vfs_getxattr(dentry, cachefiles_xattr_cache,
|
||||
xlen = vfs_getxattr(&init_user_ns, dentry, cachefiles_xattr_cache,
|
||||
&auxbuf->type, 512 + 1);
|
||||
ret = -ESTALE;
|
||||
if (xlen < 1 ||
|
||||
|
@ -213,7 +212,7 @@ int cachefiles_check_object_xattr(struct cachefiles_object *object,
|
|||
}
|
||||
|
||||
/* read the current type label */
|
||||
ret = vfs_getxattr(dentry, cachefiles_xattr_cache,
|
||||
ret = vfs_getxattr(&init_user_ns, dentry, cachefiles_xattr_cache,
|
||||
&auxbuf->type, 512 + 1);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENODATA)
|
||||
|
@ -270,9 +269,9 @@ int cachefiles_check_object_xattr(struct cachefiles_object *object,
|
|||
}
|
||||
|
||||
/* update the current label */
|
||||
ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
|
||||
&auxdata->type, auxdata->len,
|
||||
XATTR_REPLACE);
|
||||
ret = vfs_setxattr(&init_user_ns, dentry,
|
||||
cachefiles_xattr_cache, &auxdata->type,
|
||||
auxdata->len, XATTR_REPLACE);
|
||||
if (ret < 0) {
|
||||
cachefiles_io_error_obj(object,
|
||||
"Can't update xattr on %lu"
|
||||
|
@ -309,7 +308,7 @@ int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = vfs_removexattr(dentry, cachefiles_xattr_cache);
|
||||
ret = vfs_removexattr(&init_user_ns, dentry, cachefiles_xattr_cache);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENOENT || ret == -ENODATA)
|
||||
ret = 0;
|
||||
|
|
|
@ -82,7 +82,8 @@ struct posix_acl *ceph_get_acl(struct inode *inode, int type)
|
|||
return acl;
|
||||
}
|
||||
|
||||
int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
||||
int ceph_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
struct posix_acl *acl, int type)
|
||||
{
|
||||
int ret = 0, size = 0;
|
||||
const char *name = NULL;
|
||||
|
@ -100,7 +101,8 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
|||
case ACL_TYPE_ACCESS:
|
||||
name = XATTR_NAME_POSIX_ACL_ACCESS;
|
||||
if (acl) {
|
||||
ret = posix_acl_update_mode(inode, &new_mode, &acl);
|
||||
ret = posix_acl_update_mode(&init_user_ns, inode,
|
||||
&new_mode, &acl);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -823,8 +823,8 @@ int ceph_handle_notrace_create(struct inode *dir, struct dentry *dentry)
|
|||
return PTR_ERR(result);
|
||||
}
|
||||
|
||||
static int ceph_mknod(struct inode *dir, struct dentry *dentry,
|
||||
umode_t mode, dev_t rdev)
|
||||
static int ceph_mknod(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode, dev_t rdev)
|
||||
{
|
||||
struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(dir->i_sb);
|
||||
struct ceph_mds_request *req;
|
||||
|
@ -878,14 +878,14 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int ceph_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
bool excl)
|
||||
static int ceph_create(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode, bool excl)
|
||||
{
|
||||
return ceph_mknod(dir, dentry, mode, 0);
|
||||
return ceph_mknod(mnt_userns, dir, dentry, mode, 0);
|
||||
}
|
||||
|
||||
static int ceph_symlink(struct inode *dir, struct dentry *dentry,
|
||||
const char *dest)
|
||||
static int ceph_symlink(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, const char *dest)
|
||||
{
|
||||
struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(dir->i_sb);
|
||||
struct ceph_mds_request *req;
|
||||
|
@ -937,7 +937,8 @@ static int ceph_symlink(struct inode *dir, struct dentry *dentry,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
static int ceph_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode)
|
||||
{
|
||||
struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(dir->i_sb);
|
||||
struct ceph_mds_request *req;
|
||||
|
@ -1183,9 +1184,9 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
unsigned int flags)
|
||||
static int ceph_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
|
||||
struct dentry *old_dentry, struct inode *new_dir,
|
||||
struct dentry *new_dentry, unsigned int flags)
|
||||
{
|
||||
struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(old_dir->i_sb);
|
||||
struct ceph_mds_request *req;
|
||||
|
|
|
@ -2201,7 +2201,8 @@ int __ceph_setattr(struct inode *inode, struct iattr *attr)
|
|||
/*
|
||||
* setattr
|
||||
*/
|
||||
int ceph_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
int ceph_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
|
||||
struct iattr *attr)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
|
||||
|
@ -2210,7 +2211,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
|
|||
if (ceph_snap(inode) != CEPH_NOSNAP)
|
||||
return -EROFS;
|
||||
|
||||
err = setattr_prepare(dentry, attr);
|
||||
err = setattr_prepare(&init_user_ns, dentry, attr);
|
||||
if (err != 0)
|
||||
return err;
|
||||
|
||||
|
@ -2225,7 +2226,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
|
|||
err = __ceph_setattr(inode, attr);
|
||||
|
||||
if (err >= 0 && (attr->ia_valid & ATTR_MODE))
|
||||
err = posix_acl_chmod(inode, attr->ia_mode);
|
||||
err = posix_acl_chmod(&init_user_ns, inode, attr->ia_mode);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -2284,7 +2285,8 @@ int __ceph_do_getattr(struct inode *inode, struct page *locked_page,
|
|||
* Check inode permissions. We verify we have a valid value for
|
||||
* the AUTH cap, then call the generic handler.
|
||||
*/
|
||||
int ceph_permission(struct inode *inode, int mask)
|
||||
int ceph_permission(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
int mask)
|
||||
{
|
||||
int err;
|
||||
|
||||
|
@ -2294,7 +2296,7 @@ int ceph_permission(struct inode *inode, int mask)
|
|||
err = ceph_do_getattr(inode, CEPH_CAP_AUTH_SHARED, false);
|
||||
|
||||
if (!err)
|
||||
err = generic_permission(inode, mask);
|
||||
err = generic_permission(&init_user_ns, inode, mask);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -2331,8 +2333,8 @@ static int statx_to_caps(u32 want, umode_t mode)
|
|||
* Get all the attributes. If we have sufficient caps for the requested attrs,
|
||||
* then we can avoid talking to the MDS at all.
|
||||
*/
|
||||
int ceph_getattr(const struct path *path, struct kstat *stat,
|
||||
u32 request_mask, unsigned int flags)
|
||||
int ceph_getattr(struct user_namespace *mnt_userns, const struct path *path,
|
||||
struct kstat *stat, u32 request_mask, unsigned int flags)
|
||||
{
|
||||
struct inode *inode = d_inode(path->dentry);
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
|
@ -2348,7 +2350,7 @@ int ceph_getattr(const struct path *path, struct kstat *stat,
|
|||
return err;
|
||||
}
|
||||
|
||||
generic_fillattr(inode, stat);
|
||||
generic_fillattr(&init_user_ns, inode, stat);
|
||||
stat->ino = ceph_present_inode(inode);
|
||||
|
||||
/*
|
||||
|
|
|
@ -1000,10 +1000,13 @@ static inline int ceph_do_getattr(struct inode *inode, int mask, bool force)
|
|||
{
|
||||
return __ceph_do_getattr(inode, NULL, mask, force);
|
||||
}
|
||||
extern int ceph_permission(struct inode *inode, int mask);
|
||||
extern int ceph_permission(struct user_namespace *mnt_userns,
|
||||
struct inode *inode, int mask);
|
||||
extern int __ceph_setattr(struct inode *inode, struct iattr *attr);
|
||||
extern int ceph_setattr(struct dentry *dentry, struct iattr *attr);
|
||||
extern int ceph_getattr(const struct path *path, struct kstat *stat,
|
||||
extern int ceph_setattr(struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry, struct iattr *attr);
|
||||
extern int ceph_getattr(struct user_namespace *mnt_userns,
|
||||
const struct path *path, struct kstat *stat,
|
||||
u32 request_mask, unsigned int flags);
|
||||
|
||||
/* xattr.c */
|
||||
|
@ -1064,7 +1067,8 @@ void ceph_release_acl_sec_ctx(struct ceph_acl_sec_ctx *as_ctx);
|
|||
#ifdef CONFIG_CEPH_FS_POSIX_ACL
|
||||
|
||||
struct posix_acl *ceph_get_acl(struct inode *, int);
|
||||
int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type);
|
||||
int ceph_set_acl(struct user_namespace *mnt_userns,
|
||||
struct inode *inode, struct posix_acl *acl, int type);
|
||||
int ceph_pre_init_acls(struct inode *dir, umode_t *mode,
|
||||
struct ceph_acl_sec_ctx *as_ctx);
|
||||
void ceph_init_inode_acls(struct inode *inode,
|
||||
|
|
|
@ -1238,6 +1238,7 @@ static int ceph_get_xattr_handler(const struct xattr_handler *handler,
|
|||
}
|
||||
|
||||
static int ceph_set_xattr_handler(const struct xattr_handler *handler,
|
||||
struct user_namespace *mnt_userns,
|
||||
struct dentry *unused, struct inode *inode,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
|
|
|
@ -305,7 +305,8 @@ static long cifs_fallocate(struct file *file, int mode, loff_t off, loff_t len)
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int cifs_permission(struct inode *inode, int mask)
|
||||
static int cifs_permission(struct user_namespace *mnt_userns,
|
||||
struct inode *inode, int mask)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
|
||||
|
@ -320,7 +321,7 @@ static int cifs_permission(struct inode *inode, int mask)
|
|||
on the client (above and beyond ACL on servers) for
|
||||
servers which do not support setting and viewing mode bits,
|
||||
so allowing client to check permissions is useful */
|
||||
return generic_permission(inode, mask);
|
||||
return generic_permission(&init_user_ns, inode, mask);
|
||||
}
|
||||
|
||||
static struct kmem_cache *cifs_inode_cachep;
|
||||
|
|
|
@ -62,19 +62,22 @@ extern void cifs_sb_deactive(struct super_block *sb);
|
|||
/* Functions related to inodes */
|
||||
extern const struct inode_operations cifs_dir_inode_ops;
|
||||
extern struct inode *cifs_root_iget(struct super_block *);
|
||||
extern int cifs_create(struct inode *, struct dentry *, umode_t,
|
||||
bool excl);
|
||||
extern int cifs_create(struct user_namespace *, struct inode *,
|
||||
struct dentry *, umode_t, bool excl);
|
||||
extern int cifs_atomic_open(struct inode *, struct dentry *,
|
||||
struct file *, unsigned, umode_t);
|
||||
extern struct dentry *cifs_lookup(struct inode *, struct dentry *,
|
||||
unsigned int);
|
||||
extern int cifs_unlink(struct inode *dir, struct dentry *dentry);
|
||||
extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *);
|
||||
extern int cifs_mknod(struct inode *, struct dentry *, umode_t, dev_t);
|
||||
extern int cifs_mkdir(struct inode *, struct dentry *, umode_t);
|
||||
extern int cifs_mknod(struct user_namespace *, struct inode *, struct dentry *,
|
||||
umode_t, dev_t);
|
||||
extern int cifs_mkdir(struct user_namespace *, struct inode *, struct dentry *,
|
||||
umode_t);
|
||||
extern int cifs_rmdir(struct inode *, struct dentry *);
|
||||
extern int cifs_rename2(struct inode *, struct dentry *, struct inode *,
|
||||
struct dentry *, unsigned int);
|
||||
extern int cifs_rename2(struct user_namespace *, struct inode *,
|
||||
struct dentry *, struct inode *, struct dentry *,
|
||||
unsigned int);
|
||||
extern int cifs_revalidate_file_attr(struct file *filp);
|
||||
extern int cifs_revalidate_dentry_attr(struct dentry *);
|
||||
extern int cifs_revalidate_file(struct file *filp);
|
||||
|
@ -82,8 +85,10 @@ extern int cifs_revalidate_dentry(struct dentry *);
|
|||
extern int cifs_invalidate_mapping(struct inode *inode);
|
||||
extern int cifs_revalidate_mapping(struct inode *inode);
|
||||
extern int cifs_zap_mapping(struct inode *inode);
|
||||
extern int cifs_getattr(const struct path *, struct kstat *, u32, unsigned int);
|
||||
extern int cifs_setattr(struct dentry *, struct iattr *);
|
||||
extern int cifs_getattr(struct user_namespace *, const struct path *,
|
||||
struct kstat *, u32, unsigned int);
|
||||
extern int cifs_setattr(struct user_namespace *, struct dentry *,
|
||||
struct iattr *);
|
||||
extern int cifs_fiemap(struct inode *, struct fiemap_extent_info *, u64 start,
|
||||
u64 len);
|
||||
|
||||
|
@ -132,8 +137,8 @@ extern struct vfsmount *cifs_dfs_d_automount(struct path *path);
|
|||
/* Functions related to symlinks */
|
||||
extern const char *cifs_get_link(struct dentry *, struct inode *,
|
||||
struct delayed_call *);
|
||||
extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
|
||||
const char *symname);
|
||||
extern int cifs_symlink(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
struct dentry *direntry, const char *symname);
|
||||
|
||||
#ifdef CONFIG_CIFS_XATTR
|
||||
extern const struct xattr_handler *cifs_xattr_handlers[];
|
||||
|
|
|
@ -567,8 +567,8 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
|
|||
return rc;
|
||||
}
|
||||
|
||||
int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
|
||||
bool excl)
|
||||
int cifs_create(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
struct dentry *direntry, umode_t mode, bool excl)
|
||||
{
|
||||
int rc;
|
||||
unsigned int xid = get_xid();
|
||||
|
@ -611,8 +611,8 @@ int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
|
|||
return rc;
|
||||
}
|
||||
|
||||
int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
|
||||
dev_t device_number)
|
||||
int cifs_mknod(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
struct dentry *direntry, umode_t mode, dev_t device_number)
|
||||
{
|
||||
int rc = -EPERM;
|
||||
unsigned int xid;
|
||||
|
|
|
@ -1857,7 +1857,8 @@ cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode,
|
|||
goto posix_mkdir_out;
|
||||
}
|
||||
|
||||
int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
|
||||
int cifs_mkdir(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
struct dentry *direntry, umode_t mode)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned int xid;
|
||||
|
@ -2067,9 +2068,9 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
|
|||
}
|
||||
|
||||
int
|
||||
cifs_rename2(struct inode *source_dir, struct dentry *source_dentry,
|
||||
struct inode *target_dir, struct dentry *target_dentry,
|
||||
unsigned int flags)
|
||||
cifs_rename2(struct user_namespace *mnt_userns, struct inode *source_dir,
|
||||
struct dentry *source_dentry, struct inode *target_dir,
|
||||
struct dentry *target_dentry, unsigned int flags)
|
||||
{
|
||||
char *from_name = NULL;
|
||||
char *to_name = NULL;
|
||||
|
@ -2370,8 +2371,8 @@ int cifs_revalidate_dentry(struct dentry *dentry)
|
|||
return cifs_revalidate_mapping(inode);
|
||||
}
|
||||
|
||||
int cifs_getattr(const struct path *path, struct kstat *stat,
|
||||
u32 request_mask, unsigned int flags)
|
||||
int cifs_getattr(struct user_namespace *mnt_userns, const struct path *path,
|
||||
struct kstat *stat, u32 request_mask, unsigned int flags)
|
||||
{
|
||||
struct dentry *dentry = path->dentry;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
|
||||
|
@ -2408,7 +2409,7 @@ int cifs_getattr(const struct path *path, struct kstat *stat,
|
|||
return rc;
|
||||
}
|
||||
|
||||
generic_fillattr(inode, stat);
|
||||
generic_fillattr(&init_user_ns, inode, stat);
|
||||
stat->blksize = cifs_sb->ctx->bsize;
|
||||
stat->ino = CIFS_I(inode)->uniqueid;
|
||||
|
||||
|
@ -2610,7 +2611,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
|
|||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
|
||||
attrs->ia_valid |= ATTR_FORCE;
|
||||
|
||||
rc = setattr_prepare(direntry, attrs);
|
||||
rc = setattr_prepare(&init_user_ns, direntry, attrs);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
|
@ -2715,7 +2716,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
|
|||
attrs->ia_size != i_size_read(inode))
|
||||
truncate_setsize(inode, attrs->ia_size);
|
||||
|
||||
setattr_copy(inode, attrs);
|
||||
setattr_copy(&init_user_ns, inode, attrs);
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
/* force revalidate when any of these times are set since some
|
||||
|
@ -2757,7 +2758,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
|
|||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
|
||||
attrs->ia_valid |= ATTR_FORCE;
|
||||
|
||||
rc = setattr_prepare(direntry, attrs);
|
||||
rc = setattr_prepare(&init_user_ns, direntry, attrs);
|
||||
if (rc < 0) {
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
|
@ -2913,7 +2914,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
|
|||
attrs->ia_size != i_size_read(inode))
|
||||
truncate_setsize(inode, attrs->ia_size);
|
||||
|
||||
setattr_copy(inode, attrs);
|
||||
setattr_copy(&init_user_ns, inode, attrs);
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
cifs_setattr_exit:
|
||||
|
@ -2923,7 +2924,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
|
|||
}
|
||||
|
||||
int
|
||||
cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
||||
cifs_setattr(struct user_namespace *mnt_userns, struct dentry *direntry,
|
||||
struct iattr *attrs)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
|
||||
struct cifs_tcon *pTcon = cifs_sb_master_tcon(cifs_sb);
|
||||
|
|
|
@ -661,7 +661,8 @@ cifs_get_link(struct dentry *direntry, struct inode *inode,
|
|||
}
|
||||
|
||||
int
|
||||
cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
|
||||
cifs_symlink(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
struct dentry *direntry, const char *symname)
|
||||
{
|
||||
int rc = -EOPNOTSUPP;
|
||||
unsigned int xid;
|
||||
|
|
|
@ -101,6 +101,7 @@ static int cifs_creation_time_set(unsigned int xid, struct cifs_tcon *pTcon,
|
|||
}
|
||||
|
||||
static int cifs_xattr_set(const struct xattr_handler *handler,
|
||||
struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry, struct inode *inode,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
|
|
|
@ -46,10 +46,12 @@ extern const struct file_operations coda_ioctl_operations;
|
|||
/* operations shared over more than one file */
|
||||
int coda_open(struct inode *i, struct file *f);
|
||||
int coda_release(struct inode *i, struct file *f);
|
||||
int coda_permission(struct inode *inode, int mask);
|
||||
int coda_permission(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
int mask);
|
||||
int coda_revalidate_inode(struct inode *);
|
||||
int coda_getattr(const struct path *, struct kstat *, u32, unsigned int);
|
||||
int coda_setattr(struct dentry *, struct iattr *);
|
||||
int coda_getattr(struct user_namespace *, const struct path *, struct kstat *,
|
||||
u32, unsigned int);
|
||||
int coda_setattr(struct user_namespace *, struct dentry *, struct iattr *);
|
||||
|
||||
/* this file: heloers */
|
||||
char *coda_f2s(struct CodaFid *f);
|
||||
|
|
|
@ -73,7 +73,8 @@ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, unsig
|
|||
}
|
||||
|
||||
|
||||
int coda_permission(struct inode *inode, int mask)
|
||||
int coda_permission(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
int mask)
|
||||
{
|
||||
int error;
|
||||
|
||||
|
@ -132,7 +133,8 @@ static inline void coda_dir_drop_nlink(struct inode *dir)
|
|||
}
|
||||
|
||||
/* creation routines: create, mknod, mkdir, link, symlink */
|
||||
static int coda_create(struct inode *dir, struct dentry *de, umode_t mode, bool excl)
|
||||
static int coda_create(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *de, umode_t mode, bool excl)
|
||||
{
|
||||
int error;
|
||||
const char *name=de->d_name.name;
|
||||
|
@ -164,7 +166,8 @@ static int coda_create(struct inode *dir, struct dentry *de, umode_t mode, bool
|
|||
return error;
|
||||
}
|
||||
|
||||
static int coda_mkdir(struct inode *dir, struct dentry *de, umode_t mode)
|
||||
static int coda_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *de, umode_t mode)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct coda_vattr attrs;
|
||||
|
@ -225,7 +228,8 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
|
|||
}
|
||||
|
||||
|
||||
static int coda_symlink(struct inode *dir_inode, struct dentry *de,
|
||||
static int coda_symlink(struct user_namespace *mnt_userns,
|
||||
struct inode *dir_inode, struct dentry *de,
|
||||
const char *symname)
|
||||
{
|
||||
const char *name = de->d_name.name;
|
||||
|
@ -291,9 +295,9 @@ static int coda_rmdir(struct inode *dir, struct dentry *de)
|
|||
}
|
||||
|
||||
/* rename */
|
||||
static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
unsigned int flags)
|
||||
static int coda_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
|
||||
struct dentry *old_dentry, struct inode *new_dir,
|
||||
struct dentry *new_dentry, unsigned int flags)
|
||||
{
|
||||
const char *old_name = old_dentry->d_name.name;
|
||||
const char *new_name = new_dentry->d_name.name;
|
||||
|
|
|
@ -251,16 +251,17 @@ static void coda_evict_inode(struct inode *inode)
|
|||
coda_cache_clear_inode(inode);
|
||||
}
|
||||
|
||||
int coda_getattr(const struct path *path, struct kstat *stat,
|
||||
u32 request_mask, unsigned int flags)
|
||||
int coda_getattr(struct user_namespace *mnt_userns, const struct path *path,
|
||||
struct kstat *stat, u32 request_mask, unsigned int flags)
|
||||
{
|
||||
int err = coda_revalidate_inode(d_inode(path->dentry));
|
||||
if (!err)
|
||||
generic_fillattr(d_inode(path->dentry), stat);
|
||||
generic_fillattr(&init_user_ns, d_inode(path->dentry), stat);
|
||||
return err;
|
||||
}
|
||||
|
||||
int coda_setattr(struct dentry *de, struct iattr *iattr)
|
||||
int coda_setattr(struct user_namespace *mnt_userns, struct dentry *de,
|
||||
struct iattr *iattr)
|
||||
{
|
||||
struct inode *inode = d_inode(de);
|
||||
struct coda_vattr vattr;
|
||||
|
|
|
@ -24,7 +24,8 @@
|
|||
#include "coda_linux.h"
|
||||
|
||||
/* pioctl ops */
|
||||
static int coda_ioctl_permission(struct inode *inode, int mask);
|
||||
static int coda_ioctl_permission(struct user_namespace *mnt_userns,
|
||||
struct inode *inode, int mask);
|
||||
static long coda_pioctl(struct file *filp, unsigned int cmd,
|
||||
unsigned long user_data);
|
||||
|
||||
|
@ -40,7 +41,8 @@ const struct file_operations coda_ioctl_operations = {
|
|||
};
|
||||
|
||||
/* the coda pioctl inode ops */
|
||||
static int coda_ioctl_permission(struct inode *inode, int mask)
|
||||
static int coda_ioctl_permission(struct user_namespace *mnt_userns,
|
||||
struct inode *inode, int mask)
|
||||
{
|
||||
return (mask & MAY_EXEC) ? -EACCES : 0;
|
||||
}
|
||||
|
|
|
@ -79,7 +79,8 @@ extern void configfs_hash_and_remove(struct dentry * dir, const char * name);
|
|||
|
||||
extern const unsigned char * configfs_get_name(struct configfs_dirent *sd);
|
||||
extern void configfs_drop_dentry(struct configfs_dirent *sd, struct dentry *parent);
|
||||
extern int configfs_setattr(struct dentry *dentry, struct iattr *iattr);
|
||||
extern int configfs_setattr(struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry, struct iattr *iattr);
|
||||
|
||||
extern struct dentry *configfs_pin_fs(void);
|
||||
extern void configfs_release_fs(void);
|
||||
|
@ -92,7 +93,8 @@ extern const struct inode_operations configfs_root_inode_operations;
|
|||
extern const struct inode_operations configfs_symlink_inode_operations;
|
||||
extern const struct dentry_operations configfs_dentry_ops;
|
||||
|
||||
extern int configfs_symlink(struct inode *dir, struct dentry *dentry,
|
||||
extern int configfs_symlink(struct user_namespace *mnt_userns,
|
||||
struct inode *dir, struct dentry *dentry,
|
||||
const char *symname);
|
||||
extern int configfs_unlink(struct inode *dir, struct dentry *dentry);
|
||||
|
||||
|
|
|
@ -1268,7 +1268,8 @@ int configfs_depend_item_unlocked(struct configfs_subsystem *caller_subsys,
|
|||
}
|
||||
EXPORT_SYMBOL(configfs_depend_item_unlocked);
|
||||
|
||||
static int configfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
static int configfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode)
|
||||
{
|
||||
int ret = 0;
|
||||
int module_got = 0;
|
||||
|
|
|
@ -40,7 +40,8 @@ static const struct inode_operations configfs_inode_operations ={
|
|||
.setattr = configfs_setattr,
|
||||
};
|
||||
|
||||
int configfs_setattr(struct dentry * dentry, struct iattr * iattr)
|
||||
int configfs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
|
||||
struct iattr *iattr)
|
||||
{
|
||||
struct inode * inode = d_inode(dentry);
|
||||
struct configfs_dirent * sd = dentry->d_fsdata;
|
||||
|
@ -67,7 +68,7 @@ int configfs_setattr(struct dentry * dentry, struct iattr * iattr)
|
|||
}
|
||||
/* attributes were changed atleast once in past */
|
||||
|
||||
error = simple_setattr(dentry, iattr);
|
||||
error = simple_setattr(mnt_userns, dentry, iattr);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
|
|
@ -139,7 +139,8 @@ static int get_target(const char *symname, struct path *path,
|
|||
}
|
||||
|
||||
|
||||
int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
|
||||
int configfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, const char *symname)
|
||||
{
|
||||
int ret;
|
||||
struct path path;
|
||||
|
@ -197,7 +198,8 @@ int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symna
|
|||
if (dentry->d_inode || d_unhashed(dentry))
|
||||
ret = -EEXIST;
|
||||
else
|
||||
ret = inode_permission(dir, MAY_WRITE | MAY_EXEC);
|
||||
ret = inode_permission(&init_user_ns, dir,
|
||||
MAY_WRITE | MAY_EXEC);
|
||||
if (!ret)
|
||||
ret = type->ct_item_ops->allow_link(parent_item, target_item);
|
||||
if (!ret) {
|
||||
|
|
|
@ -703,6 +703,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
|
|||
goto close_fail;
|
||||
}
|
||||
} else {
|
||||
struct user_namespace *mnt_userns;
|
||||
struct inode *inode;
|
||||
int open_flags = O_CREAT | O_RDWR | O_NOFOLLOW |
|
||||
O_LARGEFILE | O_EXCL;
|
||||
|
@ -780,13 +781,15 @@ void do_coredump(const kernel_siginfo_t *siginfo)
|
|||
* a process dumps core while its cwd is e.g. on a vfat
|
||||
* filesystem.
|
||||
*/
|
||||
if (!uid_eq(inode->i_uid, current_fsuid()))
|
||||
mnt_userns = file_mnt_user_ns(cprm.file);
|
||||
if (!uid_eq(i_uid_into_mnt(mnt_userns, inode), current_fsuid()))
|
||||
goto close_fail;
|
||||
if ((inode->i_mode & 0677) != 0600)
|
||||
goto close_fail;
|
||||
if (!(cprm.file->f_mode & FMODE_CAN_WRITE))
|
||||
goto close_fail;
|
||||
if (do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file))
|
||||
if (do_truncate(mnt_userns, cprm.file->f_path.dentry,
|
||||
0, 0, cprm.file))
|
||||
goto close_fail;
|
||||
}
|
||||
|
||||
|
@ -931,7 +934,8 @@ void dump_truncate(struct coredump_params *cprm)
|
|||
if (file->f_op->llseek && file->f_op->llseek != no_llseek) {
|
||||
offset = file->f_op->llseek(file, 0, SEEK_CUR);
|
||||
if (i_size_read(file->f_mapping->host) < offset)
|
||||
do_truncate(file->f_path.dentry, offset, 0, file);
|
||||
do_truncate(file_mnt_user_ns(file), file->f_path.dentry,
|
||||
offset, 0, file);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(dump_truncate);
|
||||
|
|
|
@ -465,7 +465,7 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg)
|
|||
return -EFAULT;
|
||||
policy.version = version;
|
||||
|
||||
if (!inode_owner_or_capable(inode))
|
||||
if (!inode_owner_or_capable(&init_user_ns, inode))
|
||||
return -EACCES;
|
||||
|
||||
ret = mnt_want_write_file(filp);
|
||||
|
|
|
@ -42,13 +42,14 @@ static unsigned int debugfs_allow = DEFAULT_DEBUGFS_ALLOW_BITS;
|
|||
* so that we can use the file mode as part of a heuristic to determine whether
|
||||
* to lock down individual files.
|
||||
*/
|
||||
static int debugfs_setattr(struct dentry *dentry, struct iattr *ia)
|
||||
static int debugfs_setattr(struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry, struct iattr *ia)
|
||||
{
|
||||
int ret = security_locked_down(LOCKDOWN_DEBUGFS);
|
||||
|
||||
if (ret && (ia->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)))
|
||||
return ret;
|
||||
return simple_setattr(dentry, ia);
|
||||
return simple_setattr(&init_user_ns, dentry, ia);
|
||||
}
|
||||
|
||||
static const struct inode_operations debugfs_file_inode_operations = {
|
||||
|
@ -775,8 +776,8 @@ struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
|
|||
|
||||
take_dentry_name_snapshot(&old_name, old_dentry);
|
||||
|
||||
error = simple_rename(d_inode(old_dir), old_dentry, d_inode(new_dir),
|
||||
dentry, 0);
|
||||
error = simple_rename(&init_user_ns, d_inode(old_dir), old_dentry,
|
||||
d_inode(new_dir), dentry, 0);
|
||||
if (error) {
|
||||
release_dentry_name_snapshot(&old_name);
|
||||
goto exit;
|
||||
|
|
|
@ -1110,8 +1110,8 @@ ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry,
|
|||
}
|
||||
|
||||
inode_lock(lower_inode);
|
||||
rc = __vfs_setxattr(lower_dentry, lower_inode, ECRYPTFS_XATTR_NAME,
|
||||
page_virt, size, 0);
|
||||
rc = __vfs_setxattr(&init_user_ns, lower_dentry, lower_inode,
|
||||
ECRYPTFS_XATTR_NAME, page_virt, size, 0);
|
||||
if (!rc && ecryptfs_inode)
|
||||
fsstack_copy_attr_all(ecryptfs_inode, lower_inode);
|
||||
inode_unlock(lower_inode);
|
||||
|
|
|
@ -141,7 +141,8 @@ static int ecryptfs_do_unlink(struct inode *dir, struct dentry *dentry,
|
|||
else if (d_unhashed(lower_dentry))
|
||||
rc = -EINVAL;
|
||||
else
|
||||
rc = vfs_unlink(lower_dir_inode, lower_dentry, NULL);
|
||||
rc = vfs_unlink(&init_user_ns, lower_dir_inode, lower_dentry,
|
||||
NULL);
|
||||
if (rc) {
|
||||
printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc);
|
||||
goto out_unlock;
|
||||
|
@ -180,7 +181,8 @@ ecryptfs_do_create(struct inode *directory_inode,
|
|||
|
||||
lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
|
||||
lower_dir_dentry = lock_parent(lower_dentry);
|
||||
rc = vfs_create(d_inode(lower_dir_dentry), lower_dentry, mode, true);
|
||||
rc = vfs_create(&init_user_ns, d_inode(lower_dir_dentry), lower_dentry,
|
||||
mode, true);
|
||||
if (rc) {
|
||||
printk(KERN_ERR "%s: Failure to create dentry in lower fs; "
|
||||
"rc = [%d]\n", __func__, rc);
|
||||
|
@ -190,7 +192,8 @@ ecryptfs_do_create(struct inode *directory_inode,
|
|||
inode = __ecryptfs_get_inode(d_inode(lower_dentry),
|
||||
directory_inode->i_sb);
|
||||
if (IS_ERR(inode)) {
|
||||
vfs_unlink(d_inode(lower_dir_dentry), lower_dentry, NULL);
|
||||
vfs_unlink(&init_user_ns, d_inode(lower_dir_dentry),
|
||||
lower_dentry, NULL);
|
||||
goto out_lock;
|
||||
}
|
||||
fsstack_copy_attr_times(directory_inode, d_inode(lower_dir_dentry));
|
||||
|
@ -254,7 +257,8 @@ int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry,
|
|||
* Returns zero on success; non-zero on error condition
|
||||
*/
|
||||
static int
|
||||
ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,
|
||||
ecryptfs_create(struct user_namespace *mnt_userns,
|
||||
struct inode *directory_inode, struct dentry *ecryptfs_dentry,
|
||||
umode_t mode, bool excl)
|
||||
{
|
||||
struct inode *ecryptfs_inode;
|
||||
|
@ -436,8 +440,8 @@ static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir,
|
|||
dget(lower_old_dentry);
|
||||
dget(lower_new_dentry);
|
||||
lower_dir_dentry = lock_parent(lower_new_dentry);
|
||||
rc = vfs_link(lower_old_dentry, d_inode(lower_dir_dentry),
|
||||
lower_new_dentry, NULL);
|
||||
rc = vfs_link(lower_old_dentry, &init_user_ns,
|
||||
d_inode(lower_dir_dentry), lower_new_dentry, NULL);
|
||||
if (rc || d_really_is_negative(lower_new_dentry))
|
||||
goto out_lock;
|
||||
rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb);
|
||||
|
@ -460,7 +464,8 @@ static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry)
|
|||
return ecryptfs_do_unlink(dir, dentry, d_inode(dentry));
|
||||
}
|
||||
|
||||
static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
|
||||
static int ecryptfs_symlink(struct user_namespace *mnt_userns,
|
||||
struct inode *dir, struct dentry *dentry,
|
||||
const char *symname)
|
||||
{
|
||||
int rc;
|
||||
|
@ -481,7 +486,7 @@ static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
|
|||
strlen(symname));
|
||||
if (rc)
|
||||
goto out_lock;
|
||||
rc = vfs_symlink(d_inode(lower_dir_dentry), lower_dentry,
|
||||
rc = vfs_symlink(&init_user_ns, d_inode(lower_dir_dentry), lower_dentry,
|
||||
encoded_symname);
|
||||
kfree(encoded_symname);
|
||||
if (rc || d_really_is_negative(lower_dentry))
|
||||
|
@ -499,7 +504,8 @@ static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int ecryptfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
static int ecryptfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode)
|
||||
{
|
||||
int rc;
|
||||
struct dentry *lower_dentry;
|
||||
|
@ -507,7 +513,8 @@ static int ecryptfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
|
|||
|
||||
lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||||
lower_dir_dentry = lock_parent(lower_dentry);
|
||||
rc = vfs_mkdir(d_inode(lower_dir_dentry), lower_dentry, mode);
|
||||
rc = vfs_mkdir(&init_user_ns, d_inode(lower_dir_dentry), lower_dentry,
|
||||
mode);
|
||||
if (rc || d_really_is_negative(lower_dentry))
|
||||
goto out;
|
||||
rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb);
|
||||
|
@ -541,7 +548,7 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
|
|||
else if (d_unhashed(lower_dentry))
|
||||
rc = -EINVAL;
|
||||
else
|
||||
rc = vfs_rmdir(lower_dir_inode, lower_dentry);
|
||||
rc = vfs_rmdir(&init_user_ns, lower_dir_inode, lower_dentry);
|
||||
if (!rc) {
|
||||
clear_nlink(d_inode(dentry));
|
||||
fsstack_copy_attr_times(dir, lower_dir_inode);
|
||||
|
@ -555,7 +562,8 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
|
|||
}
|
||||
|
||||
static int
|
||||
ecryptfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
|
||||
ecryptfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode, dev_t dev)
|
||||
{
|
||||
int rc;
|
||||
struct dentry *lower_dentry;
|
||||
|
@ -563,7 +571,8 @@ ecryptfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev
|
|||
|
||||
lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||||
lower_dir_dentry = lock_parent(lower_dentry);
|
||||
rc = vfs_mknod(d_inode(lower_dir_dentry), lower_dentry, mode, dev);
|
||||
rc = vfs_mknod(&init_user_ns, d_inode(lower_dir_dentry), lower_dentry,
|
||||
mode, dev);
|
||||
if (rc || d_really_is_negative(lower_dentry))
|
||||
goto out;
|
||||
rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb);
|
||||
|
@ -579,9 +588,9 @@ ecryptfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev
|
|||
}
|
||||
|
||||
static int
|
||||
ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
unsigned int flags)
|
||||
ecryptfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
|
||||
struct dentry *old_dentry, struct inode *new_dir,
|
||||
struct dentry *new_dentry, unsigned int flags)
|
||||
{
|
||||
int rc;
|
||||
struct dentry *lower_old_dentry;
|
||||
|
@ -590,6 +599,7 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
struct dentry *lower_new_dir_dentry;
|
||||
struct dentry *trap;
|
||||
struct inode *target_inode;
|
||||
struct renamedata rd = {};
|
||||
|
||||
if (flags)
|
||||
return -EINVAL;
|
||||
|
@ -619,9 +629,14 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
rc = -ENOTEMPTY;
|
||||
goto out_lock;
|
||||
}
|
||||
rc = vfs_rename(d_inode(lower_old_dir_dentry), lower_old_dentry,
|
||||
d_inode(lower_new_dir_dentry), lower_new_dentry,
|
||||
NULL, 0);
|
||||
|
||||
rd.old_mnt_userns = &init_user_ns;
|
||||
rd.old_dir = d_inode(lower_old_dir_dentry);
|
||||
rd.old_dentry = lower_old_dentry;
|
||||
rd.new_mnt_userns = &init_user_ns;
|
||||
rd.new_dir = d_inode(lower_new_dir_dentry);
|
||||
rd.new_dentry = lower_new_dentry;
|
||||
rc = vfs_rename(&rd);
|
||||
if (rc)
|
||||
goto out_lock;
|
||||
if (target_inode)
|
||||
|
@ -855,16 +870,19 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
|
|||
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||||
|
||||
inode_lock(d_inode(lower_dentry));
|
||||
rc = notify_change(lower_dentry, &lower_ia, NULL);
|
||||
rc = notify_change(&init_user_ns, lower_dentry,
|
||||
&lower_ia, NULL);
|
||||
inode_unlock(d_inode(lower_dentry));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
ecryptfs_permission(struct inode *inode, int mask)
|
||||
ecryptfs_permission(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
int mask)
|
||||
{
|
||||
return inode_permission(ecryptfs_inode_to_lower(inode), mask);
|
||||
return inode_permission(&init_user_ns,
|
||||
ecryptfs_inode_to_lower(inode), mask);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -879,7 +897,8 @@ ecryptfs_permission(struct inode *inode, int mask)
|
|||
* All other metadata changes will be passed right to the lower filesystem,
|
||||
* and we will just update our inode to look like the lower.
|
||||
*/
|
||||
static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
|
||||
static int ecryptfs_setattr(struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry, struct iattr *ia)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dentry *lower_dentry;
|
||||
|
@ -933,7 +952,7 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
|
|||
}
|
||||
mutex_unlock(&crypt_stat->cs_mutex);
|
||||
|
||||
rc = setattr_prepare(dentry, ia);
|
||||
rc = setattr_prepare(&init_user_ns, dentry, ia);
|
||||
if (rc)
|
||||
goto out;
|
||||
if (ia->ia_valid & ATTR_SIZE) {
|
||||
|
@ -959,14 +978,15 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
|
|||
lower_ia.ia_valid &= ~ATTR_MODE;
|
||||
|
||||
inode_lock(d_inode(lower_dentry));
|
||||
rc = notify_change(lower_dentry, &lower_ia, NULL);
|
||||
rc = notify_change(&init_user_ns, lower_dentry, &lower_ia, NULL);
|
||||
inode_unlock(d_inode(lower_dentry));
|
||||
out:
|
||||
fsstack_copy_attr_all(inode, lower_inode);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ecryptfs_getattr_link(const struct path *path, struct kstat *stat,
|
||||
static int ecryptfs_getattr_link(struct user_namespace *mnt_userns,
|
||||
const struct path *path, struct kstat *stat,
|
||||
u32 request_mask, unsigned int flags)
|
||||
{
|
||||
struct dentry *dentry = path->dentry;
|
||||
|
@ -975,7 +995,7 @@ static int ecryptfs_getattr_link(const struct path *path, struct kstat *stat,
|
|||
|
||||
mount_crypt_stat = &ecryptfs_superblock_to_private(
|
||||
dentry->d_sb)->mount_crypt_stat;
|
||||
generic_fillattr(d_inode(dentry), stat);
|
||||
generic_fillattr(&init_user_ns, d_inode(dentry), stat);
|
||||
if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) {
|
||||
char *target;
|
||||
size_t targetsiz;
|
||||
|
@ -991,7 +1011,8 @@ static int ecryptfs_getattr_link(const struct path *path, struct kstat *stat,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int ecryptfs_getattr(const struct path *path, struct kstat *stat,
|
||||
static int ecryptfs_getattr(struct user_namespace *mnt_userns,
|
||||
const struct path *path, struct kstat *stat,
|
||||
u32 request_mask, unsigned int flags)
|
||||
{
|
||||
struct dentry *dentry = path->dentry;
|
||||
|
@ -1003,7 +1024,7 @@ static int ecryptfs_getattr(const struct path *path, struct kstat *stat,
|
|||
if (!rc) {
|
||||
fsstack_copy_attr_all(d_inode(dentry),
|
||||
ecryptfs_inode_to_lower(d_inode(dentry)));
|
||||
generic_fillattr(d_inode(dentry), stat);
|
||||
generic_fillattr(&init_user_ns, d_inode(dentry), stat);
|
||||
stat->blocks = lower_stat.blocks;
|
||||
}
|
||||
return rc;
|
||||
|
@ -1025,7 +1046,7 @@ ecryptfs_setxattr(struct dentry *dentry, struct inode *inode,
|
|||
goto out;
|
||||
}
|
||||
inode_lock(lower_inode);
|
||||
rc = __vfs_setxattr_locked(lower_dentry, name, value, size, flags, NULL);
|
||||
rc = __vfs_setxattr_locked(&init_user_ns, lower_dentry, name, value, size, flags, NULL);
|
||||
inode_unlock(lower_inode);
|
||||
if (!rc && inode)
|
||||
fsstack_copy_attr_all(inode, lower_inode);
|
||||
|
@ -1091,7 +1112,7 @@ static int ecryptfs_removexattr(struct dentry *dentry, struct inode *inode,
|
|||
goto out;
|
||||
}
|
||||
inode_lock(lower_inode);
|
||||
rc = __vfs_removexattr(lower_dentry, name);
|
||||
rc = __vfs_removexattr(&init_user_ns, lower_dentry, name);
|
||||
inode_unlock(lower_inode);
|
||||
out:
|
||||
return rc;
|
||||
|
@ -1135,6 +1156,7 @@ static int ecryptfs_xattr_get(const struct xattr_handler *handler,
|
|||
}
|
||||
|
||||
static int ecryptfs_xattr_set(const struct xattr_handler *handler,
|
||||
struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry, struct inode *inode,
|
||||
const char *name, const void *value, size_t size,
|
||||
int flags)
|
||||
|
|
|
@ -531,6 +531,12 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags
|
|||
goto out_free;
|
||||
}
|
||||
|
||||
if (mnt_user_ns(path.mnt) != &init_user_ns) {
|
||||
rc = -EINVAL;
|
||||
printk(KERN_ERR "Mounting on idmapped mounts currently disallowed\n");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (check_ruid && !uid_eq(d_inode(path.dentry)->i_uid, current_uid())) {
|
||||
rc = -EPERM;
|
||||
printk(KERN_ERR "Mount of device (uid: %d) not owned by "
|
||||
|
|
|
@ -426,8 +426,8 @@ static int ecryptfs_write_inode_size_to_xattr(struct inode *ecryptfs_inode)
|
|||
if (size < 0)
|
||||
size = 8;
|
||||
put_unaligned_be64(i_size_read(ecryptfs_inode), xattr_virt);
|
||||
rc = __vfs_setxattr(lower_dentry, lower_inode, ECRYPTFS_XATTR_NAME,
|
||||
xattr_virt, size, 0);
|
||||
rc = __vfs_setxattr(&init_user_ns, lower_dentry, lower_inode,
|
||||
ECRYPTFS_XATTR_NAME, xattr_virt, size, 0);
|
||||
inode_unlock(lower_inode);
|
||||
if (rc)
|
||||
printk(KERN_ERR "Error whilst attempting to write inode size "
|
||||
|
|
|
@ -137,7 +137,7 @@ efivarfs_ioc_setxflags(struct file *file, void __user *arg)
|
|||
unsigned int oldflags = efivarfs_getflags(inode);
|
||||
int error;
|
||||
|
||||
if (!inode_owner_or_capable(inode))
|
||||
if (!inode_owner_or_capable(&init_user_ns, inode))
|
||||
return -EACCES;
|
||||
|
||||
if (copy_from_user(&flags, arg, sizeof(flags)))
|
||||
|
|
|
@ -66,8 +66,8 @@ bool efivarfs_valid_name(const char *str, int len)
|
|||
return uuid_is_valid(s);
|
||||
}
|
||||
|
||||
static int efivarfs_create(struct inode *dir, struct dentry *dentry,
|
||||
umode_t mode, bool excl)
|
||||
static int efivarfs_create(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode, bool excl)
|
||||
{
|
||||
struct inode *inode = NULL;
|
||||
struct efivar_entry *var;
|
||||
|
|
|
@ -331,8 +331,9 @@ struct inode *erofs_iget(struct super_block *sb,
|
|||
return inode;
|
||||
}
|
||||
|
||||
int erofs_getattr(const struct path *path, struct kstat *stat,
|
||||
u32 request_mask, unsigned int query_flags)
|
||||
int erofs_getattr(struct user_namespace *mnt_userns, const struct path *path,
|
||||
struct kstat *stat, u32 request_mask,
|
||||
unsigned int query_flags)
|
||||
{
|
||||
struct inode *const inode = d_inode(path->dentry);
|
||||
|
||||
|
@ -343,7 +344,7 @@ int erofs_getattr(const struct path *path, struct kstat *stat,
|
|||
stat->attributes_mask |= (STATX_ATTR_COMPRESSED |
|
||||
STATX_ATTR_IMMUTABLE);
|
||||
|
||||
generic_fillattr(inode, stat);
|
||||
generic_fillattr(&init_user_ns, inode, stat);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -373,8 +373,9 @@ extern const struct inode_operations erofs_symlink_iops;
|
|||
extern const struct inode_operations erofs_fast_symlink_iops;
|
||||
|
||||
struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid, bool dir);
|
||||
int erofs_getattr(const struct path *path, struct kstat *stat,
|
||||
u32 request_mask, unsigned int query_flags);
|
||||
int erofs_getattr(struct user_namespace *mnt_userns, const struct path *path,
|
||||
struct kstat *stat, u32 request_mask,
|
||||
unsigned int query_flags);
|
||||
|
||||
/* namei.c */
|
||||
extern const struct inode_operations erofs_dir_iops;
|
||||
|
|
12
fs/exec.c
12
fs/exec.c
|
@ -1404,14 +1404,15 @@ EXPORT_SYMBOL(begin_new_exec);
|
|||
void would_dump(struct linux_binprm *bprm, struct file *file)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
if (inode_permission(inode, MAY_READ) < 0) {
|
||||
struct user_namespace *mnt_userns = file_mnt_user_ns(file);
|
||||
if (inode_permission(mnt_userns, inode, MAY_READ) < 0) {
|
||||
struct user_namespace *old, *user_ns;
|
||||
bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
|
||||
|
||||
/* Ensure mm->user_ns contains the executable */
|
||||
user_ns = old = bprm->mm->user_ns;
|
||||
while ((user_ns != &init_user_ns) &&
|
||||
!privileged_wrt_inode_uidgid(user_ns, inode))
|
||||
!privileged_wrt_inode_uidgid(user_ns, mnt_userns, inode))
|
||||
user_ns = user_ns->parent;
|
||||
|
||||
if (old != user_ns) {
|
||||
|
@ -1579,6 +1580,7 @@ static void check_unsafe_exec(struct linux_binprm *bprm)
|
|||
static void bprm_fill_uid(struct linux_binprm *bprm, struct file *file)
|
||||
{
|
||||
/* Handle suid and sgid on files */
|
||||
struct user_namespace *mnt_userns;
|
||||
struct inode *inode;
|
||||
unsigned int mode;
|
||||
kuid_t uid;
|
||||
|
@ -1595,13 +1597,15 @@ static void bprm_fill_uid(struct linux_binprm *bprm, struct file *file)
|
|||
if (!(mode & (S_ISUID|S_ISGID)))
|
||||
return;
|
||||
|
||||
mnt_userns = file_mnt_user_ns(file);
|
||||
|
||||
/* Be careful if suid/sgid is set */
|
||||
inode_lock(inode);
|
||||
|
||||
/* reload atomically mode/uid/gid now that lock held */
|
||||
mode = inode->i_mode;
|
||||
uid = inode->i_uid;
|
||||
gid = inode->i_gid;
|
||||
uid = i_uid_into_mnt(mnt_userns, inode);
|
||||
gid = i_gid_into_mnt(mnt_userns, inode);
|
||||
inode_unlock(inode);
|
||||
|
||||
/* We ignore suid/sgid if there are no mappings for them in the ns */
|
||||
|
|
|
@ -416,9 +416,11 @@ int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count);
|
|||
extern const struct file_operations exfat_file_operations;
|
||||
int __exfat_truncate(struct inode *inode, loff_t new_size);
|
||||
void exfat_truncate(struct inode *inode, loff_t size);
|
||||
int exfat_setattr(struct dentry *dentry, struct iattr *attr);
|
||||
int exfat_getattr(const struct path *path, struct kstat *stat,
|
||||
unsigned int request_mask, unsigned int query_flags);
|
||||
int exfat_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
|
||||
struct iattr *attr);
|
||||
int exfat_getattr(struct user_namespace *mnt_userns, const struct path *path,
|
||||
struct kstat *stat, unsigned int request_mask,
|
||||
unsigned int query_flags);
|
||||
int exfat_file_fsync(struct file *file, loff_t start, loff_t end, int datasync);
|
||||
|
||||
/* namei.c */
|
||||
|
|
|
@ -267,13 +267,14 @@ void exfat_truncate(struct inode *inode, loff_t size)
|
|||
mutex_unlock(&sbi->s_lock);
|
||||
}
|
||||
|
||||
int exfat_getattr(const struct path *path, struct kstat *stat,
|
||||
unsigned int request_mask, unsigned int query_flags)
|
||||
int exfat_getattr(struct user_namespace *mnt_uerns, const struct path *path,
|
||||
struct kstat *stat, unsigned int request_mask,
|
||||
unsigned int query_flags)
|
||||
{
|
||||
struct inode *inode = d_backing_inode(path->dentry);
|
||||
struct exfat_inode_info *ei = EXFAT_I(inode);
|
||||
|
||||
generic_fillattr(inode, stat);
|
||||
generic_fillattr(&init_user_ns, inode, stat);
|
||||
exfat_truncate_atime(&stat->atime);
|
||||
stat->result_mask |= STATX_BTIME;
|
||||
stat->btime.tv_sec = ei->i_crtime.tv_sec;
|
||||
|
@ -282,7 +283,8 @@ int exfat_getattr(const struct path *path, struct kstat *stat,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int exfat_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
int exfat_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
|
||||
struct iattr *attr)
|
||||
{
|
||||
struct exfat_sb_info *sbi = EXFAT_SB(dentry->d_sb);
|
||||
struct inode *inode = dentry->d_inode;
|
||||
|
@ -305,7 +307,7 @@ int exfat_setattr(struct dentry *dentry, struct iattr *attr)
|
|||
ATTR_TIMES_SET);
|
||||
}
|
||||
|
||||
error = setattr_prepare(dentry, attr);
|
||||
error = setattr_prepare(&init_user_ns, dentry, attr);
|
||||
attr->ia_valid = ia_valid;
|
||||
if (error)
|
||||
goto out;
|
||||
|
@ -340,7 +342,7 @@ int exfat_setattr(struct dentry *dentry, struct iattr *attr)
|
|||
up_write(&EXFAT_I(inode)->truncate_lock);
|
||||
}
|
||||
|
||||
setattr_copy(inode, attr);
|
||||
setattr_copy(&init_user_ns, inode, attr);
|
||||
exfat_truncate_atime(&inode->i_atime);
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
|
|
|
@ -541,8 +541,8 @@ static int exfat_add_entry(struct inode *inode, const char *path,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
bool excl)
|
||||
static int exfat_create(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode, bool excl)
|
||||
{
|
||||
struct super_block *sb = dir->i_sb;
|
||||
struct inode *inode;
|
||||
|
@ -827,7 +827,8 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
static int exfat_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode)
|
||||
{
|
||||
struct super_block *sb = dir->i_sb;
|
||||
struct inode *inode;
|
||||
|
@ -1318,9 +1319,10 @@ static int __exfat_rename(struct inode *old_parent_inode,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
unsigned int flags)
|
||||
static int exfat_rename(struct user_namespace *mnt_userns,
|
||||
struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct inode *old_inode, *new_inode;
|
||||
struct super_block *sb = old_dir->i_sb;
|
||||
|
|
|
@ -216,14 +216,16 @@ __ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
|||
* inode->i_mutex: down
|
||||
*/
|
||||
int
|
||||
ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
||||
ext2_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
struct posix_acl *acl, int type)
|
||||
{
|
||||
int error;
|
||||
int update_mode = 0;
|
||||
umode_t mode = inode->i_mode;
|
||||
|
||||
if (type == ACL_TYPE_ACCESS && acl) {
|
||||
error = posix_acl_update_mode(inode, &mode, &acl);
|
||||
error = posix_acl_update_mode(&init_user_ns, inode, &mode,
|
||||
&acl);
|
||||
if (error)
|
||||
return error;
|
||||
update_mode = 1;
|
||||
|
|
|
@ -56,7 +56,8 @@ static inline int ext2_acl_count(size_t size)
|
|||
|
||||
/* acl.c */
|
||||
extern struct posix_acl *ext2_get_acl(struct inode *inode, int type);
|
||||
extern int ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type);
|
||||
extern int ext2_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
struct posix_acl *acl, int type);
|
||||
extern int ext2_init_acl (struct inode *, struct inode *);
|
||||
|
||||
#else
|
||||
|
|
|
@ -764,8 +764,9 @@ extern struct inode *ext2_iget (struct super_block *, unsigned long);
|
|||
extern int ext2_write_inode (struct inode *, struct writeback_control *);
|
||||
extern void ext2_evict_inode(struct inode *);
|
||||
extern int ext2_get_block(struct inode *, sector_t, struct buffer_head *, int);
|
||||
extern int ext2_setattr (struct dentry *, struct iattr *);
|
||||
extern int ext2_getattr (const struct path *, struct kstat *, u32, unsigned int);
|
||||
extern int ext2_setattr (struct user_namespace *, struct dentry *, struct iattr *);
|
||||
extern int ext2_getattr (struct user_namespace *, const struct path *,
|
||||
struct kstat *, u32, unsigned int);
|
||||
extern void ext2_set_inode_flags(struct inode *inode);
|
||||
extern int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
u64 start, u64 len);
|
||||
|
|
|
@ -551,7 +551,7 @@ struct inode *ext2_new_inode(struct inode *dir, umode_t mode,
|
|||
inode->i_uid = current_fsuid();
|
||||
inode->i_gid = dir->i_gid;
|
||||
} else
|
||||
inode_init_owner(inode, dir, mode);
|
||||
inode_init_owner(&init_user_ns, inode, dir, mode);
|
||||
|
||||
inode->i_ino = ino;
|
||||
inode->i_blocks = 0;
|
||||
|
|
|
@ -1638,8 +1638,8 @@ int ext2_write_inode(struct inode *inode, struct writeback_control *wbc)
|
|||
return __ext2_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL);
|
||||
}
|
||||
|
||||
int ext2_getattr(const struct path *path, struct kstat *stat,
|
||||
u32 request_mask, unsigned int query_flags)
|
||||
int ext2_getattr(struct user_namespace *mnt_userns, const struct path *path,
|
||||
struct kstat *stat, u32 request_mask, unsigned int query_flags)
|
||||
{
|
||||
struct inode *inode = d_inode(path->dentry);
|
||||
struct ext2_inode_info *ei = EXT2_I(inode);
|
||||
|
@ -1660,16 +1660,17 @@ int ext2_getattr(const struct path *path, struct kstat *stat,
|
|||
STATX_ATTR_IMMUTABLE |
|
||||
STATX_ATTR_NODUMP);
|
||||
|
||||
generic_fillattr(inode, stat);
|
||||
generic_fillattr(&init_user_ns, inode, stat);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
|
||||
int ext2_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
|
||||
struct iattr *iattr)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
int error;
|
||||
|
||||
error = setattr_prepare(dentry, iattr);
|
||||
error = setattr_prepare(&init_user_ns, dentry, iattr);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@ -1689,9 +1690,9 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
|
|||
if (error)
|
||||
return error;
|
||||
}
|
||||
setattr_copy(inode, iattr);
|
||||
setattr_copy(&init_user_ns, inode, iattr);
|
||||
if (iattr->ia_valid & ATTR_MODE)
|
||||
error = posix_acl_chmod(inode, inode->i_mode);
|
||||
error = posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
return error;
|
||||
|
|
|
@ -39,7 +39,7 @@ long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!inode_owner_or_capable(inode)) {
|
||||
if (!inode_owner_or_capable(&init_user_ns, inode)) {
|
||||
ret = -EACCES;
|
||||
goto setflags_out;
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|||
case EXT2_IOC_SETVERSION: {
|
||||
__u32 generation;
|
||||
|
||||
if (!inode_owner_or_capable(inode))
|
||||
if (!inode_owner_or_capable(&init_user_ns, inode))
|
||||
return -EPERM;
|
||||
ret = mnt_want_write_file(filp);
|
||||
if (ret)
|
||||
|
@ -117,7 +117,7 @@ long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|||
if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode))
|
||||
return -ENOTTY;
|
||||
|
||||
if (!inode_owner_or_capable(inode))
|
||||
if (!inode_owner_or_capable(&init_user_ns, inode))
|
||||
return -EACCES;
|
||||
|
||||
if (get_user(rsv_window_size, (int __user *)arg))
|
||||
|
|
|
@ -100,7 +100,9 @@ struct dentry *ext2_get_parent(struct dentry *child)
|
|||
* If the create succeeds, we fill in the inode information
|
||||
* with d_instantiate().
|
||||
*/
|
||||
static int ext2_create (struct inode * dir, struct dentry * dentry, umode_t mode, bool excl)
|
||||
static int ext2_create (struct user_namespace * mnt_userns,
|
||||
struct inode * dir, struct dentry * dentry,
|
||||
umode_t mode, bool excl)
|
||||
{
|
||||
struct inode *inode;
|
||||
int err;
|
||||
|
@ -118,7 +120,8 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, umode_t mode
|
|||
return ext2_add_nondir(dentry, inode);
|
||||
}
|
||||
|
||||
static int ext2_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
static int ext2_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode)
|
||||
{
|
||||
struct inode *inode = ext2_new_inode(dir, mode, NULL);
|
||||
if (IS_ERR(inode))
|
||||
|
@ -131,7 +134,8 @@ static int ext2_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ext2_mknod (struct inode * dir, struct dentry *dentry, umode_t mode, dev_t rdev)
|
||||
static int ext2_mknod (struct user_namespace * mnt_userns, struct inode * dir,
|
||||
struct dentry *dentry, umode_t mode, dev_t rdev)
|
||||
{
|
||||
struct inode * inode;
|
||||
int err;
|
||||
|
@ -151,8 +155,8 @@ static int ext2_mknod (struct inode * dir, struct dentry *dentry, umode_t mode,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int ext2_symlink (struct inode * dir, struct dentry * dentry,
|
||||
const char * symname)
|
||||
static int ext2_symlink (struct user_namespace * mnt_userns, struct inode * dir,
|
||||
struct dentry * dentry, const char * symname)
|
||||
{
|
||||
struct super_block * sb = dir->i_sb;
|
||||
int err = -ENAMETOOLONG;
|
||||
|
@ -225,7 +229,8 @@ static int ext2_link (struct dentry * old_dentry, struct inode * dir,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int ext2_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
|
||||
static int ext2_mkdir(struct user_namespace * mnt_userns,
|
||||
struct inode * dir, struct dentry * dentry, umode_t mode)
|
||||
{
|
||||
struct inode * inode;
|
||||
int err;
|
||||
|
@ -315,8 +320,9 @@ static int ext2_rmdir (struct inode * dir, struct dentry *dentry)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
|
||||
struct inode * new_dir, struct dentry * new_dentry,
|
||||
static int ext2_rename (struct user_namespace * mnt_userns,
|
||||
struct inode * old_dir, struct dentry * old_dentry,
|
||||
struct inode * new_dir, struct dentry * new_dentry,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct inode * old_inode = d_inode(old_dentry);
|
||||
|
|
|
@ -19,6 +19,7 @@ ext2_xattr_security_get(const struct xattr_handler *handler,
|
|||
|
||||
static int
|
||||
ext2_xattr_security_set(const struct xattr_handler *handler,
|
||||
struct user_namespace *mnt_userns,
|
||||
struct dentry *unused, struct inode *inode,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
|
|
|
@ -26,6 +26,7 @@ ext2_xattr_trusted_get(const struct xattr_handler *handler,
|
|||
|
||||
static int
|
||||
ext2_xattr_trusted_set(const struct xattr_handler *handler,
|
||||
struct user_namespace *mnt_userns,
|
||||
struct dentry *unused, struct inode *inode,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
|
|
|
@ -30,6 +30,7 @@ ext2_xattr_user_get(const struct xattr_handler *handler,
|
|||
|
||||
static int
|
||||
ext2_xattr_user_set(const struct xattr_handler *handler,
|
||||
struct user_namespace *mnt_userns,
|
||||
struct dentry *unused, struct inode *inode,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
|
|
|
@ -222,7 +222,8 @@ __ext4_set_acl(handle_t *handle, struct inode *inode, int type,
|
|||
}
|
||||
|
||||
int
|
||||
ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
||||
ext4_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
struct posix_acl *acl, int type)
|
||||
{
|
||||
handle_t *handle;
|
||||
int error, credits, retries = 0;
|
||||
|
@ -245,7 +246,7 @@ ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
|||
ext4_fc_start_update(inode);
|
||||
|
||||
if ((type == ACL_TYPE_ACCESS) && acl) {
|
||||
error = posix_acl_update_mode(inode, &mode, &acl);
|
||||
error = posix_acl_update_mode(mnt_userns, inode, &mode, &acl);
|
||||
if (error)
|
||||
goto out_stop;
|
||||
if (mode != inode->i_mode)
|
||||
|
|
|
@ -56,7 +56,8 @@ static inline int ext4_acl_count(size_t size)
|
|||
|
||||
/* acl.c */
|
||||
struct posix_acl *ext4_get_acl(struct inode *inode, int type);
|
||||
int ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type);
|
||||
int ext4_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
struct posix_acl *acl, int type);
|
||||
extern int ext4_init_acl(handle_t *, struct inode *, struct inode *);
|
||||
|
||||
#else /* CONFIG_EXT4_FS_POSIX_ACL */
|
||||
|
|
|
@ -2755,18 +2755,19 @@ extern int ext4fs_dirhash(const struct inode *dir, const char *name, int len,
|
|||
|
||||
/* ialloc.c */
|
||||
extern int ext4_mark_inode_used(struct super_block *sb, int ino);
|
||||
extern struct inode *__ext4_new_inode(handle_t *, struct inode *, umode_t,
|
||||
extern struct inode *__ext4_new_inode(struct user_namespace *, handle_t *,
|
||||
struct inode *, umode_t,
|
||||
const struct qstr *qstr, __u32 goal,
|
||||
uid_t *owner, __u32 i_flags,
|
||||
int handle_type, unsigned int line_no,
|
||||
int nblocks);
|
||||
|
||||
#define ext4_new_inode(handle, dir, mode, qstr, goal, owner, i_flags) \
|
||||
__ext4_new_inode((handle), (dir), (mode), (qstr), (goal), (owner), \
|
||||
i_flags, 0, 0, 0)
|
||||
#define ext4_new_inode_start_handle(dir, mode, qstr, goal, owner, \
|
||||
#define ext4_new_inode(handle, dir, mode, qstr, goal, owner, i_flags) \
|
||||
__ext4_new_inode(&init_user_ns, (handle), (dir), (mode), (qstr), \
|
||||
(goal), (owner), i_flags, 0, 0, 0)
|
||||
#define ext4_new_inode_start_handle(mnt_userns, dir, mode, qstr, goal, owner, \
|
||||
type, nblocks) \
|
||||
__ext4_new_inode(NULL, (dir), (mode), (qstr), (goal), (owner), \
|
||||
__ext4_new_inode((mnt_userns), NULL, (dir), (mode), (qstr), (goal), (owner), \
|
||||
0, (type), __LINE__, (nblocks))
|
||||
|
||||
|
||||
|
@ -2877,11 +2878,14 @@ extern struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
|
|||
__ext4_iget((sb), (ino), (flags), __func__, __LINE__)
|
||||
|
||||
extern int ext4_write_inode(struct inode *, struct writeback_control *);
|
||||
extern int ext4_setattr(struct dentry *, struct iattr *);
|
||||
extern int ext4_getattr(const struct path *, struct kstat *, u32, unsigned int);
|
||||
extern int ext4_setattr(struct user_namespace *, struct dentry *,
|
||||
struct iattr *);
|
||||
extern int ext4_getattr(struct user_namespace *, const struct path *,
|
||||
struct kstat *, u32, unsigned int);
|
||||
extern void ext4_evict_inode(struct inode *);
|
||||
extern void ext4_clear_inode(struct inode *);
|
||||
extern int ext4_file_getattr(const struct path *, struct kstat *, u32, unsigned int);
|
||||
extern int ext4_file_getattr(struct user_namespace *, const struct path *,
|
||||
struct kstat *, u32, unsigned int);
|
||||
extern int ext4_sync_inode(handle_t *, struct inode *);
|
||||
extern void ext4_dirty_inode(struct inode *, int);
|
||||
extern int ext4_change_inode_journal_flag(struct inode *, int);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue