Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Richacl #109

Closed
wants to merge 27 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d5d1fb4
vfs: Indicate that the permission functions take all the MAY_* flags
Oct 18, 2011
0f69c40
vfs: Add hex format for MAY_* flag values
kvaneesh Oct 18, 2011
bf56180
vfs: Pass all mask flags down to iop->check_acl
Oct 18, 2011
518cbba
vfs: Add a comment to inode_permission()
Oct 18, 2011
89e1033
vfs: Add generic IS_ACL() test for acl support
Oct 18, 2011
45481f1
vfs: Add IS_RICHACL() test for richacl support
Oct 18, 2011
c684918
vfs: Optimize out IS_RICHACL() if CONFIG_FS_RICHACL is not defined
Oct 18, 2011
004723e
vfs: Add new file and directory create permission flags
Oct 18, 2011
1654a09
vfs: Add delete child and delete self permission flags
Oct 18, 2011
3437a82
vfs: Make the inode passed to inode_change_ok non-const
Oct 18, 2011
e963a4c
vfs: Add permission flags for setting file attributes
Oct 18, 2011
26dc449
vfs: Make acl_permission_check() work for richacls
Oct 18, 2011
e210ab8
richacl: In-memory representation and helper functions
Oct 18, 2011
36ee026
richacl: Permission mapping functions
Oct 18, 2011
dc240c0
richacl: Compute maximum file masks from an acl
Oct 18, 2011
6be646b
richacl: Update the file masks in chmod()
Oct 18, 2011
61bf134
richacl: Permission check algorithm
Oct 18, 2011
9d9bef3
richacl: Create-time inheritance
Oct 18, 2011
8013f16
richacl: Check if an acl is equivalent to a file mode
Oct 18, 2011
5882a81
richacl: Automatic Inheritance
Oct 18, 2011
862d861
richacl: xattr mapping functions
Oct 18, 2011
69d9df5
vfs: Cache richacl in struct inode
Oct 18, 2011
e86e410
vfs: Add richacl permission check
kvaneesh Oct 18, 2011
434e398
ext4: Use IS_POSIXACL() to check for POSIX ACL support
kvaneesh Oct 18, 2011
69b47fd
ext4: Implement rich acl for ext4
kvaneesh Oct 18, 2011
e17ad31
ext4: Add Ext4 compat richacl feature flag
kvaneesh Oct 18, 2011
13fc237
ext4: Add temporary richacl mount option for ext4
kvaneesh Oct 18, 2011
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions fs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ endif # BLOCK
config FS_POSIX_ACL
def_bool n

config FS_RICHACL
def_bool n

config EXPORTFS
tristate

Expand Down
2 changes: 2 additions & 0 deletions fs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ obj-$(CONFIG_NFS_COMMON) += nfs_common/
obj-$(CONFIG_GENERIC_ACL) += generic_acl.o

obj-$(CONFIG_FHANDLE) += fhandle.o
obj-$(CONFIG_FS_RICHACL) += richacl.o
richacl-y := richacl_base.o richacl_inode.o richacl_xattr.o

obj-y += quota/

Expand Down
74 changes: 62 additions & 12 deletions fs/attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,57 @@
#include <linux/fsnotify.h>
#include <linux/fcntl.h>
#include <linux/security.h>
#include <linux/richacl.h>

static int richacl_change_ok(struct inode *inode, int mask)
{
if (!IS_RICHACL(inode))
return -EPERM;

if (inode->i_op->permission)
return inode->i_op->permission(inode, mask);
if (inode->i_op->get_richacl)
return check_richacl(inode, mask);
return -EPERM;
}

static bool inode_uid_change_ok(struct inode *inode, uid_t ia_uid)
{
if (current_fsuid() == inode->i_uid && ia_uid == inode->i_uid)
return true;
if (current_fsuid() == ia_uid &&
richacl_change_ok(inode, MAY_TAKE_OWNERSHIP) == 0)
return true;
if (capable(CAP_CHOWN))
return true;
return false;
}

