Merge branch 'fs.acl.rework' into for-next

This commit is contained in:
Christian Brauner 2022-10-24 16:43:21 +02:00 committed by Christian Brauner (Microsoft)
commit 03fd1402bd
No known key found for this signature in database
GPG key ID: 91C61BC06578DCA2
110 changed files with 1826 additions and 1115 deletions

View file

@ -70,7 +70,7 @@ prototypes::
const char *(*get_link) (struct dentry *, struct inode *, struct delayed_call *);
void (*truncate) (struct inode *);
int (*permission) (struct inode *, int, unsigned int);
struct posix_acl * (*get_acl)(struct inode *, int, bool);
struct posix_acl * (*get_inode_acl)(struct inode *, int, bool);
int (*setattr) (struct dentry *, struct iattr *);
int (*getattr) (const struct path *, struct kstat *, u32, unsigned int);
ssize_t (*listxattr) (struct dentry *, char *, size_t);
@ -84,13 +84,14 @@ prototypes::
int (*fileattr_set)(struct user_namespace *mnt_userns,
struct dentry *dentry, struct fileattr *fa);
int (*fileattr_get)(struct dentry *dentry, struct fileattr *fa);
struct posix_acl * (*get_acl)(struct user_namespace *, struct dentry *, int);
locking rules:
all may block
============= =============================================
============== =============================================
ops i_rwsem(inode)
============= =============================================
============== =============================================
lookup: shared
create: exclusive
link: exclusive (both)
@ -104,6 +105,7 @@ readlink: no
get_link: no
setattr: exclusive
permission: no (may not block if called in rcu-walk mode)
get_inode_acl: no
get_acl: no
getattr: no
listxattr: no
@ -113,7 +115,7 @@ atomic_open: shared (exclusive if O_CREAT is set in open flags)
tmpfile: no
fileattr_get: no or exclusive
fileattr_set: exclusive
============= =============================================
============== =============================================
Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_rwsem

View file

@ -462,8 +462,8 @@ ERR_PTR(...).
argument; instead of passing IPERM_FLAG_RCU we add MAY_NOT_BLOCK into mask.
generic_permission() has also lost the check_acl argument; ACL checking
has been taken to VFS and filesystems need to provide a non-NULL ->i_op->get_acl
to read an ACL from disk.
has been taken to VFS and filesystems need to provide a non-NULL
->i_op->get_inode_acl to read an ACL from disk.
---

View file

@ -435,7 +435,7 @@ As of kernel 2.6.22, the following members are defined:
const char *(*get_link) (struct dentry *, struct inode *,
struct delayed_call *);
int (*permission) (struct user_namespace *, struct inode *, int);
struct posix_acl * (*get_acl)(struct inode *, int, bool);
struct posix_acl * (*get_inode_acl)(struct inode *, int, bool);
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);
@ -443,7 +443,8 @@ As of kernel 2.6.22, the following members are defined:
int (*atomic_open)(struct inode *, struct dentry *, struct file *,
unsigned open_flag, umode_t create_mode);
int (*tmpfile) (struct user_namespace *, struct inode *, struct file *, umode_t);
int (*set_acl)(struct user_namespace *, struct inode *, struct posix_acl *, int);
struct posix_acl * (*get_acl)(struct user_namespace *, struct dentry *, int);
int (*set_acl)(struct user_namespace *, struct dentry *, struct posix_acl *, int);
int (*fileattr_set)(struct user_namespace *mnt_userns,
struct dentry *dentry, struct fileattr *fa);
int (*fileattr_get)(struct dentry *dentry, struct fileattr *fa);

View file

@ -17,34 +17,64 @@
#include "v9fs_vfs.h"
#include "fid.h"
static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, char *name)
static struct posix_acl *v9fs_fid_get_acl(struct p9_fid *fid, const char *name)
{
ssize_t size;
void *value = NULL;
struct posix_acl *acl = NULL;
size = v9fs_fid_xattr_get(fid, name, NULL, 0);
if (size > 0) {
value = kzalloc(size, GFP_NOFS);
if (!value)
return ERR_PTR(-ENOMEM);
size = v9fs_fid_xattr_get(fid, name, value, size);
if (size > 0) {
acl = posix_acl_from_xattr(&init_user_ns, value, size);
if (IS_ERR(acl))
goto err_out;
}
} else if (size == -ENODATA || size == 0 ||
size == -ENOSYS || size == -EOPNOTSUPP) {
acl = NULL;
} else
acl = ERR_PTR(-EIO);
if (size < 0)
return ERR_PTR(size);
if (size == 0)
return ERR_PTR(-ENODATA);
err_out:
value = kzalloc(size, GFP_NOFS);
if (!value)
return ERR_PTR(-ENOMEM);
size = v9fs_fid_xattr_get(fid, name, value, size);
if (size < 0)
acl = ERR_PTR(size);
else if (size == 0)
acl = ERR_PTR(-ENODATA);
else
acl = posix_acl_from_xattr(&init_user_ns, value, size);
kfree(value);
return acl;
}
static struct posix_acl *v9fs_acl_get(struct dentry *dentry, const char *name)
{
struct p9_fid *fid;
struct posix_acl *acl = NULL;
fid = v9fs_fid_lookup(dentry);
if (IS_ERR(fid))
return ERR_CAST(fid);
acl = v9fs_fid_get_acl(fid, name);
p9_fid_put(fid);
return acl;
}
static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, const char *name)
{
int retval;
struct posix_acl *acl = NULL;
acl = v9fs_fid_get_acl(fid, name);
if (!IS_ERR(acl))
return acl;
retval = PTR_ERR(acl);
if (retval == -ENODATA || retval == -ENOSYS || retval == -EOPNOTSUPP)
return NULL;
/* map everything else to -EIO */
return ERR_PTR(-EIO);
}
int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
{
int retval = 0;
@ -89,7 +119,7 @@ static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type)
return acl;
}
struct posix_acl *v9fs_iop_get_acl(struct inode *inode, int type, bool rcu)
struct posix_acl *v9fs_iop_get_inode_acl(struct inode *inode, int type, bool rcu)
{
struct v9fs_session_info *v9ses;
@ -109,6 +139,112 @@ struct posix_acl *v9fs_iop_get_acl(struct inode *inode, int type, bool rcu)
}
struct posix_acl *v9fs_iop_get_acl(struct user_namespace *mnt_userns,
struct dentry *dentry, int type)
{
struct v9fs_session_info *v9ses;
v9ses = v9fs_dentry2v9ses(dentry);
/* We allow set/get/list of acl when access=client is not specified. */
if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
return v9fs_acl_get(dentry, posix_acl_xattr_name(type));
return v9fs_get_cached_acl(d_inode(dentry), type);
}
int v9fs_iop_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
int retval;
size_t size = 0;
void *value = NULL;
const char *acl_name;
struct v9fs_session_info *v9ses;
struct inode *inode = d_inode(dentry);
if (acl) {
retval = posix_acl_valid(inode->i_sb->s_user_ns, acl);
if (retval)
goto err_out;
size = posix_acl_xattr_size(acl->a_count);
value = kzalloc(size, GFP_NOFS);
if (!value) {
retval = -ENOMEM;
goto err_out;
}
retval = posix_acl_to_xattr(&init_user_ns, acl, value, size);
if (retval < 0)
goto err_out;
}
/*
* set the attribute on the remote. Without even looking at the
* xattr value. We leave it to the server to validate
*/
acl_name = posix_acl_xattr_name(type);
v9ses = v9fs_dentry2v9ses(dentry);
if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) {
retval = v9fs_xattr_set(dentry, acl_name, value, size, 0);
goto err_out;
}
if (S_ISLNK(inode->i_mode)) {
retval = -EOPNOTSUPP;
goto err_out;
}
if (!inode_owner_or_capable(&init_user_ns, inode)) {
retval = -EPERM;
goto err_out;
}
switch (type) {
case ACL_TYPE_ACCESS:
if (acl) {
struct iattr iattr = {};
struct posix_acl *acl_mode = acl;
retval = posix_acl_update_mode(&init_user_ns, inode,
&iattr.ia_mode,
&acl_mode);
if (retval)
goto err_out;
if (!acl_mode) {
/*
* ACL can be represented by the mode bits.
* So don't update ACL below.
*/
kfree(value);
value = NULL;
size = 0;
}
iattr.ia_valid = ATTR_MODE;
/*
* FIXME should we update ctime ?
* What is the following setxattr update the mode ?
*/
v9fs_vfs_setattr_dotl(&init_user_ns, dentry, &iattr);
}
break;
case ACL_TYPE_DEFAULT:
if (!S_ISDIR(inode->i_mode)) {
retval = acl ? -EINVAL : 0;
goto err_out;
}
break;
}
retval = v9fs_xattr_set(dentry, acl_name, value, size, 0);
if (!retval)
set_cached_acl(inode, type, acl);
err_out:
kfree(value);
return retval;
}
static int v9fs_set_acl(struct p9_fid *fid, int type, struct posix_acl *acl)
{
int retval;
@ -207,124 +343,3 @@ int v9fs_acl_mode(struct inode *dir, umode_t *modep,
*modep = mode;
return 0;
}
static int v9fs_xattr_get_acl(const struct xattr_handler *handler,
struct dentry *dentry, struct inode *inode,
const char *name, void *buffer, size_t size)
{
struct v9fs_session_info *v9ses;
struct posix_acl *acl;
int error;
v9ses = v9fs_dentry2v9ses(dentry);
/*
* We allow set/get/list of acl when access=client is not specified
*/
if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
return v9fs_xattr_get(dentry, handler->name, buffer, size);
acl = v9fs_get_cached_acl(inode, handler->flags);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (acl == NULL)
return -ENODATA;
error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
posix_acl_release(acl);
return error;
}
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)
{
int retval;
struct posix_acl *acl;
struct v9fs_session_info *v9ses;
v9ses = v9fs_dentry2v9ses(dentry);
/*
* set the attribute on the remote. Without even looking at the
* xattr value. We leave it to the server to validate
*/
if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
return v9fs_xattr_set(dentry, handler->name, value, size,
flags);
if (S_ISLNK(inode->i_mode))
return -EOPNOTSUPP;
if (!inode_owner_or_capable(&init_user_ns, inode))
return -EPERM;
if (value) {
/* update the cached acl value */
acl = posix_acl_from_xattr(&init_user_ns, value, size);
if (IS_ERR(acl))
return PTR_ERR(acl);
else if (acl) {
retval = posix_acl_valid(inode->i_sb->s_user_ns, acl);
if (retval)
goto err_out;
}
} else
acl = NULL;
switch (handler->flags) {
case ACL_TYPE_ACCESS:
if (acl) {
struct iattr iattr = { 0 };
struct posix_acl *old_acl = acl;
retval = posix_acl_update_mode(&init_user_ns, inode,
&iattr.ia_mode, &acl);
if (retval)
goto err_out;
if (!acl) {
/*
* ACL can be represented
* by the mode bits. So don't
* update ACL.
*/
posix_acl_release(old_acl);
value = NULL;
size = 0;
}
iattr.ia_valid = ATTR_MODE;
/* FIXME should we update ctime ?
* What is the following setxattr update the
* mode ?
*/
v9fs_vfs_setattr_dotl(&init_user_ns, dentry, &iattr);
}
break;
case ACL_TYPE_DEFAULT:
if (!S_ISDIR(inode->i_mode)) {
retval = acl ? -EINVAL : 0;
goto err_out;
}
break;
default:
BUG();
}
retval = v9fs_xattr_set(dentry, handler->name, value, size, flags);
if (!retval)
set_cached_acl(inode, handler->flags, acl);
err_out:
posix_acl_release(acl);
return retval;
}
const struct xattr_handler v9fs_xattr_acl_access_handler = {
.name = XATTR_NAME_POSIX_ACL_ACCESS,
.flags = ACL_TYPE_ACCESS,
.get = v9fs_xattr_get_acl,
.set = v9fs_xattr_set_acl,
};
const struct xattr_handler v9fs_xattr_acl_default_handler = {
.name = XATTR_NAME_POSIX_ACL_DEFAULT,
.flags = ACL_TYPE_DEFAULT,
.get = v9fs_xattr_get_acl,
.set = v9fs_xattr_set_acl,
};

View file

