mirror of
https://github.com/torvalds/linux.git
synced 2024-12-25 20:32:22 +00:00
fs.acl.rework.v6.2
-----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCY5bwTgAKCRCRxhvAZXjc ovd2AQCK00NAtGjQCjQPQGyTa4GAPqvWgq1ef0lnhv+TL5US5gD9FncQ8UofeMXt pBfjtAD6ettTPCTxUQfnTwWEU4rc7Qg= =27Wm -----END PGP SIGNATURE----- Merge tag 'fs.acl.rework.v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/idmapping Pull VFS acl updates from Christian Brauner: "This contains the work that builds a dedicated vfs posix acl api. The origins of this work trace back to v5.19 but it took quite a while to understand the various filesystem specific implementations in sufficient detail and also come up with an acceptable solution. As we discussed and seen multiple times the current state of how posix acls are handled isn't nice and comes with a lot of problems: The current way of handling posix acls via the generic xattr api is error prone, hard to maintain, and type unsafe for the vfs until we call into the filesystem's dedicated get and set inode operations. It is already the case that posix acls are special-cased to death all the way through the vfs. There are an uncounted number of hacks that operate on the uapi posix acl struct instead of the dedicated vfs struct posix_acl. And the vfs must be involved in order to interpret and fixup posix acls before storing them to the backing store, caching them, reporting them to userspace, or for permission checking. Currently a range of hacks and duct tape exist to make this work. As with most things this is really no ones fault it's just something that happened over time. But the code is hard to understand and difficult to maintain and one is constantly at risk of introducing bugs and regressions when having to touch it. Instead of continuing to hack posix acls through the xattr handlers this series builds a dedicated posix acl api solely around the get and set inode operations. Going forward, the vfs_get_acl(), vfs_remove_acl(), and vfs_set_acl() helpers must be used in order to interact with posix acls. They operate directly on the vfs internal struct posix_acl instead of abusing the uapi posix acl struct as we currently do. In the end this removes all of the hackiness, makes the codepaths easier to maintain, and gets us type safety. This series passes the LTP and xfstests suites without any regressions. For xfstests the following combinations were tested: - xfs - ext4 - btrfs - overlayfs - overlayfs on top of idmapped mounts - orangefs - (limited) cifs There's more simplifications for posix acls that we can make in the future if the basic api has made it. A few implementation details: - The series makes sure to retain exactly the same security and integrity module permission checks. Especially for the integrity modules this api is a win because right now they convert the uapi posix acl struct passed to them via a void pointer into the vfs struct posix_acl format to perform permission checking on the mode. There's a new dedicated security hook for setting posix acls which passes the vfs struct posix_acl not a void pointer. Basing checking on the posix acl stored in the uapi format is really unreliable. The vfs currently hacks around directly in the uapi struct storing values that frankly the security and integrity modules can't correctly interpret as evidenced by bugs we reported and fixed in this area. It's not necessarily even their fault it's just that the format we provide to them is sub optimal. - Some filesystems like 9p and cifs need access to the dentry in order to get and set posix acls which is why they either only partially or not even at all implement get and set inode operations. For example, cifs allows setxattr() and getxattr() operations but doesn't allow permission checking based on posix acls because it can't implement a get acl inode operation. Thus, this patch series updates the set acl inode operation to take a dentry instead of an inode argument. However, for the get acl inode operation we can't do this as the old get acl method is called in e.g., generic_permission() and inode_permission(). These helpers in turn are called in various filesystem's permission inode operation. So passing a dentry argument to the old get acl inode operation would amount to passing a dentry to the permission inode operation which we shouldn't and probably can't do. So instead of extending the existing inode operation Christoph suggested to add a new one. He also requested to ensure that the get and set acl inode operation taking a dentry are consistently named. So for this version the old get acl operation is renamed to ->get_inode_acl() and a new ->get_acl() inode operation taking a dentry is added. With this we can give both 9p and cifs get and set acl inode operations and in turn remove their complex custom posix xattr handlers. In the future I hope to get rid of the inode method duplication but it isn't like we have never had this situation. Readdir is just one example. And frankly, the overall gain in type safety and the more pleasant api wise are simply too big of a benefit to not accept this duplication for a while. - We've done a full audit of every codepaths using variant of the current generic xattr api to get and set posix acls and surprisingly it isn't that many places. There's of course always a chance that we might have missed some and if so I'm sure we'll find them soon enough. The crucial codepaths to be converted are obviously stacking filesystems such as ecryptfs and overlayfs. For a list of all callers currently using generic xattr api helpers see [2] including comments whether they support posix acls or not. - The old vfs generic posix acl infrastructure doesn't obey the create and replace semantics promised on the setxattr(2) manpage. This patch series doesn't address this. It really is something we should revisit later though. The patches are roughly organized as follows: (1) Change existing set acl inode operation to take a dentry argument (Intended to be a non-functional change) (2) Rename existing get acl method (Intended to be a non-functional change) (3) Implement get and set acl inode operations for filesystems that couldn't implement one before because of the missing dentry. That's mostly 9p and cifs (Intended to be a non-functional change) (4) Build posix acl api, i.e., add vfs_get_acl(), vfs_remove_acl(), and vfs_set_acl() including security and integrity hooks (Intended to be a non-functional change) (5) Implement get and set acl inode operations for stacking filesystems (Intended to be a non-functional change) (6) Switch posix acl handling in stacking filesystems to new posix acl api now that all filesystems it can stack upon support it. (7) Switch vfs to new posix acl api (semantical change) (8) Remove all now unused helpers (9) Additional regression fixes reported after we merged this into linux-next Thanks to Seth for a lot of good discussion around this and encouragement and input from Christoph" * tag 'fs.acl.rework.v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/idmapping: (36 commits) posix_acl: Fix the type of sentinel in get_acl orangefs: fix mode handling ovl: call posix_acl_release() after error checking evm: remove dead code in evm_inode_set_acl() cifs: check whether acl is valid early acl: make vfs_posix_acl_to_xattr() static acl: remove a slew of now unused helpers 9p: use stub posix acl handlers cifs: use stub posix acl handlers ovl: use stub posix acl handlers ecryptfs: use stub posix acl handlers evm: remove evm_xattr_acl_change() xattr: use posix acl api ovl: use posix acl api ovl: implement set acl method ovl: implement get acl method ecryptfs: implement set acl method ecryptfs: implement get acl method ksmbd: use vfs_remove_acl() acl: add vfs_remove_acl() ...
This commit is contained in:
commit
6a518afcc2
@ -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) {
|
||||
|
@ -3993,7 +3993,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;
|
||||
@ -11296,7 +11296,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,
|
||||
@ -11349,7 +11349,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,
|
||||
@ -11360,7 +11360,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;
|
||||
}
|
||||
|
||||
if (!acl)
|
||||
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 (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 (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 char *cifs_get_link(struct dentry *dentry, struct inode *inode,
|
||||
|
@ -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)
|
||||
|
@ -4194,7 +4194,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,
|
||||
@ -4205,6 +4205,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,
|
||||
|
@ -232,5 +232,26 @@ 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,
|
||||
};
|
||||
|
||||
|
@ -2915,7 +2915,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,6 +1124,10 @@ 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 */
|
||||
|
||||
@ -1125,6 +1138,19 @@ struct inode *orangefs_new_inode(struct super_block *sb, struct inode *dir,
|
||||
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,22 @@ 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);
|
||||
if (mode != inode->i_mode) {
|
||||
struct iattr iattr = {
|
||||
.ia_mode = mode,
|
||||
.ia_valid = ATTR_MODE,
|
||||
};
|
||||
inode->i_mode = mode;
|
||||
__orangefs_setattr(inode, &iattr);
|
||||
__posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
|
||||
}
|
||||
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,
|
||||
|
@ -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);
|
||||
if (IS_ERR(real_acl)) {
|
||||
err = PTR_ERR(real_acl);
|
||||
goto out_drop_write;
|
||||
}
|
||||
posix_acl_release(real_acl);
|
||||
}
|
||||
|
||||
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,
|
||||
|
725
fs/posix_acl.c
725
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,15 +111,17 @@ 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 *sentinel;
|
||||
struct posix_acl **p;
|
||||
struct posix_acl *acl;
|
||||
|
||||
/*
|
||||
* 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,74 @@ 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.
|
||||
*/
|
||||
static 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 +952,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 +966,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 +973,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 +1014,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))
|
||||
|
||||
@ -2169,7 +2169,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);
|
||||
|
||||
@ -2199,7 +2199,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
|
||||
|
@ -69,21 +69,21 @@ extern int __posix_acl_create(struct posix_acl **, gfp_t, umode_t *);
|
||||
extern int __posix_acl_chmod(struct posix_acl **, gfp_t, umode_t);
|
||||
|
||||
extern struct posix_acl *get_posix_acl(struct inode *, int);
|
||||
extern int set_posix_acl(struct user_namespace *, struct inode *, int,
|
||||
struct posix_acl *);
|
||||
int set_posix_acl(struct user_namespace *, struct dentry *, int,
|
||||
struct posix_acl *);
|
||||
|
||||
struct posix_acl *get_cached_acl_rcu(struct inode *inode, int type);
|
||||
struct posix_acl *posix_acl_clone(const struct posix_acl *acl, gfp_t flags);
|
||||
|
||||
#ifdef CONFIG_FS_POSIX_ACL
|
||||
int posix_acl_chmod(struct user_namespace *, struct inode *, umode_t);
|
||||
int posix_acl_chmod(struct user_namespace *, struct dentry *, umode_t);
|
||||
extern int posix_acl_create(struct inode *, umode_t *, struct posix_acl **,
|
||||
struct posix_acl **);
|
||||
int posix_acl_update_mode(struct user_namespace *, struct inode *, umode_t *,
|
||||
struct posix_acl **);
|
||||
|
||||
extern int simple_set_acl(struct user_namespace *, struct inode *,
|
||||
struct posix_acl *, int);
|
||||
int simple_set_acl(struct user_namespace *, struct dentry *,
|
||||
struct posix_acl *, int);
|
||||
extern int simple_acl_create(struct inode *, struct inode *);
|
||||
|
||||
struct posix_acl *get_cached_acl(struct inode *inode, int type);
|
||||
@ -99,9 +99,16 @@ static inline void cache_no_acl(struct inode *inode)
|
||||
inode->i_acl = NULL;
|
||||
inode->i_default_acl = NULL;
|
||||
}
|
||||
|
||||
int vfs_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
|
||||
const char *acl_name, struct posix_acl *kacl);
|
||||
struct posix_acl *vfs_get_acl(struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry, const char *acl_name);
|
||||
int vfs_remove_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
|
||||
const char *acl_name);
|
||||
#else
|
||||
static inline int posix_acl_chmod(struct user_namespace *mnt_userns,
|
||||
struct inode *inode, umode_t mode)
|
||||
struct dentry *dentry, umode_t mode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -126,8 +133,28 @@ static inline int posix_acl_create(struct inode *inode, umode_t *mode,
|
||||
static inline void forget_all_cached_acls(struct inode *inode)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int vfs_set_acl(struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry, const char *name,
|
||||
struct posix_acl *acl)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline struct posix_acl *vfs_get_acl(struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry,
|
||||
const char *acl_name)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline int vfs_remove_acl(struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry, const char *acl_name)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif /* CONFIG_FS_POSIX_ACL */
|
||||
|
||||
struct posix_acl *get_acl(struct inode *inode, int type);
|
||||
struct posix_acl *get_inode_acl(struct inode *inode, int type);
|
||||
|
||||
#endif /* __LINUX_POSIX_ACL_H */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user