static bool inode_gid_change_ok(struct inode *inode, gid_t ia_gid)
{
int in_group = in_group_p(ia_gid);
if (current_fsuid() == inode->i_uid &&
(in_group || ia_gid == inode->i_gid))
return true;
if (in_group && richacl_change_ok(inode, MAY_TAKE_OWNERSHIP) == 0)
return true;
if (capable(CAP_CHOWN))
return true;
return false;
}

static bool inode_owner_permitted_or_capable(struct inode *inode, int mask)
{
struct user_namespace *ns = inode_userns(inode);

if (current_user_ns() == ns && current_fsuid() == inode->i_uid)
return true;
if (richacl_change_ok(inode, mask) == 0)
return true;
if (ns_capable(ns, CAP_FOWNER))
return true;
return false;
}

/**
* inode_change_ok - check if attribute changes to an inode are allowed
Expand All @@ -26,7 +77,7 @@
* Should be called as the first thing in ->setattr implementations,
* possibly after taking additional locks.
*/
int inode_change_ok(const struct inode *inode, struct iattr *attr)
int inode_change_ok(struct inode *inode, struct iattr *attr)
{
unsigned int ia_valid = attr->ia_valid;

Expand All @@ -45,21 +96,20 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
return 0;

/* Make sure a caller can chown. */
if ((ia_valid & ATTR_UID) &&
(current_fsuid() != inode->i_uid ||
attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN))
return -EPERM;
if (ia_valid & ATTR_UID) {
if (!inode_uid_change_ok(inode, attr->ia_uid))
return -EPERM;
}

/* Make sure caller can chgrp. */
if ((ia_valid & ATTR_GID) &&
(current_fsuid() != inode->i_uid ||
(!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) &&
!capable(CAP_CHOWN))
return -EPERM;
if (ia_valid & ATTR_GID) {
if (!inode_gid_change_ok(inode, attr->ia_gid))
return -EPERM;
}

/* Make sure a caller can chmod. */
if (ia_valid & ATTR_MODE) {
if (!inode_owner_or_capable(inode))
if (!inode_owner_permitted_or_capable(inode, MAY_CHMOD))
return -EPERM;
/* Also check the setgid bit! */
if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
Expand All @@ -69,7 +119,7 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)

/* Check for setting the inode time. */
if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) {
if (!inode_owner_or_capable(inode))
if (!inode_owner_permitted_or_capable(inode, MAY_SET_TIMES))
return -EPERM;
}

Expand Down
15 changes: 15 additions & 0 deletions fs/ext4/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,18 @@ config EXT4_DEBUG

If you select Y here, then you will be able to turn on debugging
with a command such as "echo 1 > /sys/kernel/debug/ext4/mballoc-debug"

config EXT4_FS_RICHACL
bool "Ext4 Rich Access Control Lists (EXPERIMENTAL)"
depends on EXT4_FS_XATTR && EXPERIMENTAL
select FS_RICHACL
help
Rich ACLs are an implementation of NFSv4 ACLs, extended by file masks
to fit into the standard POSIX file permission model. They are
designed to work seamlessly locally as well as across the NFSv4 and
CIFS/SMB2 network file system protocols.

To learn more about Rich ACL, visit
http://acl.bestbits.at/richacl/

If you don't know what Rich ACLs are, say N
1 change: 1 addition & 0 deletions fs/ext4/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o page-io.o \
ext4-$(CONFIG_EXT4_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o
ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o
ext4-$(CONFIG_EXT4_FS_RICHACL) += richacl.o
25 changes: 12 additions & 13 deletions fs/ext4/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,15 +131,14 @@ ext4_acl_to_disk(const struct posix_acl *acl, size_t *size)
*
* inode->i_mutex: don't care
*/
struct posix_acl *
ext4_get_acl(struct inode *inode, int type)
struct posix_acl *ext4_get_posix_acl(struct inode *inode, int type)
{
int name_index;
char *value = NULL;
struct posix_acl *acl;
int retval;

if (!test_opt(inode->i_sb, POSIX_ACL))
if (!IS_POSIXACL(inode))
return NULL;

acl = get_cached_acl(inode, type);
Expand Down Expand Up @@ -248,15 +247,15 @@ ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
int error = 0;

if (!S_ISLNK(inode->i_mode)) {
if (test_opt(dir->i_sb, POSIX_ACL)) {
acl = ext4_get_acl(dir, ACL_TYPE_DEFAULT);
if (IS_POSIXACL(inode)) {
acl = ext4_get_posix_acl(dir, ACL_TYPE_DEFAULT);
if (IS_ERR(acl))
return PTR_ERR(acl);
}
if (!acl)
inode->i_mode &= ~current_umask();
}
if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
if (IS_POSIXACL(inode) && acl) {
if (S_ISDIR(inode->i_mode)) {
error = ext4_set_acl(handle, inode,
ACL_TYPE_DEFAULT, acl);
Expand Down Expand Up @@ -302,9 +301,9 @@ ext4_acl_chmod(struct inode *inode)

if (S_ISLNK(inode->i_mode))
return -EOPNOTSUPP;
if (!test_opt(inode->i_sb, POSIX_ACL))
if (!IS_POSIXACL(inode))
return 0;
acl = ext4_get_acl(inode, ACL_TYPE_ACCESS);
acl = ext4_get_posix_acl(inode, ACL_TYPE_ACCESS);
if (IS_ERR(acl) || !acl)
return PTR_ERR(acl);
error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
Expand Down Expand Up @@ -337,7 +336,7 @@ ext4_xattr_list_acl_access(struct dentry *dentry, char *list, size_t list_len,
{
const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);

if (!test_opt(dentry->d_sb, POSIX_ACL))
if (!IS_POSIXACL(dentry->d_inode))
return 0;
if (list && size <= list_len)
memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
Expand All @@ -350,7 +349,7 @@ ext4_xattr_list_acl_default(struct dentry *dentry, char *list, size_t list_len,
{
const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);

if (!test_opt(dentry->d_sb, POSIX_ACL))
if (!IS_POSIXACL(dentry->d_inode))
return 0;
if (list && size <= list_len)
memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
Expand All @@ -366,10 +365,10 @@ ext4_xattr_get_acl(struct dentry *dentry, const char *name, void *buffer,

if (strcmp(name, "") != 0)
return -EINVAL;
if (!test_opt(dentry->d_sb, POSIX_ACL))
if (!IS_POSIXACL(dentry->d_inode))
return -EOPNOTSUPP;

acl = ext4_get_acl(dentry->d_inode, type);
acl = ext4_get_posix_acl(dentry->d_inode, type);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (acl == NULL)
Expand All @@ -391,7 +390,7 @@ ext4_xattr_set_acl(struct dentry *dentry, const char *name, const void *value,

if (strcmp(name, "") != 0)
return -EINVAL;
if (!test_opt(inode->i_sb, POSIX_ACL))
if (!IS_POSIXACL(dentry->d_inode))
return -EOPNOTSUPP;
if (!inode_owner_or_capable(inode))
return -EPERM;
Expand Down
4 changes: 2 additions & 2 deletions fs/ext4/acl.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ static inline int ext4_acl_count(size_t size)
#ifdef CONFIG_EXT4_FS_POSIX_ACL

/* acl.c */
struct posix_acl *ext4_get_acl(struct inode *inode, int type);
struct posix_acl *ext4_get_posix_acl(struct inode *inode, int type);
extern int ext4_acl_chmod(struct inode *);
extern int ext4_init_acl(handle_t *, struct inode *, struct inode *);

#else /* CONFIG_EXT4_FS_POSIX_ACL */
#include <linux/sched.h>
#define ext4_get_acl NULL
#define ext4_get_posix_acl NULL

static inline int
ext4_acl_chmod(struct inode *inode)
Expand Down
1 change: 0 additions & 1 deletion fs/ext4/ext4.h
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,6 @@ struct ext4_inode_info {
#define EXT4_MOUNT_UPDATE_JOURNAL 0x01000 /* Update the journal format */
#define EXT4_MOUNT_NO_UID32 0x02000 /* Disable 32-bit UIDs */
#define EXT4_MOUNT_XATTR_USER 0x04000 /* Extended user attributes */
#define EXT4_MOUNT_POSIX_ACL 0x08000 /* POSIX Access Control Lists */
#define EXT4_MOUNT_NO_AUTO_DA_ALLOC 0x10000 /* No auto delalloc mapping */
#define EXT4_MOUNT_BARRIER 0x20000 /* Use block barriers */
#define EXT4_MOUNT_QUOTA 0x80000 /* Some quota option set */
Expand Down
4 changes: 3 additions & 1 deletion fs/ext4/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "ext4_jbd2.h"
#include "xattr.h"
#include "acl.h"
#include "richacl.h"

/*
* Called when an inode is released. Note that this is different
Expand Down Expand Up @@ -301,7 +302,8 @@ const struct inode_operations ext4_file_inode_operations = {
.listxattr = ext4_listxattr,
.removexattr = generic_removexattr,
#endif
.get_acl = ext4_get_acl,
.get_acl = ext4_get_posix_acl,
.get_richacl = ext4_get_richacl,
.fiemap = ext4_fiemap,
};

7 changes: 6 additions & 1 deletion fs/ext4/ialloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "ext4_jbd2.h"
#include "xattr.h"
#include "acl.h"
#include "richacl.h"

#include <trace/events/ext4.h>

Expand Down Expand Up @@ -1039,7 +1040,11 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode,
if (err)
goto fail_drop;

err = ext4_init_acl(handle, inode, dir);
if (EXT4_IS_RICHACL(dir))
err = ext4_init_richacl(handle, inode, dir);
else
err = ext4_init_acl(handle, inode, dir);

if (err)
goto fail_free_drop;

Expand Down
10 changes: 7 additions & 3 deletions fs/ext4/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "acl.h"
#include "ext4_extents.h"
#include "truncate.h"
#include "richacl.h"

#include <trace/events/ext4.h>

Expand Down Expand Up @@ -3945,9 +3946,12 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
if (orphan && inode->i_nlink)
ext4_orphan_del(NULL, inode);

if (!rc && (ia_valid & ATTR_MODE))
rc = ext4_acl_chmod(inode);

if (!rc && (ia_valid & ATTR_MODE)) {
if (EXT4_IS_RICHACL(inode))
rc = ext4_richacl_chmod(inode);
else
rc = ext4_acl_chmod(inode);
}
err_out:
ext4_std_error(inode->i_sb, error);
if (!error)
Expand Down
7 changes: 5 additions & 2 deletions fs/ext4/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

#include "xattr.h"
#include "acl.h"
#include "richacl.h"

#include <trace/events/ext4.h>
/*
Expand Down Expand Up @@ -2586,7 +2587,8 @@ const struct inode_operations ext4_dir_inode_operations = {
.listxattr = ext4_listxattr,
.removexattr = generic_removexattr,
#endif
.get_acl = ext4_get_acl,
.get_acl = ext4_get_posix_acl,
.get_richacl = ext4_get_richacl,
.fiemap = ext4_fiemap,
};

Expand All @@ -2598,5 +2600,6 @@ const struct inode_operations ext4_special_inode_operations = {
.listxattr = ext4_listxattr,
.removexattr = generic_removexattr,
#endif
.get_acl = ext4_get_acl,
.get_acl = ext4_get_posix_acl,
.get_richacl = ext4_get_richacl,
};
Loading