@ -8,8 +8,12 @@
#ifdef CONFIG_9P_FS_POSIX_ACL
int v9fs_get_acl(struct inode *inode, struct p9_fid *fid);
struct posix_acl *v9fs_iop_get_acl(struct inode *inode, int type,
struct posix_acl *v9fs_iop_get_inode_acl(struct inode *inode, int type,
bool rcu);
struct posix_acl *v9fs_iop_get_acl(struct user_namespace *mnt_userns,
struct dentry *dentry, int type);
int v9fs_iop_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
int v9fs_acl_chmod(struct inode *inode, struct p9_fid *fid);
int v9fs_set_create_acl(struct inode *inode, struct p9_fid *fid,
struct posix_acl *dacl, struct posix_acl *acl);
@ -17,7 +21,9 @@ int v9fs_acl_mode(struct inode *dir, umode_t *modep,
struct posix_acl **dpacl, struct posix_acl **pacl);
void v9fs_put_acl(struct posix_acl *dacl, struct posix_acl *acl);
#else
#define v9fs_iop_get_inode_acl NULL
#define v9fs_iop_get_acl NULL
#define v9fs_iop_set_acl NULL
static inline int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
{
return 0;

View file

@ -983,14 +983,18 @@ const struct inode_operations v9fs_dir_inode_operations_dotl = {
.getattr = v9fs_vfs_getattr_dotl,
.setattr = v9fs_vfs_setattr_dotl,
.listxattr = v9fs_listxattr,
.get_inode_acl = v9fs_iop_get_inode_acl,
.get_acl = v9fs_iop_get_acl,
.set_acl = v9fs_iop_set_acl,
};
const struct inode_operations v9fs_file_inode_operations_dotl = {
.getattr = v9fs_vfs_getattr_dotl,
.setattr = v9fs_vfs_setattr_dotl,
.listxattr = v9fs_listxattr,
.get_inode_acl = v9fs_iop_get_inode_acl,
.get_acl = v9fs_iop_get_acl,
.set_acl = v9fs_iop_set_acl,
};
const struct inode_operations v9fs_symlink_inode_operations_dotl = {

View file

@ -8,6 +8,7 @@
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/uio.h>
#include <linux/posix_acl_xattr.h>
#include <net/9p/9p.h>
#include <net/9p/client.h>
@ -182,9 +183,9 @@ static struct xattr_handler v9fs_xattr_security_handler = {
const struct xattr_handler *v9fs_xattr_handlers[] = {
&v9fs_xattr_user_handler,
&v9fs_xattr_trusted_handler,
#ifdef CONFIG_9P_FS_POSIX_ACL
&v9fs_xattr_acl_access_handler,
&v9fs_xattr_acl_default_handler,
#ifdef CONFIG_FS_POSIX_ACL
&posix_acl_access_xattr_handler,
&posix_acl_default_xattr_handler,
#endif
#ifdef CONFIG_9P_FS_SECURITY
&v9fs_xattr_security_handler,

View file

@ -11,8 +11,6 @@
#include <net/9p/client.h>
extern const struct xattr_handler *v9fs_xattr_handlers[];
extern const struct xattr_handler v9fs_xattr_acl_access_handler;
extern const struct xattr_handler v9fs_xattr_acl_default_handler;
ssize_t v9fs_fid_xattr_get(struct p9_fid *fid, const char *name,
void *buffer, size_t buffer_size);

View file

@ -154,7 +154,7 @@ static int bad_inode_tmpfile(struct user_namespace *mnt_userns,
}
static int bad_inode_set_acl(struct user_namespace *mnt_userns,
struct inode *inode, struct posix_acl *acl,
struct dentry *dentry, struct posix_acl *acl,
int type)
{
return -EIO;
@ -177,7 +177,7 @@ static const struct inode_operations bad_inode_ops =
.setattr = bad_inode_setattr,
.listxattr = bad_inode_listxattr,
.get_link = bad_inode_get_link,
.get_acl = bad_inode_get_acl,
.get_inode_acl = bad_inode_get_acl,
.fiemap = bad_inode_fiemap,
.update_time = bad_inode_update_time,
.atomic_open = bad_inode_atomic_open,

View file

@ -110,10 +110,11 @@ int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode,
return ret;
}
int btrfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
int btrfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
int ret;
struct inode *inode = d_inode(dentry);
umode_t old_mode = inode->i_mode;
if (type == ACL_TYPE_ACCESS && acl) {

View file

@ -3987,7 +3987,7 @@ 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, bool rcu);
int btrfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
int btrfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode,
struct posix_acl *acl, int type);

View file

@ -5256,7 +5256,7 @@ static int btrfs_setattr(struct user_namespace *mnt_userns, struct dentry *dentr
err = btrfs_dirty_inode(inode);
if (!err && attr->ia_valid & ATTR_MODE)
err = posix_acl_chmod(mnt_userns, inode, inode->i_mode);
err = posix_acl_chmod(mnt_userns, dentry, inode->i_mode);
}
return err;
@ -11288,7 +11288,7 @@ static const struct inode_operations btrfs_dir_inode_operations = {
.mknod = btrfs_mknod,
.listxattr = btrfs_listxattr,
.permission = btrfs_permission,
.get_acl = btrfs_get_acl,
.get_inode_acl = btrfs_get_acl,
.set_acl = btrfs_set_acl,
.update_time = btrfs_update_time,
.tmpfile = btrfs_tmpfile,
@ -11341,7 +11341,7 @@ static const struct inode_operations btrfs_file_inode_operations = {
.listxattr = btrfs_listxattr,
.permission = btrfs_permission,
.fiemap = btrfs_fiemap,
.get_acl = btrfs_get_acl,
.get_inode_acl = btrfs_get_acl,
.set_acl = btrfs_set_acl,
.update_time = btrfs_update_time,
.fileattr_get = btrfs_fileattr_get,
@ -11352,7 +11352,7 @@ static const struct inode_operations btrfs_special_inode_operations = {
.setattr = btrfs_setattr,
.permission = btrfs_permission,
.listxattr = btrfs_listxattr,
.get_acl = btrfs_get_acl,
.get_inode_acl = btrfs_get_acl,
.set_acl = btrfs_set_acl,
.update_time = btrfs_update_time,
};

View file

@ -85,13 +85,14 @@ struct posix_acl *ceph_get_acl(struct inode *inode, int type, bool rcu)
return acl;
}
int ceph_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
int ceph_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
int ret = 0, size = 0;
const char *name = NULL;
char *value = NULL;
struct iattr newattrs;
struct inode *inode = d_inode(dentry);
struct timespec64 old_ctime = inode->i_ctime;
umode_t new_mode = inode->i_mode, old_mode = inode->i_mode;

View file

@ -2033,7 +2033,7 @@ const struct inode_operations ceph_dir_iops = {
.getattr = ceph_getattr,
.setattr = ceph_setattr,
.listxattr = ceph_listxattr,
.get_acl = ceph_get_acl,
.get_inode_acl = ceph_get_acl,
.set_acl = ceph_set_acl,
.mknod = ceph_mknod,
.symlink = ceph_symlink,

View file

@ -126,7 +126,7 @@ const struct inode_operations ceph_file_iops = {
.setattr = ceph_setattr,
.getattr = ceph_getattr,
.listxattr = ceph_listxattr,
.get_acl = ceph_get_acl,
.get_inode_acl = ceph_get_acl,
.set_acl = ceph_set_acl,
};
@ -2255,7 +2255,7 @@ int ceph_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
err = __ceph_setattr(inode, attr);
if (err >= 0 && (attr->ia_valid & ATTR_MODE))
err = posix_acl_chmod(&init_user_ns, inode, attr->ia_mode);
err = posix_acl_chmod(&init_user_ns, dentry, attr->ia_mode);
return err;
}

View file

@ -1117,7 +1117,7 @@ void ceph_release_acl_sec_ctx(struct ceph_acl_sec_ctx *as_ctx);
struct posix_acl *ceph_get_acl(struct inode *, int, bool);
int ceph_set_acl(struct user_namespace *mnt_userns,
struct inode *inode, struct posix_acl *acl, int type);
struct dentry *dentry, 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,

View file

@ -13,6 +13,9 @@
#include <linux/string.h>
#include <linux/keyctl.h>
#include <linux/key-type.h>
#include <uapi/linux/posix_acl.h>
#include <linux/posix_acl.h>
#include <linux/posix_acl_xattr.h>
#include <keys/user-type.h>
#include "cifspdu.h"
#include "cifsglob.h"
@ -20,6 +23,8 @@
#include "cifsproto.h"
#include "cifs_debug.h"
#include "fs_context.h"
#include "cifs_fs_sb.h"
#include "cifs_unicode.h"
/* security id for everyone/world system group */
static const struct cifs_sid sid_everyone = {
@ -1668,3 +1673,137 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
kfree(pntsd);
return rc;
}
struct posix_acl *cifs_get_acl(struct user_namespace *mnt_userns,
struct dentry *dentry, int type)
{
#if defined(CONFIG_CIFS_ALLOW_INSECURE_LEGACY) && defined(CONFIG_CIFS_POSIX)
struct posix_acl *acl = NULL;
ssize_t rc = -EOPNOTSUPP;
unsigned int xid;
struct super_block *sb = dentry->d_sb;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct tcon_link *tlink;
struct cifs_tcon *pTcon;
const char *full_path;
void *page;
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return ERR_CAST(tlink);
pTcon = tlink_tcon(tlink);
xid = get_xid();
page = alloc_dentry_path();
full_path = build_path_from_dentry(dentry, page);
if (IS_ERR(full_path)) {
acl = ERR_CAST(full_path);
goto out;
}
/* return alt name if available as pseudo attr */
switch (type) {
case ACL_TYPE_ACCESS:
if (sb->s_flags & SB_POSIXACL)
rc = cifs_do_get_acl(xid, pTcon, full_path, &acl,
ACL_TYPE_ACCESS,
cifs_sb->local_nls,
cifs_remap(cifs_sb));
break;
case ACL_TYPE_DEFAULT:
if (sb->s_flags & SB_POSIXACL)
rc = cifs_do_get_acl(xid, pTcon, full_path, &acl,
ACL_TYPE_DEFAULT,
cifs_sb->local_nls,
cifs_remap(cifs_sb));
break;
}
if (rc < 0) {
if (rc == -EINVAL)
acl = ERR_PTR(-EOPNOTSUPP);
else
acl = ERR_PTR(rc);
}
out:
free_dentry_path(page);
free_xid(xid);
cifs_put_tlink(tlink);
return acl;
#else
return ERR_PTR(-EOPNOTSUPP);
#endif
}
int cifs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
#if defined(CONFIG_CIFS_ALLOW_INSECURE_LEGACY) && defined(CONFIG_CIFS_POSIX)
int rc = -EOPNOTSUPP;
unsigned int xid;
struct super_block *sb = dentry->d_sb;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct tcon_link *tlink;
struct cifs_tcon *pTcon;
const char *full_path;
void *page;
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return PTR_ERR(tlink);
pTcon = tlink_tcon(tlink);
xid = get_xid();
page = alloc_dentry_path();
full_path = build_path_from_dentry(dentry, page);
if (IS_ERR(full_path)) {
rc = PTR_ERR(full_path);
goto out;
}
/* return dos attributes as pseudo xattr */
/* return alt name if available as pseudo attr */
/* if proc/fs/cifs/streamstoxattr is set then
search server for EAs or streams to
returns as xattrs */
if (posix_acl_xattr_size(acl->a_count) > CIFSMaxBufSize) {
cifs_dbg(FYI, "size of EA value too large\n");
rc = -EOPNOTSUPP;
goto out;
}
switch (type) {
case ACL_TYPE_ACCESS:
if (!acl)
goto out;
if (sb->s_flags & SB_POSIXACL)
rc = cifs_do_set_acl(xid, pTcon, full_path, acl,
ACL_TYPE_ACCESS,
cifs_sb->local_nls,
cifs_remap(cifs_sb));
break;
case ACL_TYPE_DEFAULT:
if (!acl)
goto out;
if (sb->s_flags & SB_POSIXACL)
rc = cifs_do_set_acl(xid, pTcon, full_path, acl,
ACL_TYPE_DEFAULT,
cifs_sb->local_nls,
cifs_remap(cifs_sb));
break;
}
out:
free_dentry_path(page);
free_xid(xid);
cifs_put_tlink(tlink);
return rc;
#else
return -EOPNOTSUPP;
#endif
}

View file

@ -1133,6 +1133,8 @@ const struct inode_operations cifs_dir_inode_ops = {
.symlink = cifs_symlink,
.mknod = cifs_mknod,
.listxattr = cifs_listxattr,
.get_acl = cifs_get_acl,
.set_acl = cifs_set_acl,
};
const struct inode_operations cifs_file_inode_ops = {
@ -1141,6 +1143,8 @@ const struct inode_operations cifs_file_inode_ops = {
.permission = cifs_permission,
.listxattr = cifs_listxattr,
.fiemap = cifs_fiemap,
.get_acl = cifs_get_acl,
.set_acl = cifs_set_acl,
};
const struct inode_operations cifs_symlink_inode_ops = {

View file

@ -224,6 +224,10 @@ extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *,
const char *, u32 *, u32);
extern struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *,
const struct cifs_fid *, u32 *, u32);
extern struct posix_acl *cifs_get_acl(struct user_namespace *mnt_userns,
struct dentry *dentry, int type);
extern int cifs_set_acl(struct user_namespace *mnt_userns,
struct dentry *dentry, struct posix_acl *acl, int type);
extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *,
const char *, int);
extern unsigned int setup_authusers_ACE(struct cifs_ace *pace);
@ -537,14 +541,14 @@ extern int CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon,
__u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen);
extern int CIFSSMBSetCIFSACL(const unsigned int, struct cifs_tcon *, __u16,
struct cifs_ntsd *, __u32, int);
extern int CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
const unsigned char *searchName,
char *acl_inf, const int buflen, const int acl_type,
const struct nls_table *nls_codepage, int remap_special_chars);
extern int CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
const unsigned char *fileName,
const char *local_acl, const int buflen, const int acl_type,
const struct nls_table *nls_codepage, int remap_special_chars);
extern int cifs_do_get_acl(const unsigned int xid, struct cifs_tcon *tcon,
const unsigned char *searchName,
struct posix_acl **acl, const int acl_type,
const struct nls_table *nls_codepage, int remap);
extern int cifs_do_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
const unsigned char *fileName,
const struct posix_acl *acl, const int acl_type,
const struct nls_table *nls_codepage, int remap);
extern int CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
const int netfid, __u64 *pExtAttrBits, __u64 *pMask);
#endif /* CIFS_ALLOW_INSECURE_LEGACY */

View file

@ -2914,32 +2914,57 @@ CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
#ifdef CONFIG_CIFS_POSIX
/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
struct cifs_posix_ace *cifs_ace)
#ifdef CONFIG_FS_POSIX_ACL
/**
* cifs_init_posix_acl - convert ACL from cifs to POSIX ACL format
* @ace: POSIX ACL entry to store converted ACL into
* @cifs_ace: ACL in cifs format
*
* Convert an Access Control Entry from wire format to local POSIX xattr
* format.
*
* Note that the @cifs_uid member is used to store both {g,u}id_t.
*/
static void cifs_init_posix_acl(struct posix_acl_entry *ace,
struct cifs_posix_ace *cifs_ace)
{
/* u8 cifs fields do not need le conversion */
ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
/*
cifs_dbg(FYI, "perm %d tag %d id %d\n",
ace->e_perm, ace->e_tag, ace->e_id);
*/
ace->e_perm = cifs_ace->cifs_e_perm;
ace->e_tag = cifs_ace->cifs_e_tag;
switch (ace->e_tag) {
case ACL_USER:
ace->e_uid = make_kuid(&init_user_ns,
le64_to_cpu(cifs_ace->cifs_uid));
break;
case ACL_GROUP:
ace->e_gid = make_kgid(&init_user_ns,
le64_to_cpu(cifs_ace->cifs_uid));
break;
}
return;
}
/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
const int acl_type, const int size_of_data_area)
/**
* cifs_to_posix_acl - copy cifs ACL format to POSIX ACL format
* @acl: ACLs returned in POSIX ACL format
* @src: ACLs in cifs format
* @acl_type: type of POSIX ACL requested
* @size_of_data_area: size of SMB we got
*
* This function converts ACLs from cifs format to POSIX ACL format.
* If @acl is NULL then the size of the buffer required to store POSIX ACLs in
* their uapi format is returned.
*/
static int cifs_to_posix_acl(struct posix_acl **acl, char *src,
const int acl_type, const int size_of_data_area)
{
int size = 0;
int i;
__u16 count;
struct cifs_posix_ace *pACE;
struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
struct posix_acl_xattr_header *local_acl = (void *)trgt;
struct posix_acl *kacl = NULL;
struct posix_acl_entry *pa, *pe;
if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
return -EOPNOTSUPP;
@ -2959,7 +2984,7 @@ static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
count = le16_to_cpu(cifs_acl->access_entry_count);
size = sizeof(struct cifs_posix_acl);
size += sizeof(struct cifs_posix_ace) * count;
/* skip past access ACEs to get to default ACEs */
/* skip past access ACEs to get to default ACEs */
pACE = &cifs_acl->ace_array[count];
count = le16_to_cpu(cifs_acl->default_entry_count);
size += sizeof(struct cifs_posix_ace) * count;
@ -2971,62 +2996,75 @@ static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
return -EINVAL;
}
size = posix_acl_xattr_size(count);
if ((buflen == 0) || (local_acl == NULL)) {
/* used to query ACL EA size */
} else if (size > buflen) {
return -ERANGE;
} else /* buffer big enough */ {
struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
/* Allocate number of POSIX ACLs to store in VFS format. */
kacl = posix_acl_alloc(count, GFP_NOFS);
if (!kacl)
return -ENOMEM;
local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
for (i = 0; i < count ; i++) {
cifs_convert_ace(&ace[i], pACE);
pACE++;
}
FOREACH_ACL_ENTRY(pa, kacl, pe) {
cifs_init_posix_acl(pa, pACE);
pACE++;
}
return size;
*acl = kacl;
return 0;
}
static void convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
const struct posix_acl_xattr_entry *local_ace)
/**
* cifs_init_ace - convert ACL entry from POSIX ACL to cifs format
* @cifs_ace: the cifs ACL entry to store into
* @local_ace: the POSIX ACL entry to convert
*/
static void cifs_init_ace(struct cifs_posix_ace *cifs_ace,
const struct posix_acl_entry *local_ace)
{
cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
/* BB is there a better way to handle the large uid? */
if (local_ace->e_id == cpu_to_le32(-1)) {
/* Probably no need to le convert -1 on any arch but can not hurt */
cifs_ace->cifs_e_perm = local_ace->e_perm;
cifs_ace->cifs_e_tag = local_ace->e_tag;
switch (local_ace->e_tag) {
case ACL_USER:
cifs_ace->cifs_uid =
cpu_to_le64(from_kuid(&init_user_ns, local_ace->e_uid));
break;
case ACL_GROUP:
cifs_ace->cifs_uid =
cpu_to_le64(from_kgid(&init_user_ns, local_ace->e_gid));
break;
default:
cifs_ace->cifs_uid = cpu_to_le64(-1);
} else
cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
/*
cifs_dbg(FYI, "perm %d tag %d id %d\n",
ace->e_perm, ace->e_tag, ace->e_id);
*/
}
}
/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
const int buflen, const int acl_type)
/**
* posix_acl_to_cifs - convert ACLs from POSIX ACL to cifs format
* @parm_data: ACLs in cifs format to conver to
* @acl: ACLs in POSIX ACL format to convert from
* @acl_type: the type of POSIX ACLs stored in @acl
*
* Return: the number cifs ACL entries after conversion
*/
static __u16 posix_acl_to_cifs(char *parm_data, const struct posix_acl *acl,
const int acl_type)
{
__u16 rc = 0;
struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
struct posix_acl_xattr_header *local_acl = (void *)pACL;
struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
const struct posix_acl_entry *pa, *pe;
int count;
int i;
int i = 0;
if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
if ((acl == NULL) || (cifs_acl == NULL))
return 0;
count = posix_acl_xattr_count((size_t)buflen);
cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
count, buflen, le32_to_cpu(local_acl->a_version));
if (le32_to_cpu(local_acl->a_version) != 2) {
cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
le32_to_cpu(local_acl->a_version));
return 0;
}
count = acl->a_count;
cifs_dbg(FYI, "setting acl with %d entries\n", count);
/*
* Note that the uapi POSIX ACL version is verified by the VFS and is
* independent of the cifs ACL version. Changing the POSIX ACL version
* is a uapi change and if it's changed we will pass down the POSIX ACL
* version in struct posix_acl from the VFS. For now there's really
* only one that all filesystems know how to deal with.
*/
cifs_acl->version = cpu_to_le16(1);
if (acl_type == ACL_TYPE_ACCESS) {
cifs_acl->access_entry_count = cpu_to_le16(count);
@ -3038,8 +3076,9 @@ static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
return 0;
}
for (i = 0; i < count; i++)
convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
FOREACH_ACL_ENTRY(pa, acl, pe) {
cifs_init_ace(&cifs_acl->ace_array[i++], pa);
}
if (rc == 0) {
rc = (__u16)(count * sizeof(struct cifs_posix_ace));
rc += sizeof(struct cifs_posix_acl);
@ -3048,11 +3087,10 @@ static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
return rc;
}
int
CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
const unsigned char *searchName,
char *acl_inf, const int buflen, const int acl_type,
const struct nls_table *nls_codepage, int remap)
int cifs_do_get_acl(const unsigned int xid, struct cifs_tcon *tcon,
const unsigned char *searchName, struct posix_acl **acl,
const int acl_type, const struct nls_table *nls_codepage,
int remap)
{
/* SMB_QUERY_POSIX_ACL */
TRANSACTION2_QPI_REQ *pSMB = NULL;
@ -3124,23 +3162,26 @@ CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
else {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
rc = cifs_copy_posix_acl(acl_inf,
rc = cifs_to_posix_acl(acl,
(char *)&pSMBr->hdr.Protocol+data_offset,
buflen, acl_type, count);
acl_type, count);
}
}
cifs_buf_release(pSMB);
/*
* The else branch after SendReceive() doesn't return EAGAIN so if we
* allocated @acl in cifs_to_posix_acl() we are guaranteed to return
* here and don't leak POSIX ACLs.
*/
if (rc == -EAGAIN)
goto queryAclRetry;
return rc;
}
int
CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
const unsigned char *fileName,
const char *local_acl, const int buflen,
const int acl_type,
const struct nls_table *nls_codepage, int remap)
int cifs_do_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
const unsigned char *fileName, const struct posix_acl *acl,
const int acl_type, const struct nls_table *nls_codepage,
int remap)
{
struct smb_com_transaction2_spi_req *pSMB = NULL;
struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
@ -3181,7 +3222,7 @@ CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
pSMB->ParameterOffset = cpu_to_le16(param_offset);
/* convert to on the wire format for POSIX ACL */
data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
data_count = posix_acl_to_cifs(parm_data, acl, acl_type);
if (data_count == 0) {
rc = -EOPNOTSUPP;
@ -3211,6 +3252,23 @@ CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
goto setAclRetry;
return rc;
}
#else
int cifs_do_get_acl(const unsigned int xid, struct cifs_tcon *tcon,
const unsigned char *searchName, struct posix_acl **acl,
const int acl_type, const struct nls_table *nls_codepage,
int remap)
{
return -EOPNOTSUPP;
}
int cifs_do_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
const unsigned char *fileName, const struct posix_acl *acl,
const int acl_type, const struct nls_table *nls_codepage,
int remap)
{
return -EOPNOTSUPP;
}
#endif /* CONFIG_FS_POSIX_ACL */
int
CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,

View file

@ -200,32 +200,6 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
}
break;
}
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
case XATTR_ACL_ACCESS:
#ifdef CONFIG_CIFS_POSIX
if (!value)
goto out;
if (sb->s_flags & SB_POSIXACL)
rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
value, (const int)size,
ACL_TYPE_ACCESS, cifs_sb->local_nls,
cifs_remap(cifs_sb));
#endif /* CONFIG_CIFS_POSIX */
break;
case XATTR_ACL_DEFAULT:
#ifdef CONFIG_CIFS_POSIX
if (!value)
goto out;
if (sb->s_flags & SB_POSIXACL)
rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
value, (const int)size,
ACL_TYPE_DEFAULT, cifs_sb->local_nls,
cifs_remap(cifs_sb));
#endif /* CONFIG_CIFS_POSIX */
break;
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
}
out:
@ -366,27 +340,6 @@ static int cifs_xattr_get(const struct xattr_handler *handler,
}
break;
}
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
case XATTR_ACL_ACCESS:
#ifdef CONFIG_CIFS_POSIX
if (sb->s_flags & SB_POSIXACL)
rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
value, size, ACL_TYPE_ACCESS,
cifs_sb->local_nls,
cifs_remap(cifs_sb));
#endif /* CONFIG_CIFS_POSIX */
break;
case XATTR_ACL_DEFAULT:
#ifdef CONFIG_CIFS_POSIX
if (sb->s_flags & SB_POSIXACL)
rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
value, size, ACL_TYPE_DEFAULT,
cifs_sb->local_nls,
cifs_remap(cifs_sb));
#endif /* CONFIG_CIFS_POSIX */
break;
#endif /* ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
}
/* We could add an additional check for streams ie
@ -525,21 +478,6 @@ static const struct xattr_handler smb3_ntsd_full_xattr_handler = {
.set = cifs_xattr_set,
};
static const struct xattr_handler cifs_posix_acl_access_xattr_handler = {
.name = XATTR_NAME_POSIX_ACL_ACCESS,
.flags = XATTR_ACL_ACCESS,
.get = cifs_xattr_get,
.set = cifs_xattr_set,
};
static const struct xattr_handler cifs_posix_acl_default_xattr_handler = {
.name = XATTR_NAME_POSIX_ACL_DEFAULT,
.flags = XATTR_ACL_DEFAULT,
.get = cifs_xattr_get,
.set = cifs_xattr_set,
};
const struct xattr_handler *cifs_xattr_handlers[] = {
&cifs_user_xattr_handler,
&cifs_os2_xattr_handler,
@ -549,7 +487,9 @@ const struct xattr_handler *cifs_xattr_handlers[] = {
&smb3_ntsd_xattr_handler, /* alias for above since avoiding "cifs" */
&cifs_cifs_ntsd_full_xattr_handler,
&smb3_ntsd_full_xattr_handler, /* alias for above since avoiding "cifs" */
&cifs_posix_acl_access_xattr_handler,
&cifs_posix_acl_default_xattr_handler,
#ifdef CONFIG_FS_POSIX_ACL
&posix_acl_access_xattr_handler,
&posix_acl_default_xattr_handler,
#endif
NULL
};

View file

@ -18,6 +18,8 @@
#include <linux/fs_stack.h>
#include <linux/slab.h>
#include <linux/xattr.h>
#include <linux/posix_acl.h>
#include <linux/posix_acl_xattr.h>
#include <linux/fileattr.h>
#include <asm/unaligned.h>
#include "ecryptfs_kernel.h"
@ -1120,6 +1122,28 @@ static int ecryptfs_fileattr_set(struct user_namespace *mnt_userns,
return rc;
}
static struct posix_acl *ecryptfs_get_acl(struct user_namespace *mnt_userns,
struct dentry *dentry, int type)
{
return vfs_get_acl(mnt_userns, ecryptfs_dentry_to_lower(dentry),
posix_acl_xattr_name(type));
}
static int ecryptfs_set_acl(struct user_namespace *mnt_userns,
struct dentry *dentry, struct posix_acl *acl,
int type)
{
int rc;
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
struct inode *lower_inode = d_inode(lower_dentry);
rc = vfs_set_acl(&init_user_ns, lower_dentry,
posix_acl_xattr_name(type), acl);
if (!rc)
fsstack_copy_attr_all(d_inode(dentry), lower_inode);
return rc;
}
const struct inode_operations ecryptfs_symlink_iops = {
.get_link = ecryptfs_get_link,
.permission = ecryptfs_permission,
@ -1143,6 +1167,8 @@ const struct inode_operations ecryptfs_dir_iops = {
.listxattr = ecryptfs_listxattr,
.fileattr_get = ecryptfs_fileattr_get,
.fileattr_set = ecryptfs_fileattr_set,
.get_acl = ecryptfs_get_acl,
.set_acl = ecryptfs_set_acl,
};
const struct inode_operations ecryptfs_main_iops = {
@ -1152,6 +1178,8 @@ const struct inode_operations ecryptfs_main_iops = {
.listxattr = ecryptfs_listxattr,
.fileattr_get = ecryptfs_fileattr_get,
.fileattr_set = ecryptfs_fileattr_set,
.get_acl = ecryptfs_get_acl,
.set_acl = ecryptfs_set_acl,
};
static int ecryptfs_xattr_get(const struct xattr_handler *handler,
@ -1182,6 +1210,10 @@ static const struct xattr_handler ecryptfs_xattr_handler = {
};
const struct xattr_handler *ecryptfs_xattr_handlers[] = {
#ifdef CONFIG_FS_POSIX_ACL
&posix_acl_access_xattr_handler,
&posix_acl_default_xattr_handler,
#endif
&ecryptfs_xattr_handler,
NULL
};

View file

@ -371,7 +371,7 @@ int erofs_getattr(struct user_namespace *mnt_userns, const struct path *path,
const struct inode_operations erofs_generic_iops = {
.getattr = erofs_getattr,
.listxattr = erofs_listxattr,
.get_acl = erofs_get_acl,
.get_inode_acl = erofs_get_acl,
.fiemap = erofs_fiemap,
};
@ -379,12 +379,12 @@ const struct inode_operations erofs_symlink_iops = {
.get_link = page_get_link,
.getattr = erofs_getattr,
.listxattr = erofs_listxattr,
.get_acl = erofs_get_acl,
.get_inode_acl = erofs_get_acl,
};
const struct inode_operations erofs_fast_symlink_iops = {
.get_link = simple_get_link,
.getattr = erofs_getattr,
.listxattr = erofs_listxattr,
.get_acl = erofs_get_acl,
.get_inode_acl = erofs_get_acl,
};

View file

@ -228,6 +228,6 @@ const struct inode_operations erofs_dir_iops = {
.lookup = erofs_lookup,
.getattr = erofs_getattr,
.listxattr = erofs_listxattr,
.get_acl = erofs_get_acl,
.get_inode_acl = erofs_get_acl,
.fiemap = erofs_fiemap,
};

View file

@ -219,11 +219,12 @@ __ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
* inode->i_mutex: down
*/
int
ext2_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
ext2_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
int error;
int update_mode = 0;
struct inode *inode = d_inode(dentry);
umode_t mode = inode->i_mode;
if (type == ACL_TYPE_ACCESS && acl) {

View file

@ -56,7 +56,7 @@ static inline int ext2_acl_count(size_t size)
/* acl.c */
extern struct posix_acl *ext2_get_acl(struct inode *inode, int type, bool rcu);
extern int ext2_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
extern int ext2_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
extern int ext2_init_acl (struct inode *, struct inode *);

View file

@ -200,7 +200,7 @@ const struct inode_operations ext2_file_inode_operations = {
.listxattr = ext2_listxattr,
.getattr = ext2_getattr,
.setattr = ext2_setattr,
.get_acl = ext2_get_acl,
.get_inode_acl = ext2_get_acl,
.set_acl = ext2_set_acl,
.fiemap = ext2_fiemap,
.fileattr_get = ext2_fileattr_get,

View file

@ -1652,7 +1652,7 @@ int ext2_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
}
setattr_copy(&init_user_ns, inode, iattr);
if (iattr->ia_valid & ATTR_MODE)
error = posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
error = posix_acl_chmod(&init_user_ns, dentry, inode->i_mode);
mark_inode_dirty(inode);
return error;

View file

@ -427,7 +427,7 @@ const struct inode_operations ext2_dir_inode_operations = {
.listxattr = ext2_listxattr,
.getattr = ext2_getattr,
.setattr = ext2_setattr,
.get_acl = ext2_get_acl,
.get_inode_acl = ext2_get_acl,
.set_acl = ext2_set_acl,
.tmpfile = ext2_tmpfile,
.fileattr_get = ext2_fileattr_get,
@ -438,6 +438,6 @@ const struct inode_operations ext2_special_inode_operations = {
.listxattr = ext2_listxattr,
.getattr = ext2_getattr,
.setattr = ext2_setattr,
.get_acl = ext2_get_acl,
.get_inode_acl = ext2_get_acl,
.set_acl = ext2_set_acl,
};

View file

@ -225,12 +225,13 @@ __ext4_set_acl(handle_t *handle, struct inode *inode, int type,
}
int
ext4_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
ext4_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
handle_t *handle;
int error, credits, retries = 0;
size_t acl_size = acl ? ext4_acl_size(acl->a_count) : 0;
struct inode *inode = d_inode(dentry);
umode_t mode = inode->i_mode;
int update_mode = 0;

View file

@ -56,7 +56,7 @@ static inline int ext4_acl_count(size_t size)
/* acl.c */
struct posix_acl *ext4_get_acl(struct inode *inode, int type, bool rcu);
int ext4_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
int ext4_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
extern int ext4_init_acl(handle_t *, struct inode *, struct inode *);

View file

@ -955,7 +955,7 @@ const struct inode_operations ext4_file_inode_operations = {
.setattr = ext4_setattr,
.getattr = ext4_file_getattr,
.listxattr = ext4_listxattr,
.get_acl = ext4_get_acl,
.get_inode_acl = ext4_get_acl,
.set_acl = ext4_set_acl,
.fiemap = ext4_fiemap,
.fileattr_get = ext4_fileattr_get,

View file

@ -870,7 +870,7 @@ static int ext4_xattr_credits_for_new_inode(struct inode *dir, mode_t mode,
struct super_block *sb = dir->i_sb;
int nblocks = 0;
#ifdef CONFIG_EXT4_FS_POSIX_ACL
struct posix_acl *p = get_acl(dir, ACL_TYPE_DEFAULT);
struct posix_acl *p = get_inode_acl(dir, ACL_TYPE_DEFAULT);
if (IS_ERR(p))
return PTR_ERR(p);

View file

@ -5550,7 +5550,7 @@ int ext4_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
ext4_orphan_del(NULL, inode);
if (!error && (ia_valid & ATTR_MODE))
rc = posix_acl_chmod(mnt_userns, inode, inode->i_mode);
rc = posix_acl_chmod(mnt_userns, dentry, inode->i_mode);
err_out:
if (error)

View file

@ -4186,7 +4186,7 @@ const struct inode_operations ext4_dir_inode_operations = {
.setattr = ext4_setattr,
.getattr = ext4_getattr,
.listxattr = ext4_listxattr,
.get_acl = ext4_get_acl,
.get_inode_acl = ext4_get_acl,
.set_acl = ext4_set_acl,
.fiemap = ext4_fiemap,
.fileattr_get = ext4_fileattr_get,
@ -4197,6 +4197,6 @@ const struct inode_operations ext4_special_inode_operations = {
.setattr = ext4_setattr,
.getattr = ext4_getattr,
.listxattr = ext4_listxattr,
.get_acl = ext4_get_acl,
.get_inode_acl = ext4_get_acl,
.set_acl = ext4_set_acl,
};

View file

@ -276,9 +276,11 @@ static int __f2fs_set_acl(struct user_namespace *mnt_userns,
return error;
}
int f2fs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
int f2fs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
struct inode *inode = d_inode(dentry);
if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
return -EIO;

View file

@ -34,7 +34,7 @@ struct f2fs_acl_header {
#ifdef CONFIG_F2FS_FS_POSIX_ACL
extern struct posix_acl *f2fs_get_acl(struct inode *, int, bool);
extern int f2fs_set_acl(struct user_namespace *, struct inode *,
extern int f2fs_set_acl(struct user_namespace *, struct dentry *,
struct posix_acl *, int);
extern int f2fs_init_acl(struct inode *, struct inode *, struct page *,
struct page *);

View file

@ -1025,7 +1025,7 @@ int f2fs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
__setattr_copy(mnt_userns, inode, attr);
if (attr->ia_valid & ATTR_MODE) {
err = posix_acl_chmod(mnt_userns, inode, f2fs_get_inode_mode(inode));
err = posix_acl_chmod(mnt_userns, dentry, f2fs_get_inode_mode(inode));
if (is_inode_flag_set(inode, FI_ACL_MODE)) {
if (!err)
@ -1046,7 +1046,7 @@ int f2fs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
const struct inode_operations f2fs_file_inode_operations = {
.getattr = f2fs_getattr,
.setattr = f2fs_setattr,
.get_acl = f2fs_get_acl,
.get_inode_acl = f2fs_get_acl,
.set_acl = f2fs_set_acl,
.listxattr = f2fs_listxattr,
.fiemap = f2fs_fiemap,

View file

@ -1379,7 +1379,7 @@ const struct inode_operations f2fs_dir_inode_operations = {
.tmpfile = f2fs_tmpfile,
.getattr = f2fs_getattr,
.setattr = f2fs_setattr,
.get_acl = f2fs_get_acl,
.get_inode_acl = f2fs_get_acl,
.set_acl = f2fs_set_acl,
.listxattr = f2fs_listxattr,
.fiemap = f2fs_fiemap,
@ -1397,7 +1397,7 @@ const struct inode_operations f2fs_symlink_inode_operations = {
const struct inode_operations f2fs_special_inode_operations = {
.getattr = f2fs_getattr,
.setattr = f2fs_setattr,
.get_acl = f2fs_get_acl,
.get_inode_acl = f2fs_get_acl,
.set_acl = f2fs_set_acl,
.listxattr = f2fs_listxattr,
};

View file

@ -53,9 +53,10 @@ struct posix_acl *fuse_get_acl(struct inode *inode, int type, bool rcu)
return acl;
}
int fuse_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
int fuse_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
struct inode *inode = d_inode(dentry);
struct fuse_conn *fc = get_fuse_conn(inode);
const char *name;
int ret;

View file

@ -1935,7 +1935,7 @@ static const struct inode_operations fuse_dir_inode_operations = {
.permission = fuse_permission,
.getattr = fuse_getattr,
.listxattr = fuse_listxattr,
.get_acl = fuse_get_acl,
.get_inode_acl = fuse_get_acl,
.set_acl = fuse_set_acl,
.fileattr_get = fuse_fileattr_get,
.fileattr_set = fuse_fileattr_set,
@ -1957,7 +1957,7 @@ static const struct inode_operations fuse_common_inode_operations = {
.permission = fuse_permission,
.getattr = fuse_getattr,
.listxattr = fuse_listxattr,
.get_acl = fuse_get_acl,
.get_inode_acl = fuse_get_acl,
.set_acl = fuse_set_acl,
.fileattr_get = fuse_fileattr_get,
.fileattr_set = fuse_fileattr_set,

View file

@ -1269,7 +1269,7 @@ extern const struct xattr_handler *fuse_no_acl_xattr_handlers[];
struct posix_acl;
struct posix_acl *fuse_get_acl(struct inode *inode, int type, bool rcu);
int fuse_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
int fuse_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
/* readdir.c */

View file

@ -109,9 +109,10 @@ int __gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
return error;
}
int gfs2_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
int gfs2_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
struct inode *inode = d_inode(dentry);
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder gh;
bool need_unlock = false;

View file

@ -13,7 +13,7 @@
extern struct posix_acl *gfs2_get_acl(struct inode *inode, int type, bool rcu);
extern int __gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type);
extern int gfs2_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
extern int gfs2_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
#endif /* __ACL_DOT_H__ */

View file

@ -1997,7 +1997,7 @@ static int gfs2_setattr(struct user_namespace *mnt_userns,
else {
error = gfs2_setattr_simple(inode, attr);
if (!error && attr->ia_valid & ATTR_MODE)
error = posix_acl_chmod(&init_user_ns, inode,
error = posix_acl_chmod(&init_user_ns, dentry,
inode->i_mode);
}
@ -2149,7 +2149,7 @@ static const struct inode_operations gfs2_file_iops = {
.getattr = gfs2_getattr,
.listxattr = gfs2_listxattr,
.fiemap = gfs2_fiemap,
.get_acl = gfs2_get_acl,
.get_inode_acl = gfs2_get_acl,
.set_acl = gfs2_set_acl,
.update_time = gfs2_update_time,
.fileattr_get = gfs2_fileattr_get,
@ -2171,7 +2171,7 @@ static const struct inode_operations gfs2_dir_iops = {
.getattr = gfs2_getattr,
.listxattr = gfs2_listxattr,
.fiemap = gfs2_fiemap,
.get_acl = gfs2_get_acl,
.get_inode_acl = gfs2_get_acl,
.set_acl = gfs2_set_acl,
.update_time = gfs2_update_time,
.atomic_open = gfs2_atomic_open,

View file

@ -234,6 +234,27 @@ ssize_t do_getxattr(struct user_namespace *mnt_userns,
int setxattr_copy(const char __user *name, struct xattr_ctx *ctx);
int do_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
struct xattr_ctx *ctx);
int may_write_xattr(struct user_namespace *mnt_userns, struct inode *inode);
#ifdef CONFIG_FS_POSIX_ACL
int do_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
const char *acl_name, const void *kvalue, size_t size);
ssize_t do_get_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
const char *acl_name, void *kvalue, size_t size);
#else
static inline int do_set_acl(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *acl_name,
const void *kvalue, size_t size)
{
return -EOPNOTSUPP;
}
static inline ssize_t do_get_acl(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *acl_name,
void *kvalue, size_t size)
{
return -EOPNOTSUPP;
}
#endif
ssize_t __kernel_write_iter(struct file *file, struct iov_iter *from, loff_t *pos);

View file

@ -229,10 +229,11 @@ static int __jffs2_set_acl(struct inode *inode, int xprefix, struct posix_acl *a
return rc;
}
int jffs2_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
int jffs2_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
int rc, xprefix;
struct inode *inode = d_inode(dentry);
switch (type) {
case ACL_TYPE_ACCESS:

View file

@ -28,7 +28,7 @@ struct jffs2_acl_header {
#ifdef CONFIG_JFFS2_FS_POSIX_ACL
struct posix_acl *jffs2_get_acl(struct inode *inode, int type, bool rcu);
int jffs2_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
int jffs2_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
extern int jffs2_init_acl_pre(struct inode *, struct inode *, umode_t *);
extern int jffs2_init_acl_post(struct inode *);

View file

@ -62,7 +62,7 @@ const struct inode_operations jffs2_dir_inode_operations =
.rmdir = jffs2_rmdir,
.mknod = jffs2_mknod,
.rename = jffs2_rename,
.get_acl = jffs2_get_acl,
.get_inode_acl = jffs2_get_acl,
.set_acl = jffs2_set_acl,
.setattr = jffs2_setattr,
.listxattr = jffs2_listxattr,

View file

@ -64,7 +64,7 @@ const struct file_operations jffs2_file_operations =
const struct inode_operations jffs2_file_inode_operations =
{
.get_acl = jffs2_get_acl,
.get_inode_acl = jffs2_get_acl,
.set_acl = jffs2_set_acl,
.setattr = jffs2_setattr,
.listxattr = jffs2_listxattr,

View file

@ -202,7 +202,7 @@ int jffs2_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
rc = jffs2_do_setattr(inode, iattr);
if (!rc && (iattr->ia_valid & ATTR_MODE))
rc = posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
rc = posix_acl_chmod(&init_user_ns, dentry, inode->i_mode);
return rc;
}

View file

@ -94,12 +94,13 @@ static int __jfs_set_acl(tid_t tid, struct inode *inode, int type,
return rc;
}
int jfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
int jfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
int rc;
tid_t tid;
int update_mode = 0;
struct inode *inode = d_inode(dentry);
umode_t mode = inode->i_mode;
tid = txBegin(inode->i_sb, 0);

View file

@ -123,7 +123,7 @@ int jfs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
mark_inode_dirty(inode);
if (iattr->ia_valid & ATTR_MODE)
rc = posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
rc = posix_acl_chmod(&init_user_ns, dentry, inode->i_mode);
return rc;
}
@ -133,7 +133,7 @@ const struct inode_operations jfs_file_inode_operations = {
.fileattr_get = jfs_fileattr_get,
.fileattr_set = jfs_fileattr_set,
#ifdef CONFIG_JFS_POSIX_ACL
.get_acl = jfs_get_acl,
.get_inode_acl = jfs_get_acl,
.set_acl = jfs_set_acl,
#endif
};

View file

@ -8,7 +8,7 @@
#ifdef CONFIG_JFS_POSIX_ACL
struct posix_acl *jfs_get_acl(struct inode *inode, int type, bool rcu);
int jfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
int jfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
int jfs_init_acl(tid_t, struct inode *, struct inode *);

View file

@ -1525,7 +1525,7 @@ const struct inode_operations jfs_dir_inode_operations = {
.fileattr_get = jfs_fileattr_get,
.fileattr_set = jfs_fileattr_set,
#ifdef CONFIG_JFS_POSIX_ACL
.get_acl = jfs_get_acl,
.get_inode_acl = jfs_get_acl,
.set_acl = jfs_set_acl,
#endif
};

View file

@ -2487,9 +2487,9 @@ static void ksmbd_acls_fattr(struct smb_fattr *fattr,
fattr->cf_dacls = NULL;
if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) {
fattr->cf_acls = get_acl(inode, ACL_TYPE_ACCESS);
fattr->cf_acls = get_inode_acl(inode, ACL_TYPE_ACCESS);
if (S_ISDIR(inode->i_mode))
fattr->cf_dacls = get_acl(inode, ACL_TYPE_DEFAULT);
fattr->cf_dacls = get_inode_acl(inode, ACL_TYPE_DEFAULT);
}
}
@ -2956,7 +2956,7 @@ int smb2_open(struct ksmbd_work *work)
struct inode *inode = d_inode(path.dentry);
posix_acl_rc = ksmbd_vfs_inherit_posix_acl(user_ns,
inode,
path.dentry,
d_inode(path.dentry->d_parent));
if (posix_acl_rc)
ksmbd_debug(SMB, "inherit posix acl failed : %d\n", posix_acl_rc);
@ -2972,7 +2972,7 @@ int smb2_open(struct ksmbd_work *work)
if (rc) {
if (posix_acl_rc)
ksmbd_vfs_set_init_posix_acl(user_ns,
inode);
path.dentry);
if (test_share_config_flag(work->tcon->share_conf,
KSMBD_SHARE_FLAG_ACL_XATTR)) {

View file

@ -1289,7 +1289,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
}
if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) {
posix_acls = get_acl(d_inode(path->dentry), ACL_TYPE_ACCESS);
posix_acls = get_inode_acl(d_inode(path->dentry), ACL_TYPE_ACCESS);
if (posix_acls && !found) {
unsigned int id = -1;
@ -1386,14 +1386,14 @@ int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
ksmbd_vfs_remove_acl_xattrs(user_ns, path->dentry);
/* Update posix acls */
if (IS_ENABLED(CONFIG_FS_POSIX_ACL) && fattr.cf_dacls) {
rc = set_posix_acl(user_ns, inode,
rc = set_posix_acl(user_ns, path->dentry,
ACL_TYPE_ACCESS, fattr.cf_acls);
if (rc < 0)
ksmbd_debug(SMB,
"Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n",
rc);
if (S_ISDIR(inode->i_mode) && fattr.cf_dacls) {
rc = set_posix_acl(user_ns, inode,
rc = set_posix_acl(user_ns, path->dentry,
ACL_TYPE_DEFAULT, fattr.cf_dacls);
if (rc)
ksmbd_debug(SMB,

View file

@ -1321,7 +1321,7 @@ int ksmbd_vfs_remove_acl_xattrs(struct user_namespace *user_ns,
sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1) ||
!strncmp(name, XATTR_NAME_POSIX_ACL_DEFAULT,
sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1)) {
err = ksmbd_vfs_remove_xattr(user_ns, dentry, name);
err = vfs_remove_acl(user_ns, dentry, name);
if (err)
ksmbd_debug(SMB,
"remove acl xattr failed : %s\n", name);
@ -1375,7 +1375,7 @@ static struct xattr_smb_acl *ksmbd_vfs_make_xattr_posix_acl(struct user_namespac
if (!IS_ENABLED(CONFIG_FS_POSIX_ACL))
return NULL;
posix_acls = get_acl(inode, acl_type);
posix_acls = get_inode_acl(inode, acl_type);
if (!posix_acls)
return NULL;
@ -1824,10 +1824,11 @@ void ksmbd_vfs_posix_lock_unblock(struct file_lock *flock)
}
int ksmbd_vfs_set_init_posix_acl(struct user_namespace *user_ns,
struct inode *inode)
struct dentry *dentry)
{
struct posix_acl_state acl_state;
struct posix_acl *acls;
struct inode *inode = d_inode(dentry);
int rc;
if (!IS_ENABLED(CONFIG_FS_POSIX_ACL))
@ -1856,14 +1857,13 @@ int ksmbd_vfs_set_init_posix_acl(struct user_namespace *user_ns,
return -ENOMEM;
}
posix_state_to_acl(&acl_state, acls->a_entries);
rc = set_posix_acl(user_ns, inode, ACL_TYPE_ACCESS, acls);
rc = set_posix_acl(user_ns, dentry, ACL_TYPE_ACCESS, acls);
if (rc < 0)
ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n",
rc);
else if (S_ISDIR(inode->i_mode)) {
posix_state_to_acl(&acl_state, acls->a_entries);
rc = set_posix_acl(user_ns, inode, ACL_TYPE_DEFAULT,
acls);
rc = set_posix_acl(user_ns, dentry, ACL_TYPE_DEFAULT, acls);
if (rc < 0)
ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n",
rc);
@ -1874,16 +1874,17 @@ int ksmbd_vfs_set_init_posix_acl(struct user_namespace *user_ns,
}
int ksmbd_vfs_inherit_posix_acl(struct user_namespace *user_ns,
struct inode *inode, struct inode *parent_inode)
struct dentry *dentry, struct inode *parent_inode)
{
struct posix_acl *acls;
struct posix_acl_entry *pace;
struct inode *inode = d_inode(dentry);
int rc, i;
if (!IS_ENABLED(CONFIG_FS_POSIX_ACL))
return -EOPNOTSUPP;
acls = get_acl(parent_inode, ACL_TYPE_DEFAULT);
acls = get_inode_acl(parent_inode, ACL_TYPE_DEFAULT);
if (!acls)
return -ENOENT;
pace = acls->a_entries;
@ -1895,12 +1896,12 @@ int ksmbd_vfs_inherit_posix_acl(struct user_namespace *user_ns,
}
}
rc = set_posix_acl(user_ns, inode, ACL_TYPE_ACCESS, acls);
rc = set_posix_acl(user_ns, dentry, ACL_TYPE_ACCESS, acls);
if (rc < 0)
ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n",
rc);
if (S_ISDIR(inode->i_mode)) {
rc = set_posix_acl(user_ns, inode, ACL_TYPE_DEFAULT,
rc = set_posix_acl(user_ns, dentry, ACL_TYPE_DEFAULT,
acls);
if (rc < 0)
ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n",

View file

@ -160,8 +160,8 @@ int ksmbd_vfs_get_dos_attrib_xattr(struct user_namespace *user_ns,
struct dentry *dentry,
struct xattr_dos_attrib *da);
int ksmbd_vfs_set_init_posix_acl(struct user_namespace *user_ns,
struct inode *inode);
struct dentry *dentry);
int ksmbd_vfs_inherit_posix_acl(struct user_namespace *user_ns,
struct inode *inode,
struct dentry *dentry,
struct inode *parent_inode);
#endif /* __KSMBD_VFS_H__ */

View file

@ -297,13 +297,13 @@ static int check_acl(struct user_namespace *mnt_userns,
acl = get_cached_acl_rcu(inode, ACL_TYPE_ACCESS);
if (!acl)
return -EAGAIN;
/* no ->get_acl() calls in RCU mode... */
/* no ->get_inode_acl() calls in RCU mode... */
if (is_uncached_acl(acl))
return -ECHILD;
return posix_acl_permission(mnt_userns, inode, acl, mask);
}
acl = get_acl(inode, ACL_TYPE_ACCESS);
acl = get_inode_acl(inode, ACL_TYPE_ACCESS);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (acl) {

View file

@ -12,7 +12,7 @@
*/
#ifdef CONFIG_NFS_V3_ACL
extern struct posix_acl *nfs3_get_acl(struct inode *inode, int type, bool rcu);
extern int nfs3_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
extern int nfs3_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
extern int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
struct posix_acl *dfacl);

View file

@ -255,23 +255,24 @@ int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
}
int nfs3_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
int nfs3_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
struct posix_acl *orig = acl, *dfacl = NULL, *alloc;
struct inode *inode = d_inode(dentry);
int status;
if (S_ISDIR(inode->i_mode)) {
switch(type) {
case ACL_TYPE_ACCESS:
alloc = get_acl(inode, ACL_TYPE_DEFAULT);
alloc = get_inode_acl(inode, ACL_TYPE_DEFAULT);
if (IS_ERR(alloc))
goto fail;
dfacl = alloc;
break;
case ACL_TYPE_DEFAULT:
alloc = get_acl(inode, ACL_TYPE_ACCESS);
alloc = get_inode_acl(inode, ACL_TYPE_ACCESS);
if (IS_ERR(alloc))
goto fail;
dfacl = acl;
@ -312,7 +313,7 @@ nfs3_list_one_acl(struct inode *inode, int type, const char *name, void *data,
struct posix_acl *acl;
char *p = data + *result;
acl = get_acl(inode, type);
acl = get_inode_acl(inode, type);
if (IS_ERR_OR_NULL(acl))
return 0;

View file

@ -998,7 +998,7 @@ static const struct inode_operations nfs3_dir_inode_operations = {
.setattr = nfs_setattr,
#ifdef CONFIG_NFS_V3_ACL
.listxattr = nfs3_listxattr,
.get_acl = nfs3_get_acl,
.get_inode_acl = nfs3_get_acl,
.set_acl = nfs3_set_acl,
#endif
};
@ -1009,7 +1009,7 @@ static const struct inode_operations nfs3_file_inode_operations = {
.setattr = nfs_setattr,
#ifdef CONFIG_NFS_V3_ACL
.listxattr = nfs3_listxattr,
.get_acl = nfs3_get_acl,
.get_inode_acl = nfs3_get_acl,
.set_acl = nfs3_set_acl,
#endif
};

View file

@ -55,7 +55,7 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp)
goto out;
if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
acl = get_acl(inode, ACL_TYPE_ACCESS);
acl = get_inode_acl(inode, ACL_TYPE_ACCESS);
if (acl == NULL) {
/* Solaris returns the inode's minimum ACL. */
acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
@ -69,7 +69,7 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp)
if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
/* Check how Solaris handles requests for the Default ACL
of a non-directory! */
acl = get_acl(inode, ACL_TYPE_DEFAULT);
acl = get_inode_acl(inode, ACL_TYPE_DEFAULT);
if (IS_ERR(acl)) {
resp->status = nfserrno(PTR_ERR(acl));
goto fail;
@ -113,11 +113,11 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
inode_lock(inode);
error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS,
error = set_posix_acl(&init_user_ns, fh->fh_dentry, ACL_TYPE_ACCESS,
argp->acl_access);
if (error)
goto out_drop_lock;
error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_DEFAULT,
error = set_posix_acl(&init_user_ns, fh->fh_dentry, ACL_TYPE_DEFAULT,
argp->acl_default);
if (error)
goto out_drop_lock;

View file

@ -47,7 +47,7 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst *rqstp)
resp->mask = argp->mask;
if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
acl = get_acl(inode, ACL_TYPE_ACCESS);
acl = get_inode_acl(inode, ACL_TYPE_ACCESS);
if (acl == NULL) {
/* Solaris returns the inode's minimum ACL. */
acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
@ -61,7 +61,7 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst *rqstp)
if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
/* Check how Solaris handles requests for the Default ACL
of a non-directory! */
acl = get_acl(inode, ACL_TYPE_DEFAULT);
acl = get_inode_acl(inode, ACL_TYPE_DEFAULT);
if (IS_ERR(acl)) {
resp->status = nfserrno(PTR_ERR(acl));
goto fail;
@ -103,11 +103,11 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp)
inode_lock(inode);
error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS,
error = set_posix_acl(&init_user_ns, fh->fh_dentry, ACL_TYPE_ACCESS,
argp->acl_access);
if (error)
goto out_drop_lock;
error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_DEFAULT,
error = set_posix_acl(&init_user_ns, fh->fh_dentry, ACL_TYPE_DEFAULT,
argp->acl_default);
out_drop_lock:

View file

@ -135,7 +135,7 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
unsigned int flags = 0;
int size = 0;
pacl = get_acl(inode, ACL_TYPE_ACCESS);
pacl = get_inode_acl(inode, ACL_TYPE_ACCESS);
if (!pacl)
pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
@ -147,7 +147,7 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
if (S_ISDIR(inode->i_mode)) {
flags = NFS4_ACL_DIR;
dpacl = get_acl(inode, ACL_TYPE_DEFAULT);
dpacl = get_inode_acl(inode, ACL_TYPE_DEFAULT);
if (IS_ERR(dpacl)) {
error = PTR_ERR(dpacl);
goto rel_pacl;

View file

@ -480,12 +480,12 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
attr->na_seclabel->data, attr->na_seclabel->len);
if (IS_ENABLED(CONFIG_FS_POSIX_ACL) && attr->na_pacl)
attr->na_aclerr = set_posix_acl(&init_user_ns,
inode, ACL_TYPE_ACCESS,
dentry, ACL_TYPE_ACCESS,
attr->na_pacl);
if (IS_ENABLED(CONFIG_FS_POSIX_ACL) &&
!attr->na_aclerr && attr->na_dpacl && S_ISDIR(inode->i_mode))
attr->na_aclerr = set_posix_acl(&init_user_ns,
inode, ACL_TYPE_DEFAULT,
dentry, ACL_TYPE_DEFAULT,
attr->na_dpacl);
inode_unlock(inode);
if (size_change)

View file

@ -802,7 +802,7 @@ int ntfs3_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
setattr_copy(mnt_userns, inode, attr);
if (mode != inode->i_mode) {
err = ntfs_acl_chmod(mnt_userns, inode);
err = ntfs_acl_chmod(mnt_userns, dentry);
if (err)
goto out;
@ -1255,7 +1255,7 @@ const struct inode_operations ntfs_file_inode_operations = {
.setattr = ntfs3_setattr,
.listxattr = ntfs_listxattr,
.permission = ntfs_permission,
.get_acl = ntfs_get_acl,
.get_inode_acl = ntfs_get_acl,
.set_acl = ntfs_set_acl,
.fiemap = ntfs_fiemap,
};

View file

@ -367,7 +367,7 @@ const struct inode_operations ntfs_dir_inode_operations = {
.mknod = ntfs_mknod,
.rename = ntfs_rename,
.permission = ntfs_permission,
.get_acl = ntfs_get_acl,
.get_inode_acl = ntfs_get_acl,
.set_acl = ntfs_set_acl,
.setattr = ntfs3_setattr,
.getattr = ntfs_getattr,
@ -379,7 +379,7 @@ const struct inode_operations ntfs_special_inode_operations = {
.setattr = ntfs3_setattr,
.getattr = ntfs_getattr,
.listxattr = ntfs_listxattr,
.get_acl = ntfs_get_acl,
.get_inode_acl = ntfs_get_acl,
.set_acl = ntfs_set_acl,
};
// clang-format on

View file

@ -843,7 +843,7 @@ int ntfs_cmp_names_cpu(const struct cpu_str *uni1, const struct le_str *uni2,
/* globals from xattr.c */
#ifdef CONFIG_NTFS3_FS_POSIX_ACL
struct posix_acl *ntfs_get_acl(struct inode *inode, int type, bool rcu);
int ntfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
int ntfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
int ntfs_init_acl(struct user_namespace *mnt_userns, struct inode *inode,
struct inode *dir);
@ -852,7 +852,7 @@ int ntfs_init_acl(struct user_namespace *mnt_userns, struct inode *inode,
#define ntfs_set_acl NULL
#endif
int ntfs_acl_chmod(struct user_namespace *mnt_userns, struct inode *inode);
int ntfs_acl_chmod(struct user_namespace *mnt_userns, struct dentry *dentry);
int ntfs_permission(struct user_namespace *mnt_userns, struct inode *inode,
int mask);
ssize_t ntfs_listxattr(struct dentry *dentry, char *buffer, size_t size);

View file

@ -619,10 +619,10 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
/*
* ntfs_set_acl - inode_operations::set_acl
*/
int ntfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
int ntfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
return ntfs_set_acl_ex(mnt_userns, inode, acl, type, false);
return ntfs_set_acl_ex(mnt_userns, d_inode(dentry), acl, type, false);
}
/*
@ -664,8 +664,9 @@ int ntfs_init_acl(struct user_namespace *mnt_userns, struct inode *inode,
/*
* ntfs_acl_chmod - Helper for ntfs3_setattr().
*/
int ntfs_acl_chmod(struct user_namespace *mnt_userns, struct inode *inode)
int ntfs_acl_chmod(struct user_namespace *mnt_userns, struct dentry *dentry)
{
struct inode *inode = d_inode(dentry);
struct super_block *sb = inode->i_sb;
if (!(sb->s_flags & SB_POSIXACL))
@ -674,7 +675,7 @@ int ntfs_acl_chmod(struct user_namespace *mnt_userns, struct inode *inode)
if (S_ISLNK(inode->i_mode))
return -EOPNOTSUPP;
return posix_acl_chmod(mnt_userns, inode, inode->i_mode);
return posix_acl_chmod(mnt_userns, dentry, inode->i_mode);
}
/*

View file

@ -260,12 +260,13 @@ static int ocfs2_set_acl(handle_t *handle,
return ret;
}
int ocfs2_iop_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
int ocfs2_iop_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
struct buffer_head *bh = NULL;
int status, had_lock;
struct ocfs2_lock_holder oh;
struct inode *inode = d_inode(dentry);
had_lock = ocfs2_inode_lock_tracker(inode, &bh, 1, &oh);
if (had_lock < 0)

View file

@ -17,7 +17,7 @@ struct ocfs2_acl_entry {
};
struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type, bool rcu);
int ocfs2_iop_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
int ocfs2_iop_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
extern int ocfs2_acl_chmod(struct inode *, struct buffer_head *);
extern int ocfs2_init_acl(handle_t *, struct inode *, struct inode *,

View file

@ -2712,7 +2712,7 @@ const struct inode_operations ocfs2_file_iops = {
.permission = ocfs2_permission,
.listxattr = ocfs2_listxattr,
.fiemap = ocfs2_fiemap,
.get_acl = ocfs2_iop_get_acl,
.get_inode_acl = ocfs2_iop_get_acl,
.set_acl = ocfs2_iop_set_acl,
.fileattr_get = ocfs2_fileattr_get,
.fileattr_set = ocfs2_fileattr_set,
@ -2722,7 +2722,7 @@ const struct inode_operations ocfs2_special_file_iops = {
.setattr = ocfs2_setattr,
.getattr = ocfs2_getattr,
.permission = ocfs2_permission,
.get_acl = ocfs2_iop_get_acl,
.get_inode_acl = ocfs2_iop_get_acl,
.set_acl = ocfs2_iop_set_acl,
};

View file

@ -2916,7 +2916,7 @@ const struct inode_operations ocfs2_dir_iops = {
.permission = ocfs2_permission,
.listxattr = ocfs2_listxattr,
.fiemap = ocfs2_fiemap,
.get_acl = ocfs2_iop_get_acl,
.get_inode_acl = ocfs2_iop_get_acl,
.set_acl = ocfs2_iop_set_acl,
.fileattr_get = ocfs2_fileattr_get,
.fileattr_set = ocfs2_fileattr_set,

View file

@ -64,8 +64,7 @@ struct posix_acl *orangefs_get_acl(struct inode *inode, int type, bool rcu)
return acl;
}
static int __orangefs_set_acl(struct inode *inode, struct posix_acl *acl,
int type)
int __orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
{
int error = 0;
void *value = NULL;
@ -119,12 +118,13 @@ static int __orangefs_set_acl(struct inode *inode, struct posix_acl *acl,
return error;
}
int orangefs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
int orangefs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
int error;
struct iattr iattr;
int rc;
struct inode *inode = d_inode(dentry);
memset(&iattr, 0, sizeof iattr);
@ -153,46 +153,7 @@ int orangefs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
rc = __orangefs_set_acl(inode, acl, type);
if (!rc && (iattr.ia_valid == ATTR_MODE))
rc = __orangefs_setattr(inode, &iattr);
rc = __orangefs_setattr_mode(dentry, &iattr);
return rc;
}
int orangefs_init_acl(struct inode *inode, struct inode *dir)
{
struct posix_acl *default_acl, *acl;
umode_t mode = inode->i_mode;
struct iattr iattr;
int error = 0;
error = posix_acl_create(dir, &mode, &default_acl, &acl);
if (error)
return error;
if (default_acl) {
error = __orangefs_set_acl(inode, default_acl,
ACL_TYPE_DEFAULT);
posix_acl_release(default_acl);
} else {
inode->i_default_acl = NULL;
}
if (acl) {
if (!error)
error = __orangefs_set_acl(inode, acl, ACL_TYPE_ACCESS);
posix_acl_release(acl);
} else {
inode->i_acl = NULL;
}
/* If mode of the inode was changed, then do a forcible ->setattr */
if (mode != inode->i_mode) {
memset(&iattr, 0, sizeof iattr);
inode->i_mode = mode;
iattr.ia_mode = mode;
iattr.ia_valid |= ATTR_MODE;
__orangefs_setattr(inode, &iattr);
}
return error;
}

View file

@ -828,15 +828,23 @@ int __orangefs_setattr(struct inode *inode, struct iattr *iattr)
spin_unlock(&inode->i_lock);
mark_inode_dirty(inode);
if (iattr->ia_valid & ATTR_MODE)
/* change mod on a file that has ACLs */
ret = posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
ret = 0;
out:
return ret;
}
int __orangefs_setattr_mode(struct dentry *dentry, struct iattr *iattr)
{
int ret;
struct inode *inode = d_inode(dentry);
ret = __orangefs_setattr(inode, iattr);
/* change mode on a file that has ACLs */
if (!ret && (iattr->ia_valid & ATTR_MODE))
ret = posix_acl_chmod(&init_user_ns, dentry, inode->i_mode);
return ret;
}
/*
* Change attributes of an object referenced by dentry.
*/
@ -849,7 +857,7 @@ int orangefs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
ret = setattr_prepare(&init_user_ns, dentry, iattr);
if (ret)
goto out;
ret = __orangefs_setattr(d_inode(dentry), iattr);
ret = __orangefs_setattr_mode(dentry, iattr);
sync_inode_metadata(d_inode(dentry), 1);
out:
gossip_debug(GOSSIP_INODE_DEBUG, "orangefs_setattr: returning %d\n",
@ -967,7 +975,7 @@ static int orangefs_fileattr_set(struct user_namespace *mnt_userns,
/* ORANGEFS2 implementation of VFS inode operations for files */
static const struct inode_operations orangefs_file_inode_operations = {
.get_acl = orangefs_get_acl,
.get_inode_acl = orangefs_get_acl,
.set_acl = orangefs_set_acl,
.setattr = orangefs_setattr,
.getattr = orangefs_getattr,
@ -1097,8 +1105,9 @@ struct inode *orangefs_iget(struct super_block *sb,
* Allocate an inode for a newly created file and insert it into the inode hash.
*/
struct inode *orangefs_new_inode(struct super_block *sb, struct inode *dir,
int mode, dev_t dev, struct orangefs_object_kref *ref)
umode_t mode, dev_t dev, struct orangefs_object_kref *ref)
{
struct posix_acl *acl = NULL, *default_acl = NULL;
unsigned long hash = orangefs_handle_hash(ref);
struct inode *inode;
int error;
@ -1115,16 +1124,33 @@ struct inode *orangefs_new_inode(struct super_block *sb, struct inode *dir,
if (!inode)
return ERR_PTR(-ENOMEM);
error = posix_acl_create(dir, &mode, &default_acl, &acl);
if (error)
goto out_iput;
orangefs_set_inode(inode, ref);
inode->i_ino = hash; /* needed for stat etc */
error = orangefs_inode_getattr(inode, ORANGEFS_GETATTR_NEW);
error = __orangefs_inode_getattr(inode, mode, ORANGEFS_GETATTR_NEW);
if (error)
goto out_iput;
orangefs_init_iops(inode);
inode->i_rdev = dev;
if (default_acl) {
error = __orangefs_set_acl(inode, default_acl,
ACL_TYPE_DEFAULT);
if (error)
goto out_iput;
}
if (acl) {
error = __orangefs_set_acl(inode, acl, ACL_TYPE_ACCESS);
if (error)
goto out_iput;
}
error = insert_inode_locked4(inode, hash, orangefs_test_inode, ref);
if (error < 0)
goto out_iput;
@ -1132,10 +1158,13 @@ struct inode *orangefs_new_inode(struct super_block *sb, struct inode *dir,
gossip_debug(GOSSIP_INODE_DEBUG,
"Initializing ACL's for inode %pU\n",
get_khandle_from_ino(inode));
orangefs_init_acl(inode, dir);
posix_acl_release(acl);
posix_acl_release(default_acl);
return inode;
out_iput:
iput(inode);
posix_acl_release(acl);
posix_acl_release(default_acl);
return ERR_PTR(error);
}

View file

@ -430,7 +430,7 @@ static int orangefs_rename(struct user_namespace *mnt_userns,
/* ORANGEFS implementation of VFS inode operations for directories */
const struct inode_operations orangefs_dir_inode_operations = {
.lookup = orangefs_lookup,
.get_acl = orangefs_get_acl,
.get_inode_acl = orangefs_get_acl,
.set_acl = orangefs_set_acl,
.create = orangefs_create,
.unlink = orangefs_unlink,

View file

@ -103,13 +103,13 @@ enum orangefs_vfs_op_states {
#define ORANGEFS_CACHE_CREATE_FLAGS 0
#endif
extern int orangefs_init_acl(struct inode *inode, struct inode *dir);
extern const struct xattr_handler *orangefs_xattr_handlers[];
extern struct posix_acl *orangefs_get_acl(struct inode *inode, int type, bool rcu);
extern int orangefs_set_acl(struct user_namespace *mnt_userns,
struct inode *inode, struct posix_acl *acl,
struct dentry *dentry, struct posix_acl *acl,
int type);
int __orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
/*
* orangefs data structures
@ -356,11 +356,12 @@ void fsid_key_table_finalize(void);
vm_fault_t orangefs_page_mkwrite(struct vm_fault *);
struct inode *orangefs_new_inode(struct super_block *sb,
struct inode *dir,
int mode,
umode_t mode,
dev_t dev,
struct orangefs_object_kref *ref);
int __orangefs_setattr(struct inode *, struct iattr *);
int __orangefs_setattr_mode(struct dentry *dentry, struct iattr *iattr);
int orangefs_setattr(struct user_namespace *, struct dentry *, struct iattr *);
int orangefs_getattr(struct user_namespace *mnt_userns, const struct path *path,
@ -422,6 +423,7 @@ int orangefs_inode_setxattr(struct inode *inode,
#define ORANGEFS_GETATTR_SIZE 2
int orangefs_inode_getattr(struct inode *, int);
int __orangefs_inode_getattr(struct inode *inode, umode_t mode, int flags);
int orangefs_inode_check_changed(struct inode *inode);

View file

@ -233,7 +233,7 @@ static int orangefs_inode_is_stale(struct inode *inode,
return 0;
}
int orangefs_inode_getattr(struct inode *inode, int flags)
int __orangefs_inode_getattr(struct inode *inode, umode_t mode, int flags)
{
struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
struct orangefs_kernel_op_s *new_op;
@ -369,7 +369,8 @@ int orangefs_inode_getattr(struct inode *inode, int flags)
/* special case: mark the root inode as sticky */
inode->i_mode = type | (is_root_handle(inode) ? S_ISVTX : 0) |
orangefs_inode_perms(&new_op->downcall.resp.getattr.attributes);
orangefs_inode_perms(&new_op->downcall.resp.getattr.attributes) |
mode;
orangefs_inode->getattr_time = jiffies +
orangefs_getattr_timeout_msecs*HZ/1000;
@ -381,6 +382,11 @@ int orangefs_inode_getattr(struct inode *inode, int flags)
return ret;
}
int orangefs_inode_getattr(struct inode *inode, int flags)
{
return __orangefs_inode_getattr(inode, 0, flags);
}
int orangefs_inode_check_changed(struct inode *inode)
{
struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);

View file

@ -44,6 +44,35 @@ static bool ovl_must_copy_xattr(const char *name)
!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN);
}
static int ovl_copy_acl(struct ovl_fs *ofs, const struct path *path,
struct dentry *dentry, const char *acl_name)
{
int err;
struct posix_acl *clone, *real_acl = NULL;
real_acl = ovl_get_acl_path(path, acl_name, false);
if (!real_acl)
return 0;
if (IS_ERR(real_acl)) {
err = PTR_ERR(real_acl);
if (err == -ENODATA || err == -EOPNOTSUPP)
return 0;
return err;
}
clone = posix_acl_clone(real_acl, GFP_KERNEL);
posix_acl_release(real_acl); /* release original acl */
if (!clone)
return -ENOMEM;
err = ovl_do_set_acl(ofs, dentry, acl_name, clone);
/* release cloned acl */
posix_acl_release(clone);
return err;
}
int ovl_copy_xattr(struct super_block *sb, const struct path *oldpath, struct dentry *new)
{
struct dentry *old = oldpath->dentry;
@ -93,6 +122,15 @@ int ovl_copy_xattr(struct super_block *sb, const struct path *oldpath, struct de
error = 0;
continue; /* Discard */
}
if (is_posix_acl_xattr(name)) {
error = ovl_copy_acl(OVL_FS(sb), oldpath, new, name);
if (!error)
continue;
/* POSIX ACLs must be copied. */
break;
}
retry:
size = ovl_do_getxattr(oldpath, name, value, value_size);
if (size == -ERANGE)

View file

@ -435,28 +435,12 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
}
static int ovl_set_upper_acl(struct ovl_fs *ofs, struct dentry *upperdentry,
const char *name, const struct posix_acl *acl)
const char *acl_name, struct posix_acl *acl)
{
void *buffer;
size_t size;
int err;
if (!IS_ENABLED(CONFIG_FS_POSIX_ACL) || !acl)
return 0;
size = posix_acl_xattr_size(acl->a_count);
buffer = kmalloc(size, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
err = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
if (err < 0)
goto out_free;
err = ovl_do_setxattr(ofs, upperdentry, name, buffer, size, XATTR_CREATE);
out_free:
kfree(buffer);
return err;
return ovl_do_set_acl(ofs, upperdentry, acl_name, acl);
}
static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
@ -1311,7 +1295,9 @@ const struct inode_operations ovl_dir_inode_operations = {
.permission = ovl_permission,
.getattr = ovl_getattr,
.listxattr = ovl_listxattr,
.get_inode_acl = ovl_get_inode_acl,
.get_acl = ovl_get_acl,
.set_acl = ovl_set_acl,
.update_time = ovl_update_time,
.fileattr_get = ovl_fileattr_get,
.fileattr_set = ovl_fileattr_set,

View file

@ -14,6 +14,8 @@
#include <linux/fileattr.h>
#include <linux/security.h>
#include <linux/namei.h>
#include <linux/posix_acl.h>
#include <linux/posix_acl_xattr.h>
#include "overlayfs.h"
@ -460,7 +462,7 @@ ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
* of the POSIX ACLs retrieved from the lower layer to this function to not
* alter the POSIX ACLs for the underlying filesystem.
*/
static void ovl_idmap_posix_acl(struct inode *realinode,
static void ovl_idmap_posix_acl(const struct inode *realinode,
struct user_namespace *mnt_userns,
struct posix_acl *acl)
{
@ -484,6 +486,64 @@ static void ovl_idmap_posix_acl(struct inode *realinode,
}
}
/*
* The @noperm argument is used to skip permission checking and is a temporary
* measure. Quoting Miklos from an earlier discussion:
*
* > So there are two paths to getting an acl:
* > 1) permission checking and 2) retrieving the value via getxattr(2).
* > This is a similar situation as reading a symlink vs. following it.
* > When following a symlink overlayfs always reads the link on the
* > underlying fs just as if it was a readlink(2) call, calling
* > security_inode_readlink() instead of security_inode_follow_link().
* > This is logical: we are reading the link from the underlying storage,
* > and following it on overlayfs.
* >
* > Applying the same logic to acl: we do need to call the
* > security_inode_getxattr() on the underlying fs, even if just want to
* > check permissions on overlay. This is currently not done, which is an
* > inconsistency.
* >
* > Maybe adding the check to ovl_get_acl() is the right way to go, but
* > I'm a little afraid of a performance regression. Will look into that.
*
* Until we have made a decision allow this helper to take the @noperm
* argument. We should hopefully be able to remove it soon.
*/
struct posix_acl *ovl_get_acl_path(const struct path *path,
const char *acl_name, bool noperm)
{
struct posix_acl *real_acl, *clone;
struct user_namespace *mnt_userns;
struct inode *realinode = d_inode(path->dentry);
mnt_userns = mnt_user_ns(path->mnt);
if (noperm)
real_acl = get_inode_acl(realinode, posix_acl_type(acl_name));
else
real_acl = vfs_get_acl(mnt_userns, path->dentry, acl_name);
if (IS_ERR_OR_NULL(real_acl))
return real_acl;
if (!is_idmapped_mnt(path->mnt))
return real_acl;
/*
* We cannot alter the ACLs returned from the relevant layer as that
* would alter the cached values filesystem wide for the lower
* filesystem. Instead we can clone the ACLs and then apply the
* relevant idmapping of the layer.
*/
clone = posix_acl_clone(real_acl, GFP_KERNEL);
posix_acl_release(real_acl); /* release original acl */
if (!clone)
return ERR_PTR(-ENOMEM);
ovl_idmap_posix_acl(realinode, mnt_userns, clone);
return clone;
}
/*
* When the relevant layer is an idmapped mount we need to take the idmapping
* of the layer into account and translate any ACL_{GROUP,USER} values
@ -495,10 +555,12 @@ static void ovl_idmap_posix_acl(struct inode *realinode,
*
* This is obviously only relevant when idmapped layers are used.
*/
struct posix_acl *ovl_get_acl(struct inode *inode, int type, bool rcu)
struct posix_acl *do_ovl_get_acl(struct user_namespace *mnt_userns,
struct inode *inode, int type,
bool rcu, bool noperm)
{
struct inode *realinode = ovl_inode_real(inode);
struct posix_acl *acl, *clone;
struct posix_acl *acl;
struct path realpath;
if (!IS_POSIXACL(realinode))
@ -512,40 +574,115 @@ struct posix_acl *ovl_get_acl(struct inode *inode, int type, bool rcu)
}
if (rcu) {
/*
* If the layer is idmapped drop out of RCU path walk
* so we can clone the ACLs.
*/
if (is_idmapped_mnt(realpath.mnt))
return ERR_PTR(-ECHILD);
acl = get_cached_acl_rcu(realinode, type);
} else {
const struct cred *old_cred;
old_cred = ovl_override_creds(inode->i_sb);
acl = get_acl(realinode, type);
acl = ovl_get_acl_path(&realpath, posix_acl_xattr_name(type), noperm);
revert_creds(old_cred);
}
/*
* If there are no POSIX ACLs, or we encountered an error,
* or the layer isn't idmapped we don't need to do anything.
*/
if (!is_idmapped_mnt(realpath.mnt) || IS_ERR_OR_NULL(acl))
return acl;
return acl;
}
static int ovl_set_or_remove_acl(struct dentry *dentry, struct inode *inode,
struct posix_acl *acl, int type)
{
int err;
struct path realpath;
const char *acl_name;
const struct cred *old_cred;
struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
struct dentry *upperdentry = ovl_dentry_upper(dentry);
struct dentry *realdentry = upperdentry ?: ovl_dentry_lower(dentry);
err = ovl_want_write(dentry);
if (err)
return err;
/*
* We only get here if the layer is idmapped. So drop out of RCU path
* walk so we can clone the ACLs. There's no need to release the ACLs
* since get_cached_acl_rcu() doesn't take a reference on the ACLs.
* If ACL is to be removed from a lower file, check if it exists in
* the first place before copying it up.
*/
if (rcu)
return ERR_PTR(-ECHILD);
acl_name = posix_acl_xattr_name(type);
if (!acl && !upperdentry) {
struct posix_acl *real_acl;
clone = posix_acl_clone(acl, GFP_KERNEL);
if (!clone)
clone = ERR_PTR(-ENOMEM);
ovl_path_lower(dentry, &realpath);
old_cred = ovl_override_creds(dentry->d_sb);
real_acl = vfs_get_acl(mnt_user_ns(realpath.mnt), realdentry,
acl_name);
revert_creds(old_cred);
posix_acl_release(real_acl);
if (IS_ERR(real_acl)) {
err = PTR_ERR(real_acl);
goto out_drop_write;
}
}
if (!upperdentry) {
err = ovl_copy_up(dentry);
if (err)
goto out_drop_write;
realdentry = ovl_dentry_upper(dentry);
}
old_cred = ovl_override_creds(dentry->d_sb);
if (acl)
err = ovl_do_set_acl(ofs, realdentry, acl_name, acl);
else
ovl_idmap_posix_acl(realinode, mnt_user_ns(realpath.mnt), clone);
err = ovl_do_remove_acl(ofs, realdentry, acl_name);
revert_creds(old_cred);
/* copy c/mtime */
ovl_copyattr(inode);
out_drop_write:
ovl_drop_write(dentry);
return err;
}
int ovl_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
int err;
struct inode *inode = d_inode(dentry);
struct dentry *workdir = ovl_workdir(dentry);
struct inode *realinode = ovl_inode_real(inode);
if (!IS_POSIXACL(d_inode(workdir)))
return -EOPNOTSUPP;
if (!realinode->i_op->set_acl)
return -EOPNOTSUPP;
if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
return acl ? -EACCES : 0;
if (!inode_owner_or_capable(&init_user_ns, inode))
return -EPERM;
/*
* Since we're not in RCU path walk we always need to release the
* original ACLs.
* Check if sgid bit needs to be cleared (actual setacl operation will
* be done with mounter's capabilities and so that won't do it for us).
*/
posix_acl_release(acl);
return clone;
if (unlikely(inode->i_mode & S_ISGID) && type == ACL_TYPE_ACCESS &&
!in_group_p(inode->i_gid) &&
!capable_wrt_inode_uidgid(&init_user_ns, inode, CAP_FSETID)) {
struct iattr iattr = { .ia_valid = ATTR_KILL_SGID };
err = ovl_setattr(&init_user_ns, dentry, &iattr);
if (err)
return err;
}
return ovl_set_or_remove_acl(dentry, inode, acl, type);
}
#endif
@ -721,7 +858,9 @@ static const struct inode_operations ovl_file_inode_operations = {
.permission = ovl_permission,
.getattr = ovl_getattr,
.listxattr = ovl_listxattr,
.get_inode_acl = ovl_get_inode_acl,
.get_acl = ovl_get_acl,
.set_acl = ovl_set_acl,
.update_time = ovl_update_time,
.fiemap = ovl_fiemap,
.fileattr_get = ovl_fileattr_get,
@ -741,7 +880,9 @@ static const struct inode_operations ovl_special_inode_operations = {
.permission = ovl_permission,
.getattr = ovl_getattr,
.listxattr = ovl_listxattr,
.get_inode_acl = ovl_get_inode_acl,
.get_acl = ovl_get_acl,
.set_acl = ovl_set_acl,
.update_time = ovl_update_time,
};

View file

@ -8,6 +8,8 @@
#include <linux/uuid.h>
#include <linux/fs.h>
#include <linux/namei.h>
#include <linux/posix_acl.h>
#include <linux/posix_acl_xattr.h>
#include "ovl_entry.h"
#undef pr_fmt
@ -278,6 +280,18 @@ static inline int ovl_removexattr(struct ovl_fs *ofs, struct dentry *dentry,
return ovl_do_removexattr(ofs, dentry, ovl_xattr(ofs, ox));
}
static inline int ovl_do_set_acl(struct ovl_fs *ofs, struct dentry *dentry,
const char *acl_name, struct posix_acl *acl)
{
return vfs_set_acl(ovl_upper_mnt_userns(ofs), dentry, acl_name, acl);
}
static inline int ovl_do_remove_acl(struct ovl_fs *ofs, struct dentry *dentry,
const char *acl_name)
{
return vfs_remove_acl(ovl_upper_mnt_userns(ofs), dentry, acl_name);
}
static inline int ovl_do_rename(struct ovl_fs *ofs, struct inode *olddir,
struct dentry *olddentry, struct inode *newdir,
struct dentry *newdentry, unsigned int flags)
@ -594,9 +608,33 @@ int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name,
ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
#ifdef CONFIG_FS_POSIX_ACL
struct posix_acl *ovl_get_acl(struct inode *inode, int type, bool rcu);
struct posix_acl *do_ovl_get_acl(struct user_namespace *mnt_userns,
struct inode *inode, int type,
bool rcu, bool noperm);
static inline struct posix_acl *ovl_get_inode_acl(struct inode *inode, int type,
bool rcu)
{
return do_ovl_get_acl(&init_user_ns, inode, type, rcu, true);
}
static inline struct posix_acl *ovl_get_acl(struct user_namespace *mnt_userns,
struct dentry *dentry, int type)
{
return do_ovl_get_acl(mnt_userns, d_inode(dentry), type, false, false);
}
int ovl_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
struct posix_acl *ovl_get_acl_path(const struct path *path,
const char *acl_name, bool noperm);
#else
#define ovl_get_acl NULL
#define ovl_get_inode_acl NULL
#define ovl_get_acl NULL
#define ovl_set_acl NULL
static inline struct posix_acl *ovl_get_acl_path(const struct path *path,
const char *acl_name,
bool noperm)
{
return NULL;
}
#endif
int ovl_update_time(struct inode *inode, struct timespec64 *ts, int flags);

View file

@ -813,13 +813,11 @@ static struct dentry *ovl_workdir_create(struct ovl_fs *ofs,
* allowed as upper are limited to "normal" ones, where checking
* for the above two errors is sufficient.
*/
err = ovl_do_removexattr(ofs, work,
XATTR_NAME_POSIX_ACL_DEFAULT);
err = ovl_do_remove_acl(ofs, work, XATTR_NAME_POSIX_ACL_DEFAULT);
if (err && err != -ENODATA && err != -EOPNOTSUPP)
goto out_dput;
err = ovl_do_removexattr(ofs, work,
XATTR_NAME_POSIX_ACL_ACCESS);
err = ovl_do_remove_acl(ofs, work, XATTR_NAME_POSIX_ACL_ACCESS);
if (err && err != -ENODATA && err != -EOPNOTSUPP)
goto out_dput;
@ -1001,83 +999,6 @@ static unsigned int ovl_split_lowerdirs(char *str)
return ctr;
}
static int __maybe_unused
ovl_posix_acl_xattr_get(const struct xattr_handler *handler,
struct dentry *dentry, struct inode *inode,
const char *name, void *buffer, size_t size)
{
return ovl_xattr_get(dentry, inode, handler->name, buffer, size);
}
static int __maybe_unused
ovl_posix_acl_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)
{
struct dentry *workdir = ovl_workdir(dentry);
struct inode *realinode = ovl_inode_real(inode);
struct posix_acl *acl = NULL;
int err;
/* Check that everything is OK before copy-up */
if (value) {
/* The above comment can be understood in two ways:
*
* 1. We just want to check whether the basic POSIX ACL format
* is ok. For example, if the header is correct and the size
* is sane.
* 2. We want to know whether the ACL_{GROUP,USER} entries can
* be mapped according to the underlying filesystem.
*
* Currently, we only check 1. If we wanted to check 2. we
* would need to pass the mnt_userns and the fs_userns of the
* underlying filesystem. But frankly, I think checking 1. is
* enough to start the copy-up.
*/
acl = vfs_set_acl_prepare(&init_user_ns, &init_user_ns, value, size);
if (IS_ERR(acl))
return PTR_ERR(acl);
}
err = -EOPNOTSUPP;
if (!IS_POSIXACL(d_inode(workdir)))
goto out_acl_release;
if (!realinode->i_op->set_acl)
goto out_acl_release;
if (handler->flags == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) {
err = acl ? -EACCES : 0;
goto out_acl_release;
}
err = -EPERM;
if (!inode_owner_or_capable(&init_user_ns, inode))
goto out_acl_release;
posix_acl_release(acl);
/*
* Check if sgid bit needs to be cleared (actual setacl operation will
* be done with mounter's capabilities and so that won't do it for us).
*/
if (unlikely(inode->i_mode & S_ISGID) &&
handler->flags == ACL_TYPE_ACCESS &&
!in_group_p(inode->i_gid) &&
!capable_wrt_inode_uidgid(&init_user_ns, inode, CAP_FSETID)) {
struct iattr iattr = { .ia_valid = ATTR_KILL_SGID };
err = ovl_setattr(&init_user_ns, dentry, &iattr);
if (err)
return err;
}
err = ovl_xattr_set(dentry, inode, handler->name, value, size, flags);
return err;
out_acl_release:
posix_acl_release(acl);
return err;
}
static int ovl_own_xattr_get(const struct xattr_handler *handler,
struct dentry *dentry, struct inode *inode,
const char *name, void *buffer, size_t size)
@ -1110,22 +1031,6 @@ static int ovl_other_xattr_set(const struct xattr_handler *handler,
return ovl_xattr_set(dentry, inode, name, value, size, flags);
}
static const struct xattr_handler __maybe_unused
ovl_posix_acl_access_xattr_handler = {
.name = XATTR_NAME_POSIX_ACL_ACCESS,
.flags = ACL_TYPE_ACCESS,
.get = ovl_posix_acl_xattr_get,
.set = ovl_posix_acl_xattr_set,
};
static const struct xattr_handler __maybe_unused
ovl_posix_acl_default_xattr_handler = {
.name = XATTR_NAME_POSIX_ACL_DEFAULT,
.flags = ACL_TYPE_DEFAULT,
.get = ovl_posix_acl_xattr_get,
.set = ovl_posix_acl_xattr_set,
};
static const struct xattr_handler ovl_own_trusted_xattr_handler = {
.prefix = OVL_XATTR_TRUSTED_PREFIX,
.get = ovl_own_xattr_get,
@ -1146,8 +1051,8 @@ static const struct xattr_handler ovl_other_xattr_handler = {
static const struct xattr_handler *ovl_trusted_xattr_handlers[] = {
#ifdef CONFIG_FS_POSIX_ACL
&ovl_posix_acl_access_xattr_handler,
&ovl_posix_acl_default_xattr_handler,
&posix_acl_access_xattr_handler,
&posix_acl_default_xattr_handler,
#endif
&ovl_own_trusted_xattr_handler,
&ovl_other_xattr_handler,
@ -1156,8 +1061,8 @@ static const struct xattr_handler *ovl_trusted_xattr_handlers[] = {
static const struct xattr_handler *ovl_user_xattr_handlers[] = {
#ifdef CONFIG_FS_POSIX_ACL
&ovl_posix_acl_access_xattr_handler,
&ovl_posix_acl_default_xattr_handler,
&posix_acl_access_xattr_handler,
&posix_acl_default_xattr_handler,
#endif
&ovl_own_user_xattr_handler,
&ovl_other_xattr_handler,

View file

@ -25,6 +25,11 @@
#include <linux/namei.h>
#include <linux/mnt_idmapping.h>
#include <linux/iversion.h>
#include <linux/security.h>
#include <linux/evm.h>
#include <linux/fsnotify.h>
#include "internal.h"
static struct posix_acl **acl_by_type(struct inode *inode, int type)
{
@ -64,7 +69,7 @@ struct posix_acl *get_cached_acl_rcu(struct inode *inode, int type)
if (acl == ACL_DONT_CACHE) {
struct posix_acl *ret;
ret = inode->i_op->get_acl(inode, type, LOOKUP_RCU);
ret = inode->i_op->get_inode_acl(inode, type, LOOKUP_RCU);
if (!IS_ERR(ret))
acl = ret;
}
@ -106,7 +111,9 @@ void forget_all_cached_acls(struct inode *inode)
}
EXPORT_SYMBOL(forget_all_cached_acls);
struct posix_acl *get_acl(struct inode *inode, int type)
static struct posix_acl *__get_acl(struct user_namespace *mnt_userns,
struct dentry *dentry, struct inode *inode,
int type)
{
void *sentinel;
struct posix_acl **p;
@ -114,7 +121,7 @@ struct posix_acl *get_acl(struct inode *inode, int type)
/*
* The sentinel is used to detect when another operation like
* set_cached_acl() or forget_cached_acl() races with get_acl().
* set_cached_acl() or forget_cached_acl() races with get_inode_acl().
* It is guaranteed that is_uncached_acl(sentinel) is true.
*/
@ -133,25 +140,27 @@ struct posix_acl *get_acl(struct inode *inode, int type)
* current value of the ACL will not be ACL_NOT_CACHED and so our own
* sentinel will not be set; another task will update the cache. We
* could wait for that other task to complete its job, but it's easier
* to just call ->get_acl to fetch the ACL ourself. (This is going to
* be an unlikely race.)
* to just call ->get_inode_acl to fetch the ACL ourself. (This is
* going to be an unlikely race.)
*/
cmpxchg(p, ACL_NOT_CACHED, sentinel);
/*
* Normally, the ACL returned by ->get_acl will be cached.
* Normally, the ACL returned by ->get{_inode}_acl will be cached.
* A filesystem can prevent that by calling
* forget_cached_acl(inode, type) in ->get_acl.
* forget_cached_acl(inode, type) in ->get{_inode}_acl.
*
* If the filesystem doesn't have a get_acl() function at all, we'll
* just create the negative cache entry.
* If the filesystem doesn't have a get{_inode}_ acl() function at all,
* we'll just create the negative cache entry.
*/
if (!inode->i_op->get_acl) {
if (dentry && inode->i_op->get_acl) {
acl = inode->i_op->get_acl(mnt_userns, dentry, type);
} else if (inode->i_op->get_inode_acl) {
acl = inode->i_op->get_inode_acl(inode, type, false);
} else {
set_cached_acl(inode, type, NULL);
return NULL;
}
acl = inode->i_op->get_acl(inode, type, false);
if (IS_ERR(acl)) {
/*
* Remove our sentinel so that we don't block future attempts
@ -169,7 +178,12 @@ struct posix_acl *get_acl(struct inode *inode, int type)
posix_acl_release(acl);
return acl;
}
EXPORT_SYMBOL(get_acl);
struct posix_acl *get_inode_acl(struct inode *inode, int type)
{
return __get_acl(&init_user_ns, NULL, inode, type);
}
EXPORT_SYMBOL(get_inode_acl);
/*
* Init a fresh posix_acl
@ -578,19 +592,20 @@ EXPORT_SYMBOL(__posix_acl_chmod);
* posix_acl_chmod - chmod a posix acl
*
* @mnt_userns: user namespace of the mount @inode was found from
* @inode: inode to check permissions on
* @dentry: dentry to check permissions on
* @mode: the new mode of @inode
*
* If the inode has been found through an idmapped mount the user namespace of
* If the dentry 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
posix_acl_chmod(struct user_namespace *mnt_userns, struct inode *inode,
posix_acl_chmod(struct user_namespace *mnt_userns, struct dentry *dentry,
umode_t mode)
{
struct inode *inode = d_inode(dentry);
struct posix_acl *acl;
int ret = 0;
@ -599,7 +614,7 @@ int
if (!inode->i_op->set_acl)
return -EOPNOTSUPP;
acl = get_acl(inode, ACL_TYPE_ACCESS);
acl = get_inode_acl(inode, ACL_TYPE_ACCESS);
if (IS_ERR_OR_NULL(acl)) {
if (acl == ERR_PTR(-EOPNOTSUPP))
return 0;
@ -609,7 +624,7 @@ int
ret = __posix_acl_chmod(&acl, GFP_KERNEL, mode);
if (ret)
return ret;
ret = inode->i_op->set_acl(mnt_userns, inode, acl, ACL_TYPE_ACCESS);
ret = inode->i_op->set_acl(mnt_userns, dentry, acl, ACL_TYPE_ACCESS);
posix_acl_release(acl);
return ret;
}
@ -629,7 +644,7 @@ posix_acl_create(struct inode *dir, umode_t *mode,
if (S_ISLNK(*mode) || !IS_POSIXACL(dir))
return 0;
p = get_acl(dir, ACL_TYPE_DEFAULT);
p = get_inode_acl(dir, ACL_TYPE_DEFAULT);
if (!p || p == ERR_PTR(-EOPNOTSUPP)) {
*mode &= ~current_umask();
return 0;
@ -732,118 +747,32 @@ static int posix_acl_fix_xattr_common(const void *value, size_t size)
return count;
}
void posix_acl_getxattr_idmapped_mnt(struct user_namespace *mnt_userns,
const struct inode *inode,
void *value, size_t size)
{
struct posix_acl_xattr_header *header = value;
struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end;
struct user_namespace *fs_userns = i_user_ns(inode);
int count;
vfsuid_t vfsuid;
vfsgid_t vfsgid;
kuid_t uid;
kgid_t gid;
if (no_idmapping(mnt_userns, i_user_ns(inode)))
return;
count = posix_acl_fix_xattr_common(value, size);
if (count <= 0)
return;
for (end = entry + count; entry != end; entry++) {
switch (le16_to_cpu(entry->e_tag)) {
case ACL_USER:
uid = make_kuid(&init_user_ns, le32_to_cpu(entry->e_id));
vfsuid = make_vfsuid(mnt_userns, fs_userns, uid);
entry->e_id = cpu_to_le32(from_kuid(&init_user_ns,
vfsuid_into_kuid(vfsuid)));
break;
case ACL_GROUP:
gid = make_kgid(&init_user_ns, le32_to_cpu(entry->e_id));
vfsgid = make_vfsgid(mnt_userns, fs_userns, gid);
entry->e_id = cpu_to_le32(from_kgid(&init_user_ns,
vfsgid_into_kgid(vfsgid)));
break;
default:
break;
}
}
}
static void posix_acl_fix_xattr_userns(
struct user_namespace *to, struct user_namespace *from,
void *value, size_t size)
{
struct posix_acl_xattr_header *header = value;
struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end;
int count;
kuid_t uid;
kgid_t gid;
count = posix_acl_fix_xattr_common(value, size);
if (count <= 0)
return;
for (end = entry + count; entry != end; entry++) {
switch(le16_to_cpu(entry->e_tag)) {
case ACL_USER:
uid = make_kuid(from, le32_to_cpu(entry->e_id));
entry->e_id = cpu_to_le32(from_kuid(to, uid));
break;
case ACL_GROUP:
gid = make_kgid(from, le32_to_cpu(entry->e_id));
entry->e_id = cpu_to_le32(from_kgid(to, gid));
break;
default:
break;
}
}
}
void posix_acl_fix_xattr_from_user(void *value, size_t size)
{
struct user_namespace *user_ns = current_user_ns();
if (user_ns == &init_user_ns)
return;
posix_acl_fix_xattr_userns(&init_user_ns, user_ns, value, size);
}
void posix_acl_fix_xattr_to_user(void *value, size_t size)
{
struct user_namespace *user_ns = current_user_ns();
if (user_ns == &init_user_ns)
return;
posix_acl_fix_xattr_userns(user_ns, &init_user_ns, value, size);
}
/**
* make_posix_acl - convert POSIX ACLs from uapi to VFS format using the
* provided callbacks to map ACL_{GROUP,USER} entries into the
* appropriate format
* @mnt_userns: the mount's idmapping
* @fs_userns: the filesystem's idmapping
* posix_acl_from_xattr - convert POSIX ACLs from backing store to VFS format
* @userns: the filesystem's idmapping
* @value: the uapi representation of POSIX ACLs
* @size: the size of @void
* @uid_cb: callback to use for mapping the uid stored in ACL_USER entries
* @gid_cb: callback to use for mapping the gid stored in ACL_GROUP entries
*
* The make_posix_acl() helper is an abstraction to translate from uapi format
* into the VFS format allowing the caller to specific callbacks to map
* ACL_{GROUP,USER} entries into the expected format. This is used in
* posix_acl_from_xattr() and vfs_set_acl_prepare() and avoids pointless code
* duplication.
* Filesystems that store POSIX ACLs in the unaltered uapi format should use
* posix_acl_from_xattr() when reading them from the backing store and
* converting them into the struct posix_acl VFS format. The helper is
* specifically intended to be called from the acl inode operation.
*
* The posix_acl_from_xattr() function will map the raw {g,u}id values stored
* in ACL_{GROUP,USER} entries into idmapping in @userns.
*
* Note that posix_acl_from_xattr() does not take idmapped mounts into account.
* If it did it calling it from the get acl inode operation would return POSIX
* ACLs mapped according to an idmapped mount which would mean that the value
* couldn't be cached for the filesystem. Idmapped mounts are taken into
* account on the fly during permission checking or right at the VFS -
* userspace boundary before reporting them to the user.
*
* Return: Allocated struct posix_acl on success, NULL for a valid header but
* without actual POSIX ACL entries, or ERR_PTR() encoded error code.
*/
static struct posix_acl *make_posix_acl(struct user_namespace *mnt_userns,
struct user_namespace *fs_userns, const void *value, size_t size,
kuid_t (*uid_cb)(struct user_namespace *, struct user_namespace *,
const struct posix_acl_xattr_entry *),
kgid_t (*gid_cb)(struct user_namespace *, struct user_namespace *,
const struct posix_acl_xattr_entry *))
struct posix_acl *posix_acl_from_xattr(struct user_namespace *userns,
const void *value, size_t size)
{
const struct posix_acl_xattr_header *header = value;
const struct posix_acl_xattr_entry *entry = (const void *)(header + 1), *end;
@ -874,12 +803,14 @@ static struct posix_acl *make_posix_acl(struct user_namespace *mnt_userns,
break;
case ACL_USER:
acl_e->e_uid = uid_cb(mnt_userns, fs_userns, entry);
acl_e->e_uid = make_kuid(userns,
le32_to_cpu(entry->e_id));
if (!uid_valid(acl_e->e_uid))
goto fail;
break;
case ACL_GROUP:
acl_e->e_gid = gid_cb(mnt_userns, fs_userns, entry);
acl_e->e_gid = make_kgid(userns,
le32_to_cpu(entry->e_id));
if (!gid_valid(acl_e->e_gid))
goto fail;
break;
@ -894,181 +825,6 @@ static struct posix_acl *make_posix_acl(struct user_namespace *mnt_userns,
posix_acl_release(acl);
return ERR_PTR(-EINVAL);
}
/**
* vfs_set_acl_prepare_kuid - map ACL_USER uid according to mount- and
* filesystem idmapping
* @mnt_userns: the mount's idmapping
* @fs_userns: the filesystem's idmapping
* @e: a ACL_USER entry in POSIX ACL uapi format
*
* The uid stored as ACL_USER entry in @e is a kuid_t stored as a raw {g,u}id
* value. The vfs_set_acl_prepare_kuid() will recover the kuid_t through
* KUIDT_INIT() and then map it according to the idmapped mount. The resulting
* kuid_t is the value which the filesystem can map up into a raw backing store
* id in the filesystem's idmapping.
*
* This is used in vfs_set_acl_prepare() to generate the proper VFS
* representation of POSIX ACLs with ACL_USER entries during setxattr().
*
* Return: A kuid in @fs_userns for the uid stored in @e.
*/
static inline kuid_t
vfs_set_acl_prepare_kuid(struct user_namespace *mnt_userns,
struct user_namespace *fs_userns,
const struct posix_acl_xattr_entry *e)
{
kuid_t kuid = KUIDT_INIT(le32_to_cpu(e->e_id));
return from_vfsuid(mnt_userns, fs_userns, VFSUIDT_INIT(kuid));
}
/**
* vfs_set_acl_prepare_kgid - map ACL_GROUP gid according to mount- and
* filesystem idmapping
* @mnt_userns: the mount's idmapping
* @fs_userns: the filesystem's idmapping
* @e: a ACL_GROUP entry in POSIX ACL uapi format
*
* The gid stored as ACL_GROUP entry in @e is a kgid_t stored as a raw {g,u}id
* value. The vfs_set_acl_prepare_kgid() will recover the kgid_t through
* KGIDT_INIT() and then map it according to the idmapped mount. The resulting
* kgid_t is the value which the filesystem can map up into a raw backing store
* id in the filesystem's idmapping.
*
* This is used in vfs_set_acl_prepare() to generate the proper VFS
* representation of POSIX ACLs with ACL_GROUP entries during setxattr().
*
* Return: A kgid in @fs_userns for the gid stored in @e.
*/
static inline kgid_t
vfs_set_acl_prepare_kgid(struct user_namespace *mnt_userns,
struct user_namespace *fs_userns,
const struct posix_acl_xattr_entry *e)
{
kgid_t kgid = KGIDT_INIT(le32_to_cpu(e->e_id));
return from_vfsgid(mnt_userns, fs_userns, VFSGIDT_INIT(kgid));
}
/**
* vfs_set_acl_prepare - convert POSIX ACLs from uapi to VFS format taking
* mount and filesystem idmappings into account
* @mnt_userns: the mount's idmapping
* @fs_userns: the filesystem's idmapping
* @value: the uapi representation of POSIX ACLs
* @size: the size of @void
*
* When setting POSIX ACLs with ACL_{GROUP,USER} entries they need to be
* mapped according to the relevant mount- and filesystem idmapping. It is
* important that the ACL_{GROUP,USER} entries in struct posix_acl will be
* mapped into k{g,u}id_t that are supposed to be mapped up in the filesystem
* idmapping. This is crucial since the resulting struct posix_acl might be
* cached filesystem wide. The vfs_set_acl_prepare() function will take care to
* perform all necessary idmappings.
*
* Note, that since basically forever the {g,u}id values encoded as
* ACL_{GROUP,USER} entries in the uapi POSIX ACLs passed via @value contain
* values that have been mapped according to the caller's idmapping. In other
* words, POSIX ACLs passed in uapi format as @value during setxattr() contain
* {g,u}id values in their ACL_{GROUP,USER} entries that should actually have
* been stored as k{g,u}id_t.
*
* This means, vfs_set_acl_prepare() needs to first recover the k{g,u}id_t by
* calling K{G,U}IDT_INIT(). Afterwards they can be interpreted as vfs{g,u}id_t
* through from_vfs{g,u}id() to account for any idmapped mounts. The
* vfs_set_acl_prepare_k{g,u}id() helpers will take care to generate the
* correct k{g,u}id_t.
*
* The filesystem will then receive the POSIX ACLs ready to be cached
* filesystem wide and ready to be written to the backing store taking the
* filesystem's idmapping into account.
*
* Return: Allocated struct posix_acl on success, NULL for a valid header but
* without actual POSIX ACL entries, or ERR_PTR() encoded error code.
*/
struct posix_acl *vfs_set_acl_prepare(struct user_namespace *mnt_userns,
struct user_namespace *fs_userns,
const void *value, size_t size)
{
return make_posix_acl(mnt_userns, fs_userns, value, size,
vfs_set_acl_prepare_kuid,
vfs_set_acl_prepare_kgid);
}
EXPORT_SYMBOL(vfs_set_acl_prepare);
/**
* posix_acl_from_xattr_kuid - map ACL_USER uid into filesystem idmapping
* @mnt_userns: unused
* @fs_userns: the filesystem's idmapping
* @e: a ACL_USER entry in POSIX ACL uapi format
*
* Map the uid stored as ACL_USER entry in @e into the filesystem's idmapping.
* This is used in posix_acl_from_xattr() to generate the proper VFS
* representation of POSIX ACLs with ACL_USER entries.
*
* Return: A kuid in @fs_userns for the uid stored in @e.
*/
static inline kuid_t
posix_acl_from_xattr_kuid(struct user_namespace *mnt_userns,
struct user_namespace *fs_userns,
const struct posix_acl_xattr_entry *e)
{
return make_kuid(fs_userns, le32_to_cpu(e->e_id));
}
/**
* posix_acl_from_xattr_kgid - map ACL_GROUP gid into filesystem idmapping
* @mnt_userns: unused
* @fs_userns: the filesystem's idmapping
* @e: a ACL_GROUP entry in POSIX ACL uapi format
*
* Map the gid stored as ACL_GROUP entry in @e into the filesystem's idmapping.
* This is used in posix_acl_from_xattr() to generate the proper VFS
* representation of POSIX ACLs with ACL_GROUP entries.
*
* Return: A kgid in @fs_userns for the gid stored in @e.
*/
static inline kgid_t
posix_acl_from_xattr_kgid(struct user_namespace *mnt_userns,
struct user_namespace *fs_userns,
const struct posix_acl_xattr_entry *e)
{
return make_kgid(fs_userns, le32_to_cpu(e->e_id));
}
/**
* posix_acl_from_xattr - convert POSIX ACLs from backing store to VFS format
* @fs_userns: the filesystem's idmapping
* @value: the uapi representation of POSIX ACLs
* @size: the size of @void
*
* Filesystems that store POSIX ACLs in the unaltered uapi format should use
* posix_acl_from_xattr() when reading them from the backing store and
* converting them into the struct posix_acl VFS format. The helper is
* specifically intended to be called from the ->get_acl() inode operation.
*
* The posix_acl_from_xattr() function will map the raw {g,u}id values stored
* in ACL_{GROUP,USER} entries into the filesystem idmapping in @fs_userns. The
* posix_acl_from_xattr_k{g,u}id() helpers will take care to generate the
* correct k{g,u}id_t. The returned struct posix_acl can be cached.
*
* Note that posix_acl_from_xattr() does not take idmapped mounts into account.
* If it did it calling is from the ->get_acl() inode operation would return
* POSIX ACLs mapped according to an idmapped mount which would mean that the
* value couldn't be cached for the filesystem. Idmapped mounts are taken into
* account on the fly during permission checking or right at the VFS -
* userspace boundary before reporting them to the user.
*
* Return: Allocated struct posix_acl on success, NULL for a valid header but
* without actual POSIX ACL entries, or ERR_PTR() encoded error code.
*/
struct posix_acl *
posix_acl_from_xattr(struct user_namespace *fs_userns,
const void *value, size_t size)
{
return make_posix_acl(&init_user_ns, fs_userns, value, size,
posix_acl_from_xattr_kuid,
posix_acl_from_xattr_kgid);
}
EXPORT_SYMBOL (posix_acl_from_xattr);
/*
@ -1113,35 +869,73 @@ posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl,
}
EXPORT_SYMBOL (posix_acl_to_xattr);
static int
posix_acl_xattr_get(const struct xattr_handler *handler,
struct dentry *unused, struct inode *inode,
const char *name, void *value, size_t size)
/**
* vfs_posix_acl_to_xattr - convert from kernel to userspace representation
* @mnt_userns: user namespace of the mount
* @inode: inode the posix acls are set on
* @acl: the posix acls as represented by the vfs
* @buffer: the buffer into which to convert @acl
* @size: size of @buffer
*
* This converts @acl from the VFS representation in the filesystem idmapping
* to the uapi form reportable to userspace. And mount and caller idmappings
* are handled appropriately.
*
* Return: On success, the size of the stored uapi posix acls, on error a
* negative errno.
*/
ssize_t vfs_posix_acl_to_xattr(struct user_namespace *mnt_userns,
struct inode *inode, const struct posix_acl *acl,
void *buffer, size_t size)
{
struct posix_acl *acl;
int error;
struct posix_acl_xattr_header *ext_acl = buffer;
struct posix_acl_xattr_entry *ext_entry;
struct user_namespace *fs_userns, *caller_userns;
ssize_t real_size, n;
vfsuid_t vfsuid;
vfsgid_t vfsgid;
if (!IS_POSIXACL(inode))
return -EOPNOTSUPP;
if (S_ISLNK(inode->i_mode))
return -EOPNOTSUPP;
real_size = posix_acl_xattr_size(acl->a_count);
if (!buffer)
return real_size;
if (real_size > size)
return -ERANGE;
acl = get_acl(inode, handler->flags);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (acl == NULL)
return -ENODATA;
ext_entry = (void *)(ext_acl + 1);
ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
error = posix_acl_to_xattr(&init_user_ns, acl, value, size);
posix_acl_release(acl);
return error;
fs_userns = i_user_ns(inode);
caller_userns = current_user_ns();
for (n=0; n < acl->a_count; n++, ext_entry++) {
const struct posix_acl_entry *acl_e = &acl->a_entries[n];
ext_entry->e_tag = cpu_to_le16(acl_e->e_tag);
ext_entry->e_perm = cpu_to_le16(acl_e->e_perm);
switch(acl_e->e_tag) {
case ACL_USER:
vfsuid = make_vfsuid(mnt_userns, fs_userns, acl_e->e_uid);
ext_entry->e_id = cpu_to_le32(from_kuid(
caller_userns, vfsuid_into_kuid(vfsuid)));
break;
case ACL_GROUP:
vfsgid = make_vfsgid(mnt_userns, fs_userns, acl_e->e_gid);
ext_entry->e_id = cpu_to_le32(from_kgid(
caller_userns, vfsgid_into_kgid(vfsgid)));
break;
default:
ext_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
break;
}
}
return real_size;
}
int
set_posix_acl(struct user_namespace *mnt_userns, struct inode *inode,
set_posix_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
int type, struct posix_acl *acl)
{
struct inode *inode = d_inode(dentry);
if (!IS_POSIXACL(inode))
return -EOPNOTSUPP;
if (!inode->i_op->set_acl)
@ -1157,40 +951,10 @@ set_posix_acl(struct user_namespace *mnt_userns, struct inode *inode,
if (ret)
return ret;
}
return inode->i_op->set_acl(mnt_userns, inode, acl, type);
return inode->i_op->set_acl(mnt_userns, dentry, acl, type);
}
EXPORT_SYMBOL(set_posix_acl);
static int
posix_acl_xattr_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)
{
struct posix_acl *acl = NULL;
int ret;
if (value) {
/*
* By the time we end up here the {g,u}ids stored in
* ACL_{GROUP,USER} have already been mapped according to the
* caller's idmapping. The vfs_set_acl_prepare() helper will
* recover them and take idmapped mounts into account. The
* filesystem will receive the POSIX ACLs in the correct
* format ready to be cached or written to the backing store
* taking the filesystem idmapping into account.
*/
acl = vfs_set_acl_prepare(mnt_userns, i_user_ns(inode),
value, size);
if (IS_ERR(acl))
return PTR_ERR(acl);
}
ret = set_posix_acl(mnt_userns, inode, handler->flags, acl);
posix_acl_release(acl);
return ret;
}
static bool
posix_acl_xattr_list(struct dentry *dentry)
{
@ -1201,8 +965,6 @@ const struct xattr_handler posix_acl_access_xattr_handler = {
.name = XATTR_NAME_POSIX_ACL_ACCESS,
.flags = ACL_TYPE_ACCESS,
.list = posix_acl_xattr_list,
.get = posix_acl_xattr_get,
.set = posix_acl_xattr_set,
};
EXPORT_SYMBOL_GPL(posix_acl_access_xattr_handler);
@ -1210,15 +972,14 @@ const struct xattr_handler posix_acl_default_xattr_handler = {
.name = XATTR_NAME_POSIX_ACL_DEFAULT,
.flags = ACL_TYPE_DEFAULT,
.list = posix_acl_xattr_list,
.get = posix_acl_xattr_get,
.set = posix_acl_xattr_set,
};
EXPORT_SYMBOL_GPL(posix_acl_default_xattr_handler);
int simple_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
int simple_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
int error;
struct inode *inode = d_inode(dentry);
if (type == ACL_TYPE_ACCESS) {
error = posix_acl_update_mode(mnt_userns, inode,
@ -1252,3 +1013,252 @@ int simple_acl_create(struct inode *dir, struct inode *inode)
posix_acl_release(acl);
return 0;
}
static int vfs_set_acl_idmapped_mnt(struct user_namespace *mnt_userns,
struct user_namespace *fs_userns,
struct posix_acl *acl)
{
for (int n = 0; n < acl->a_count; n++) {
struct posix_acl_entry *acl_e = &acl->a_entries[n];
switch (acl_e->e_tag) {
case ACL_USER:
acl_e->e_uid = from_vfsuid(mnt_userns, fs_userns,
VFSUIDT_INIT(acl_e->e_uid));
break;
case ACL_GROUP:
acl_e->e_gid = from_vfsgid(mnt_userns, fs_userns,
VFSGIDT_INIT(acl_e->e_gid));
break;
}
}
return 0;
}
/**
* vfs_set_acl - set posix acls
* @mnt_userns: user namespace of the mount
* @dentry: the dentry based on which to set the posix acls
* @acl_name: the name of the posix acl
* @kacl: the posix acls in the appropriate VFS format
*
* This function sets @kacl. The caller must all posix_acl_release() on @kacl
* afterwards.
*
* Return: On success 0, on error negative errno.
*/
int vfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
const char *acl_name, struct posix_acl *kacl)
{
int acl_type;
int error;
struct inode *inode = d_inode(dentry);
struct inode *delegated_inode = NULL;
acl_type = posix_acl_type(acl_name);
if (acl_type < 0)
return -EINVAL;
if (kacl) {
/*
* If we're on an idmapped mount translate from mount specific
* vfs{g,u}id_t into global filesystem k{g,u}id_t.
* Afterwards we can cache the POSIX ACLs filesystem wide and -
* if this is a filesystem with a backing store - ultimately
* translate them to backing store values.
*/
error = vfs_set_acl_idmapped_mnt(mnt_userns, i_user_ns(inode), kacl);
if (error)
return error;
}
retry_deleg:
inode_lock(inode);
/*
* We only care about restrictions the inode struct itself places upon
* us otherwise POSIX ACLs aren't subject to any VFS restrictions.
*/
error = may_write_xattr(mnt_userns, inode);
if (error)
goto out_inode_unlock;
error = security_inode_set_acl(mnt_userns, dentry, acl_name, kacl);
if (error)
goto out_inode_unlock;
error = try_break_deleg(inode, &delegated_inode);
if (error)
goto out_inode_unlock;
if (inode->i_opflags & IOP_XATTR)
error = set_posix_acl(mnt_userns, dentry, acl_type, kacl);
else if (unlikely(is_bad_inode(inode)))
error = -EIO;
else
error = -EOPNOTSUPP;
if (!error) {
fsnotify_xattr(dentry);
evm_inode_post_set_acl(dentry, acl_name, kacl);
}
out_inode_unlock:
inode_unlock(inode);
if (delegated_inode) {
error = break_deleg_wait(&delegated_inode);
if (!error)
goto retry_deleg;
}
return error;
}
EXPORT_SYMBOL_GPL(vfs_set_acl);
/**
* vfs_get_acl - get posix acls
* @mnt_userns: user namespace of the mount
* @dentry: the dentry based on which to retrieve the posix acls
* @acl_name: the name of the posix acl
*
* This function retrieves @kacl from the filesystem. The caller must all
* posix_acl_release() on @kacl.
*
* Return: On success POSIX ACLs in VFS format, on error negative errno.
*/
struct posix_acl *vfs_get_acl(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *acl_name)
{
struct inode *inode = d_inode(dentry);
struct posix_acl *acl;
int acl_type, error;
acl_type = posix_acl_type(acl_name);
if (acl_type < 0)
return ERR_PTR(-EINVAL);
/*
* The VFS has no restrictions on reading POSIX ACLs so calling
* something like xattr_permission() isn't needed. Only LSMs get a say.
*/
error = security_inode_get_acl(mnt_userns, dentry, acl_name);
if (error)
return ERR_PTR(error);
if (!IS_POSIXACL(inode))
return ERR_PTR(-EOPNOTSUPP);
if (S_ISLNK(inode->i_mode))
return ERR_PTR(-EOPNOTSUPP);
acl = __get_acl(mnt_userns, dentry, inode, acl_type);
if (IS_ERR(acl))
return acl;
if (!acl)
return ERR_PTR(-ENODATA);
return acl;
}
EXPORT_SYMBOL_GPL(vfs_get_acl);
/**
* vfs_remove_acl - remove posix acls
* @mnt_userns: user namespace of the mount
* @dentry: the dentry based on which to retrieve the posix acls
* @acl_name: the name of the posix acl
*
* This function removes posix acls.
*
* Return: On success 0, on error negative errno.
*/
int vfs_remove_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
const char *acl_name)
{
int acl_type;
int error;
struct inode *inode = d_inode(dentry);
struct inode *delegated_inode = NULL;
acl_type = posix_acl_type(acl_name);
if (acl_type < 0)
return -EINVAL;
retry_deleg:
inode_lock(inode);
/*
* We only care about restrictions the inode struct itself places upon
* us otherwise POSIX ACLs aren't subject to any VFS restrictions.
*/
error = may_write_xattr(mnt_userns, inode);
if (error)
goto out_inode_unlock;
error = security_inode_remove_acl(mnt_userns, dentry, acl_name);
if (error)
goto out_inode_unlock;
error = try_break_deleg(inode, &delegated_inode);
if (error)
goto out_inode_unlock;
if (inode->i_opflags & IOP_XATTR)
error = set_posix_acl(mnt_userns, dentry, acl_type, NULL);
else if (unlikely(is_bad_inode(inode)))
error = -EIO;
else
error = -EOPNOTSUPP;
if (!error) {
fsnotify_xattr(dentry);
evm_inode_post_remove_acl(mnt_userns, dentry, acl_name);
}
out_inode_unlock:
inode_unlock(inode);
if (delegated_inode) {
error = break_deleg_wait(&delegated_inode);
if (!error)
goto retry_deleg;
}
return error;
}
EXPORT_SYMBOL_GPL(vfs_remove_acl);
int do_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
const char *acl_name, const void *kvalue, size_t size)
{
int error;
struct posix_acl *acl = NULL;
if (size) {
/*
* Note that posix_acl_from_xattr() uses GFP_NOFS when it
* probably doesn't need to here.
*/
acl = posix_acl_from_xattr(current_user_ns(), kvalue, size);
if (IS_ERR(acl))
return PTR_ERR(acl);
}
error = vfs_set_acl(mnt_userns, dentry, acl_name, acl);
posix_acl_release(acl);
return error;
}
ssize_t do_get_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
const char *acl_name, void *kvalue, size_t size)
{
ssize_t error;
struct posix_acl *acl;
acl = vfs_get_acl(mnt_userns, dentry, acl_name);
if (IS_ERR(acl))
return PTR_ERR(acl);
error = vfs_posix_acl_to_xattr(mnt_userns, d_inode(dentry),
acl, kvalue, size);
posix_acl_release(acl);
return error;
}

View file

@ -49,9 +49,9 @@ static inline int reiserfs_acl_count(size_t size)
#ifdef CONFIG_REISERFS_FS_POSIX_ACL
struct posix_acl *reiserfs_get_acl(struct inode *inode, int type, bool rcu);
int reiserfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
int reiserfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
int reiserfs_acl_chmod(struct inode *inode);
int reiserfs_acl_chmod(struct dentry *dentry);
int reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
struct inode *dir, struct dentry *dentry,
struct inode *inode);
@ -63,7 +63,7 @@ int reiserfs_cache_default_acl(struct inode *dir);
#define reiserfs_get_acl NULL
#define reiserfs_set_acl NULL
static inline int reiserfs_acl_chmod(struct inode *inode)
static inline int reiserfs_acl_chmod(struct dentry *dentry)
{
return 0;
}

View file

@ -256,7 +256,7 @@ const struct inode_operations reiserfs_file_inode_operations = {
.setattr = reiserfs_setattr,
.listxattr = reiserfs_listxattr,
.permission = reiserfs_permission,
.get_acl = reiserfs_get_acl,
.get_inode_acl = reiserfs_get_acl,
.set_acl = reiserfs_set_acl,
.fileattr_get = reiserfs_fileattr_get,
.fileattr_set = reiserfs_fileattr_set,

View file

@ -3404,7 +3404,7 @@ int reiserfs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
if (!error && reiserfs_posixacl(inode->i_sb)) {
if (attr->ia_valid & ATTR_MODE)
error = reiserfs_acl_chmod(inode);
error = reiserfs_acl_chmod(dentry);
}
out:

View file

@ -1659,7 +1659,7 @@ const struct inode_operations reiserfs_dir_inode_operations = {
.setattr = reiserfs_setattr,
.listxattr = reiserfs_listxattr,
.permission = reiserfs_permission,
.get_acl = reiserfs_get_acl,
.get_inode_acl = reiserfs_get_acl,
.set_acl = reiserfs_set_acl,
.fileattr_get = reiserfs_fileattr_get,
.fileattr_set = reiserfs_fileattr_set,
@ -1683,6 +1683,6 @@ const struct inode_operations reiserfs_special_inode_operations = {
.setattr = reiserfs_setattr,
.listxattr = reiserfs_listxattr,
.permission = reiserfs_permission,
.get_acl = reiserfs_get_acl,
.get_inode_acl = reiserfs_get_acl,
.set_acl = reiserfs_set_acl,
};

View file

@ -18,7 +18,7 @@ static int __reiserfs_set_acl(struct reiserfs_transaction_handle *th,
int
reiserfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
reiserfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
int error, error2;
@ -26,6 +26,7 @@ reiserfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
size_t jcreate_blocks;
int size = acl ? posix_acl_xattr_size(acl->a_count) : 0;
int update_mode = 0;
struct inode *inode = d_inode(dentry);
umode_t mode = inode->i_mode;
/*
@ -371,7 +372,7 @@ int reiserfs_cache_default_acl(struct inode *inode)
if (IS_PRIVATE(inode))
return 0;
acl = get_acl(inode, ACL_TYPE_DEFAULT);
acl = get_inode_acl(inode, ACL_TYPE_DEFAULT);
if (acl && !IS_ERR(acl)) {
int size = reiserfs_acl_size(acl->a_count);
@ -396,13 +397,15 @@ int reiserfs_cache_default_acl(struct inode *inode)
/*
* Called under i_mutex
*/
int reiserfs_acl_chmod(struct inode *inode)
int reiserfs_acl_chmod(struct dentry *dentry)
{
struct inode *inode = d_inode(dentry);
if (IS_PRIVATE(inode))
return 0;
if (get_inode_sd_version(inode) == STAT_DATA_V1 ||
!reiserfs_posixacl(inode->i_sb))
return 0;
return posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
return posix_acl_chmod(&init_user_ns, dentry, inode->i_mode);
}

View file

@ -80,6 +80,31 @@ xattr_resolve_name(struct inode *inode, const char **name)
return ERR_PTR(-EOPNOTSUPP);
}
/**
* may_write_xattr - check whether inode allows writing xattr
* @mnt_userns: User namespace of the mount the inode was found from
* @inode: the inode on which to set an xattr
*
* Check whether the inode allows writing xattrs. Specifically, we can never
* set or remove an extended attribute on a read-only filesystem or on an
* immutable / append-only inode.
*
* We also need to ensure that the inode has a mapping in the mount to
* not risk writing back invalid i_{g,u}id values.
*
* Return: On success zero is returned. On error a negative errno is returned.
*/
int may_write_xattr(struct user_namespace *mnt_userns, struct inode *inode)
{
if (IS_IMMUTABLE(inode))
return -EPERM;
if (IS_APPEND(inode))
return -EPERM;
if (HAS_UNMAPPED_ID(mnt_userns, inode))
return -EPERM;
return 0;
}
/*
* Check permissions for extended attribute access. This is a bit complicated
* because different namespaces have very different rules.
@ -88,20 +113,12 @@ static int
xattr_permission(struct user_namespace *mnt_userns, struct inode *inode,
const char *name, int mask)
{
/*
* We can never set or remove an extended attribute on a read-only
* filesystem or on an immutable / append-only inode.
*/
if (mask & MAY_WRITE) {
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
return -EPERM;
/*
* Updating an xattr will likely cause i_uid and i_gid
* to be writen back improperly if their true value is
* unknown to the vfs.
*/
if (HAS_UNMAPPED_ID(mnt_userns, inode))
return -EPERM;
int ret;
ret = may_write_xattr(mnt_userns, inode);
if (ret)
return ret;
}
/*
@ -172,6 +189,9 @@ __vfs_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
{
const struct xattr_handler *handler;
if (is_posix_acl_xattr(name))
return -EOPNOTSUPP;
handler = xattr_resolve_name(inode, &name);
if (IS_ERR(handler))
return PTR_ERR(handler);
@ -282,12 +302,6 @@ __vfs_setxattr_locked(struct user_namespace *mnt_userns, struct dentry *dentry,
}
EXPORT_SYMBOL_GPL(__vfs_setxattr_locked);
static inline bool is_posix_acl_xattr(const char *name)
{
return (strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
(strcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT) == 0);
}
int
vfs_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
const char *name, const void *value, size_t size, int flags)
@ -399,6 +413,9 @@ __vfs_getxattr(struct dentry *dentry, struct inode *inode, const char *name,
{
const struct xattr_handler *handler;
if (is_posix_acl_xattr(name))
return -EOPNOTSUPP;
handler = xattr_resolve_name(inode, &name);
if (IS_ERR(handler))
return PTR_ERR(handler);
@ -437,10 +454,7 @@ vfs_getxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
return ret;
}
nolsm:
error = __vfs_getxattr(dentry, inode, name, value, size);
if (error > 0 && is_posix_acl_xattr(name))
posix_acl_getxattr_idmapped_mnt(mnt_userns, inode, value, size);
return error;
return __vfs_getxattr(dentry, inode, name, value, size);
}
EXPORT_SYMBOL_GPL(vfs_getxattr);
@ -471,6 +485,9 @@ __vfs_removexattr(struct user_namespace *mnt_userns, struct dentry *dentry,
struct inode *inode = d_inode(dentry);
const struct xattr_handler *handler;
if (is_posix_acl_xattr(name))
return -EOPNOTSUPP;
handler = xattr_resolve_name(inode, &name);
if (IS_ERR(handler))
return PTR_ERR(handler);
@ -580,17 +597,13 @@ int setxattr_copy(const char __user *name, struct xattr_ctx *ctx)
return error;
}
static void setxattr_convert(struct user_namespace *mnt_userns,
struct dentry *d, struct xattr_ctx *ctx)
{
if (ctx->size && is_posix_acl_xattr(ctx->kname->name))
posix_acl_fix_xattr_from_user(ctx->kvalue, ctx->size);
}
int do_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
struct xattr_ctx *ctx)
{
setxattr_convert(mnt_userns, dentry, ctx);
if (is_posix_acl_xattr(ctx->kname->name))
return do_set_acl(mnt_userns, dentry, ctx->kname->name,
ctx->kvalue, ctx->size);
return vfs_setxattr(mnt_userns, dentry, ctx->kname->name,
ctx->kvalue, ctx->size, ctx->flags);
}
@ -697,10 +710,11 @@ do_getxattr(struct user_namespace *mnt_userns, struct dentry *d,
return -ENOMEM;
}
error = vfs_getxattr(mnt_userns, d, kname, ctx->kvalue, ctx->size);
if (is_posix_acl_xattr(ctx->kname->name))
error = do_get_acl(mnt_userns, d, kname, ctx->kvalue, ctx->size);
else
error = vfs_getxattr(mnt_userns, d, kname, ctx->kvalue, ctx->size);
if (error > 0) {
if (is_posix_acl_xattr(kname))
posix_acl_fix_xattr_to_user(ctx->kvalue, error);
if (ctx->size && copy_to_user(ctx->value, ctx->kvalue, error))
error = -EFAULT;
} else if (error == -ERANGE && ctx->size >= XATTR_SIZE_MAX) {
@ -875,6 +889,9 @@ removexattr(struct user_namespace *mnt_userns, struct dentry *d,
if (error < 0)
return error;
if (is_posix_acl_xattr(kname))
return vfs_remove_acl(mnt_userns, d, kname);
return vfs_removexattr(mnt_userns, d, kname);
}

View file

@ -242,12 +242,13 @@ xfs_acl_set_mode(
}
int
xfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
xfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type)
{
umode_t mode;
bool set_mode = false;
int error = 0;
struct inode *inode = d_inode(dentry);
if (!acl)
goto set_acl;

View file

@ -11,7 +11,7 @@ struct posix_acl;
#ifdef CONFIG_XFS_POSIX_ACL
extern struct posix_acl *xfs_get_acl(struct inode *inode, int type, bool rcu);
extern int xfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
extern int xfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
struct posix_acl *acl, int type);
extern int __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
void xfs_forget_acl(struct inode *inode, const char *name);

View file

@ -651,6 +651,7 @@ xfs_vn_change_ok(
static int
xfs_setattr_nonsize(
struct user_namespace *mnt_userns,
struct dentry *dentry,
struct xfs_inode *ip,
struct iattr *iattr)
{
@ -757,7 +758,7 @@ xfs_setattr_nonsize(
* Posix ACL code seems to care about this issue either.
*/
if (mask & ATTR_MODE) {
error = posix_acl_chmod(mnt_userns, inode, inode->i_mode);
error = posix_acl_chmod(mnt_userns, dentry, inode->i_mode);
if (error)
return error;
}
@ -779,6 +780,7 @@ xfs_setattr_nonsize(
STATIC int
xfs_setattr_size(
struct user_namespace *mnt_userns,
struct dentry *dentry,
struct xfs_inode *ip,
struct iattr *iattr)
{
@ -810,7 +812,7 @@ xfs_setattr_size(
* Use the regular setattr path to update the timestamps.
*/
iattr->ia_valid &= ~ATTR_SIZE;
return xfs_setattr_nonsize(mnt_userns, ip, iattr);
return xfs_setattr_nonsize(mnt_userns, dentry, ip, iattr);
}
/*
@ -987,7 +989,7 @@ xfs_vn_setattr_size(
error = xfs_vn_change_ok(mnt_userns, dentry, iattr);
if (error)
return error;
return xfs_setattr_size(mnt_userns, ip, iattr);
return xfs_setattr_size(mnt_userns, dentry, ip, iattr);
}
STATIC int
@ -1019,7 +1021,7 @@ xfs_vn_setattr(
error = xfs_vn_change_ok(mnt_userns, dentry, iattr);
if (!error)
error = xfs_setattr_nonsize(mnt_userns, ip, iattr);
error = xfs_setattr_nonsize(mnt_userns, dentry, ip, iattr);
}
return error;
@ -1101,7 +1103,7 @@ xfs_vn_tmpfile(
}
static const struct inode_operations xfs_inode_operations = {
.get_acl = xfs_get_acl,
.get_inode_acl = xfs_get_acl,
.set_acl = xfs_set_acl,
.getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr,
@ -1128,7 +1130,7 @@ static const struct inode_operations xfs_dir_inode_operations = {
.rmdir = xfs_vn_unlink,
.mknod = xfs_vn_mknod,
.rename = xfs_vn_rename,
.get_acl = xfs_get_acl,
.get_inode_acl = xfs_get_acl,
.set_acl = xfs_set_acl,
.getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr,
@ -1155,7 +1157,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = {
.rmdir = xfs_vn_unlink,
.mknod = xfs_vn_mknod,
.rename = xfs_vn_rename,
.get_acl = xfs_get_acl,
.get_inode_acl = xfs_get_acl,
.set_acl = xfs_set_acl,
.getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr,

View file

@ -35,6 +35,27 @@ extern int evm_inode_removexattr(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *xattr_name);
extern void evm_inode_post_removexattr(struct dentry *dentry,
const char *xattr_name);
static inline void evm_inode_post_remove_acl(struct user_namespace *mnt_userns,
struct dentry *dentry,
const char *acl_name)
{
evm_inode_post_removexattr(dentry, acl_name);
}
extern int evm_inode_set_acl(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *acl_name,
struct posix_acl *kacl);
static inline int evm_inode_remove_acl(struct user_namespace *mnt_userns,
struct dentry *dentry,
const char *acl_name)
{
return evm_inode_set_acl(mnt_userns, dentry, acl_name, NULL);
}
static inline void evm_inode_post_set_acl(struct dentry *dentry,
const char *acl_name,
struct posix_acl *kacl)
{
return evm_inode_post_setxattr(dentry, acl_name, NULL, 0);
}
extern int evm_inode_init_security(struct inode *inode,
const struct xattr *xattr_array,
struct xattr *evm);
@ -108,6 +129,34 @@ static inline void evm_inode_post_removexattr(struct dentry *dentry,
return;
}
static inline void evm_inode_post_remove_acl(struct user_namespace *mnt_userns,
struct dentry *dentry,
const char *acl_name)
{
return;
}
static inline int evm_inode_set_acl(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *acl_name,
struct posix_acl *kacl)
{
return 0;
}
static inline int evm_inode_remove_acl(struct user_namespace *mnt_userns,
struct dentry *dentry,
const char *acl_name)
{
return 0;
}
static inline void evm_inode_post_set_acl(struct dentry *dentry,
const char *acl_name,
struct posix_acl *kacl)
{
return;
}
static inline int evm_inode_init_security(struct inode *inode,
const struct xattr *xattr_array,
struct xattr *evm)

View file

@ -560,8 +560,8 @@ struct posix_acl;
#define ACL_NOT_CACHED ((void *)(-1))
/*
* ACL_DONT_CACHE is for stacked filesystems, that rely on underlying fs to
* cache the ACL. This also means that ->get_acl() can be called in RCU mode
* with the LOOKUP_RCU flag.
* cache the ACL. This also means that ->get_inode_acl() can be called in RCU
* mode with the LOOKUP_RCU flag.
*/
#define ACL_DONT_CACHE ((void *)(-3))
@ -2142,7 +2142,7 @@ struct inode_operations {
struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *);
int (*permission) (struct user_namespace *, struct inode *, int);
struct posix_acl * (*get_acl)(struct inode *, int, bool);
struct posix_acl * (*get_inode_acl)(struct inode *, int, bool);
int (*readlink) (struct dentry *, char __user *,int);
@ -2172,7 +2172,9 @@ struct inode_operations {
umode_t create_mode);
int (*tmpfile) (struct user_namespace *, struct inode *,
struct file *, umode_t);
int (*set_acl)(struct user_namespace *, struct inode *,
struct posix_acl *(*get_acl)(struct user_namespace *, struct dentry *,
int);
int (*set_acl)(struct user_namespace *, struct dentry *,
struct posix_acl *, int);
int (*fileattr_set)(struct user_namespace *mnt_userns,
struct dentry *dentry, struct fileattr *fa);

View file

@ -187,6 +187,15 @@ extern void ima_inode_post_setattr(struct user_namespace *mnt_userns,
struct dentry *dentry);
extern int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
const void *xattr_value, size_t xattr_value_len);
extern int ima_inode_set_acl(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *acl_name,
struct posix_acl *kacl);
static inline int ima_inode_remove_acl(struct user_namespace *mnt_userns,
struct dentry *dentry,
const char *acl_name)
{
return ima_inode_set_acl(mnt_userns, dentry, acl_name, NULL);
}
extern int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name);
#else
static inline bool is_ima_appraise_enabled(void)
@ -208,11 +217,26 @@ static inline int ima_inode_setxattr(struct dentry *dentry,
return 0;
}
static inline int ima_inode_set_acl(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *acl_name,
struct posix_acl *kacl)
{
return 0;
}
static inline int ima_inode_removexattr(struct dentry *dentry,
const char *xattr_name)
{
return 0;
}
static inline int ima_inode_remove_acl(struct user_namespace *mnt_userns,
struct dentry *dentry,
const char *acl_name)
{
return 0;
}
#endif /* CONFIG_IMA_APPRAISE */
#if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING)

View file

@ -145,6 +145,12 @@ LSM_HOOK(int, 0, inode_getxattr, struct dentry *dentry, const char *name)
LSM_HOOK(int, 0, inode_listxattr, struct dentry *dentry)
LSM_HOOK(int, 0, inode_removexattr, struct user_namespace *mnt_userns,
struct dentry *dentry, const char *name)
LSM_HOOK(int, 0, inode_set_acl, struct user_namespace *mnt_userns,
struct dentry *dentry, const char *acl_name, struct posix_acl *kacl)
LSM_HOOK(int, 0, inode_get_acl, struct user_namespace *mnt_userns,
struct dentry *dentry, const char *acl_name)
LSM_HOOK(int, 0, inode_remove_acl, struct user_namespace *mnt_userns,
struct dentry *dentry, const char *acl_name)
LSM_HOOK(int, 0, inode_need_killpriv, struct dentry *dentry)
LSM_HOOK(int, 0, inode_killpriv, struct user_namespace *mnt_userns,
struct dentry *dentry)

View file

@ -435,6 +435,18 @@
* Check permission before removing the extended attribute
* identified by @name for @dentry.
* Return 0 if permission is granted.
* @inode_set_acl:
* Check permission before setting posix acls
* The posix acls in @kacl are identified by @acl_name.
* Return 0 if permission is granted.
* @inode_get_acl:
* Check permission before getting osix acls
* The posix acls are identified by @acl_name.
* Return 0 if permission is granted.
* @inode_remove_acl:
* Check permission before removing posix acls
* The posix acls are identified by @acl_name.
* Return 0 if permission is granted.
* @inode_getsecurity:
* Retrieve a copy of the extended attribute representation of the
* security label associated with @name for @inode via @buffer. Note that

Some files were not shown because too many files have changed in this diff Show more