Merge branch 'fs.acl.rework' into for-next
This commit is contained in:
commit
03fd1402bd
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
293
fs/9p/acl.c
293
fs/9p/acl.c
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -110,10 +110,11 @@ out:
|
|||
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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -85,13 +85,14 @@ retry:
|
|||
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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 @@ queryAclRetry:
|
|||
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 @@ setAclRetry:
|
|||
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 @@ setACLerrorExit:
|
|||
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,
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 *);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 *);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -5550,7 +5550,7 @@ out_mmap_sem:
|
|||
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)
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -109,9 +109,10 @@ out:
|
|||
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;
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -94,12 +94,13 @@ out:
|
|||
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);
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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 *);
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -619,10 +619,10 @@ out:
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 *,
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 @@ out:
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -828,15 +828,23 @@ again:
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 @@ again2:
|
|||
|
||||
/* 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 @@ out:
|
|||
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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -435,28 +435,12 @@ out:
|
|||
}
|
||||
|
||||
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,
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -813,13 +813,11 @@ retry:
|
|||
* 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,
|
||||
|
|
722
fs/posix_acl.c
722
fs/posix_acl.c
|
@ -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 @@ fail:
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
85
fs/xattr.c
85
fs/xattr.c
|
@ -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 @@ out:
|
|||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 @@ out_dqrele:
|
|||
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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue