提交 39f0247d 编写于 作者: A Andreas Gruenbacher 提交者: Linus Torvalds

[PATCH] Access Control Lists for tmpfs

Add access control lists for tmpfs.
Signed-off-by: NAndreas Gruenbacher <agruen@suse.de>
Cc: Hugh Dickins <hugh@veritas.com>
Signed-off-by: NAndrew Morton <akpm@osdl.org>
Signed-off-by: NLinus Torvalds <torvalds@osdl.org>
上级 f0c8bd16
master alk-4.19.24 alk-4.19.30 alk-4.19.34 alk-4.19.36 alk-4.19.43 alk-4.19.48 alk-4.19.57 ck-4.19.67 ck-4.19.81 ck-4.19.91 github/fork/deepanshu1422/fix-typo-in-comment github/fork/haosdent/fix-typo linux-next v4.19.91 v4.19.90 v4.19.89 v4.19.88 v4.19.87 v4.19.86 v4.19.85 v4.19.84 v4.19.83 v4.19.82 v4.19.81 v4.19.80 v4.19.79 v4.19.78 v4.19.77 v4.19.76 v4.19.75 v4.19.74 v4.19.73 v4.19.72 v4.19.71 v4.19.70 v4.19.69 v4.19.68 v4.19.67 v4.19.66 v4.19.65 v4.19.64 v4.19.63 v4.19.62 v4.19.61 v4.19.60 v4.19.59 v4.19.58 v4.19.57 v4.19.56 v4.19.55 v4.19.54 v4.19.53 v4.19.52 v4.19.51 v4.19.50 v4.19.49 v4.19.48 v4.19.47 v4.19.46 v4.19.45 v4.19.44 v4.19.43 v4.19.42 v4.19.41 v4.19.40 v4.19.39 v4.19.38 v4.19.37 v4.19.36 v4.19.35 v4.19.34 v4.19.33 v4.19.32 v4.19.31 v4.19.30 v4.19.29 v4.19.28 v4.19.27 v4.19.26 v4.19.25 v4.19.24 v4.19.23 v4.19.22 v4.19.21 v4.19.20 v4.19.19 v4.19.18 v4.19.17 v4.19.16 v4.19.15 v4.19.14 v4.19.13 v4.19.12 v4.19.11 v4.19.10 v4.19.9 v4.19.8 v4.19.7 v4.19.6 v4.19.5 v4.19.4 v4.19.3 v4.19.2 v4.19.1 v4.19 v4.19-rc8 v4.19-rc7 v4.19-rc6 v4.19-rc5 v4.19-rc4 v4.19-rc3 v4.19-rc2 v4.19-rc1 ck-release-21 ck-release-20 ck-release-19.2 ck-release-19.1 ck-release-19 ck-release-18 ck-release-17.2 ck-release-17.1 ck-release-17 ck-release-16 ck-release-15.1 ck-release-15 ck-release-14 ck-release-13.2 ck-release-13 ck-release-12 ck-release-11 ck-release-10 ck-release-9 ck-release-7 alk-release-15 alk-release-14 alk-release-13.2 alk-release-13 alk-release-12 alk-release-11 alk-release-10 alk-release-9 alk-release-7
无相关合并请求
......@@ -881,6 +881,19 @@ config TMPFS
See <file:Documentation/filesystems/tmpfs.txt> for details.
config TMPFS_POSIX_ACL
bool "Tmpfs POSIX Access Control Lists"
depends on TMPFS
select GENERIC_ACL
help
POSIX Access Control Lists (ACLs) support permissions for users and
groups beyond the owner/group/world scheme.
To learn more about Access Control Lists, visit the POSIX ACLs for
Linux website <http://acl.bestbits.at/>.
If you don't know what Access Control Lists are, say N.
config HUGETLBFS
bool "HugeTLB file system support"
depends X86 || IA64 || PPC64 || SPARC64 || SUPERH || BROKEN
......
......@@ -19,6 +19,10 @@ struct shmem_inode_info {
swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* first blocks */
struct list_head swaplist; /* chain of maybes on swap */
struct inode vfs_inode;
#ifdef CONFIG_TMPFS_POSIX_ACL
struct posix_acl *i_acl;
struct posix_acl *i_default_acl;
#endif
};
struct shmem_sb_info {
......@@ -36,4 +40,24 @@ static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
return container_of(inode, struct shmem_inode_info, vfs_inode);
}
#ifdef CONFIG_TMPFS_POSIX_ACL
int shmem_permission(struct inode *, int, struct nameidata *);
int shmem_acl_init(struct inode *, struct inode *);
void shmem_acl_destroy_inode(struct inode *);
extern struct xattr_handler shmem_xattr_acl_access_handler;
extern struct xattr_handler shmem_xattr_acl_default_handler;
extern struct generic_acl_operations shmem_acl_ops;
#else
static inline int shmem_acl_init(struct inode *inode, struct inode *dir)
{
return 0;
}
static inline void shmem_acl_destroy_inode(struct inode *inode)
{
}
#endif /* CONFIG_TMPFS_POSIX_ACL */
#endif
......@@ -17,6 +17,7 @@ obj-$(CONFIG_HUGETLBFS) += hugetlb.o
obj-$(CONFIG_NUMA) += mempolicy.o
obj-$(CONFIG_SPARSEMEM) += sparse.o
obj-$(CONFIG_SHMEM) += shmem.o
obj-$(CONFIG_TMPFS_POSIX_ACL) += shmem_acl.o
obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
obj-$(CONFIG_SLOB) += slob.o
obj-$(CONFIG_SLAB) += slab.o
......
......@@ -26,6 +26,8 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/xattr.h>
#include <linux/generic_acl.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/file.h>
......@@ -177,6 +179,7 @@ static const struct address_space_operations shmem_aops;
static struct file_operations shmem_file_operations;
static struct inode_operations shmem_inode_operations;
static struct inode_operations shmem_dir_inode_operations;
static struct inode_operations shmem_special_inode_operations;
static struct vm_operations_struct shmem_vm_ops;
static struct backing_dev_info shmem_backing_dev_info __read_mostly = {
......@@ -637,7 +640,7 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
struct page *page = NULL;
int error;
if (attr->ia_valid & ATTR_SIZE) {
if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) {
if (attr->ia_size < inode->i_size) {
/*
* If truncating down to a partial page, then
......@@ -670,6 +673,10 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
error = inode_change_ok(inode, attr);
if (!error)
error = inode_setattr(inode, attr);
#ifdef CONFIG_TMPFS_POSIX_ACL
if (!error && (attr->ia_valid & ATTR_MODE))
error = generic_acl_chmod(inode, &shmem_acl_ops);
#endif
if (page)
page_cache_release(page);
return error;
......@@ -1362,6 +1369,7 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
switch (mode & S_IFMT) {
default:
inode->i_op = &shmem_special_inode_operations;
init_special_inode(inode, mode, dev);
break;
case S_IFREG:
......@@ -1682,7 +1690,11 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
iput(inode);
return error;
}
error = 0;
}
error = shmem_acl_init(inode, dir);
if (error) {
iput(inode);
return error;
}
if (dir->i_mode & S_ISGID) {
inode->i_gid = dir->i_gid;
......@@ -1897,6 +1909,53 @@ static struct inode_operations shmem_symlink_inode_operations = {
.put_link = shmem_put_link,
};
#ifdef CONFIG_TMPFS_POSIX_ACL
/**
* Superblocks without xattr inode operations will get security.* xattr
* support from the VFS "for free". As soon as we have any other xattrs
* like ACLs, we also need to implement the security.* handlers at
* filesystem level, though.
*/
static size_t shmem_xattr_security_list(struct inode *inode, char *list,
size_t list_len, const char *name,
size_t name_len)
{
return security_inode_listsecurity(inode, list, list_len);
}
static int shmem_xattr_security_get(struct inode *inode, const char *name,
void *buffer, size_t size)
{
if (strcmp(name, "") == 0)
return -EINVAL;
return security_inode_getsecurity(inode, name, buffer, size,
-EOPNOTSUPP);
}
static int shmem_xattr_security_set(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
if (strcmp(name, "") == 0)
return -EINVAL;
return security_inode_setsecurity(inode, name, value, size, flags);
}
struct xattr_handler shmem_xattr_security_handler = {
.prefix = XATTR_SECURITY_PREFIX,
.list = shmem_xattr_security_list,
.get = shmem_xattr_security_get,
.set = shmem_xattr_security_set,
};
static struct xattr_handler *shmem_xattr_handlers[] = {
&shmem_xattr_acl_access_handler,
&shmem_xattr_acl_default_handler,
&shmem_xattr_security_handler,
NULL
};
#endif
static int shmem_parse_options(char *options, int *mode, uid_t *uid,
gid_t *gid, unsigned long *blocks, unsigned long *inodes,
int *policy, nodemask_t *policy_nodes)
......@@ -2094,6 +2153,10 @@ static int shmem_fill_super(struct super_block *sb,
sb->s_magic = TMPFS_MAGIC;
sb->s_op = &shmem_ops;
sb->s_time_gran = 1;
#ifdef CONFIG_TMPFS_POSIX_ACL
sb->s_xattr = shmem_xattr_handlers;
sb->s_flags |= MS_POSIXACL;
#endif
inode = shmem_get_inode(sb, S_IFDIR | mode, 0);
if (!inode)
......@@ -2130,6 +2193,7 @@ static void shmem_destroy_inode(struct inode *inode)
/* only struct inode is valid if it's an inline symlink */
mpol_free_shared_policy(&SHMEM_I(inode)->policy);
}
shmem_acl_destroy_inode(inode);
kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode));
}
......@@ -2141,6 +2205,10 @@ static void init_once(void *foo, struct kmem_cache *cachep,
if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
SLAB_CTOR_CONSTRUCTOR) {
inode_init_once(&p->vfs_inode);
#ifdef CONFIG_TMPFS_POSIX_ACL
p->i_acl = NULL;
p->i_default_acl = NULL;
#endif
}
}
......@@ -2184,6 +2252,14 @@ static struct inode_operations shmem_inode_operations = {
.truncate = shmem_truncate,
.setattr = shmem_notify_change,
.truncate_range = shmem_truncate_range,
#ifdef CONFIG_TMPFS_POSIX_ACL
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
.listxattr = generic_listxattr,
.removexattr = generic_removexattr,
.permission = shmem_permission,
#endif
};
static struct inode_operations shmem_dir_inode_operations = {
......@@ -2198,6 +2274,25 @@ static struct inode_operations shmem_dir_inode_operations = {
.mknod = shmem_mknod,
.rename = shmem_rename,
#endif
#ifdef CONFIG_TMPFS_POSIX_ACL
.setattr = shmem_notify_change,
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
.listxattr = generic_listxattr,
.removexattr = generic_removexattr,
.permission = shmem_permission,
#endif
};
static struct inode_operations shmem_special_inode_operations = {
#ifdef CONFIG_TMPFS_POSIX_ACL
.setattr = shmem_notify_change,
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
.listxattr = generic_listxattr,
.removexattr = generic_removexattr,
.permission = shmem_permission,
#endif
};
static struct super_operations shmem_ops = {
......
/*
* mm/shmem_acl.c
*
* (C) 2005 Andreas Gruenbacher <agruen@suse.de>
*
* This file is released under the GPL.
*/
#include <linux/fs.h>
#include <linux/shmem_fs.h>
#include <linux/xattr.h>
#include <linux/generic_acl.h>
/**
* shmem_get_acl - generic_acl_operations->getacl() operation
*/
static struct posix_acl *
shmem_get_acl(struct inode *inode, int type)
{
struct posix_acl *acl = NULL;
spin_lock(&inode->i_lock);
switch(type) {
case ACL_TYPE_ACCESS:
acl = posix_acl_dup(SHMEM_I(inode)->i_acl);
break;
case ACL_TYPE_DEFAULT:
acl = posix_acl_dup(SHMEM_I(inode)->i_default_acl);
break;
}
spin_unlock(&inode->i_lock);
return acl;
}
/**
* shmem_get_acl - generic_acl_operations->setacl() operation
*/
static void
shmem_set_acl(struct inode *inode, int type, struct posix_acl *acl)
{
struct posix_acl *free = NULL;
spin_lock(&inode->i_lock);
switch(type) {
case ACL_TYPE_ACCESS:
free = SHMEM_I(inode)->i_acl;
SHMEM_I(inode)->i_acl = posix_acl_dup(acl);
break;
case ACL_TYPE_DEFAULT:
free = SHMEM_I(inode)->i_default_acl;
SHMEM_I(inode)->i_default_acl = posix_acl_dup(acl);
break;
}
spin_unlock(&inode->i_lock);
posix_acl_release(free);
}
struct generic_acl_operations shmem_acl_ops = {
.getacl = shmem_get_acl,
.setacl = shmem_set_acl,
};
/**
* shmem_list_acl_access, shmem_get_acl_access, shmem_set_acl_access,
* shmem_xattr_acl_access_handler - plumbing code to implement the
* system.posix_acl_access xattr using the generic acl functions.
*/
static size_t
shmem_list_acl_access(struct inode *inode, char *list, size_t list_size,
const char *name, size_t name_len)
{
return generic_acl_list(inode, &shmem_acl_ops, ACL_TYPE_ACCESS,
list, list_size);
}
static int
shmem_get_acl_access(struct inode *inode, const char *name, void *buffer,
size_t size)
{
if (strcmp(name, "") != 0)
return -EINVAL;
return generic_acl_get(inode, &shmem_acl_ops, ACL_TYPE_ACCESS, buffer,
size);
}
static int
shmem_set_acl_access(struct inode *inode, const char *name, const void *value,
size_t size, int flags)
{
if (strcmp(name, "") != 0)
return -EINVAL;
return generic_acl_set(inode, &shmem_acl_ops, ACL_TYPE_ACCESS, value,
size);
}
struct xattr_handler shmem_xattr_acl_access_handler = {
.prefix = POSIX_ACL_XATTR_ACCESS,
.list = shmem_list_acl_access,
.get = shmem_get_acl_access,
.set = shmem_set_acl_access,
};
/**
* shmem_list_acl_default, shmem_get_acl_default, shmem_set_acl_default,
* shmem_xattr_acl_default_handler - plumbing code to implement the
* system.posix_acl_default xattr using the generic acl functions.
*/
static size_t
shmem_list_acl_default(struct inode *inode, char *list, size_t list_size,
const char *name, size_t name_len)
{
return generic_acl_list(inode, &shmem_acl_ops, ACL_TYPE_DEFAULT,
list, list_size);
}
static int
shmem_get_acl_default(struct inode *inode, const char *name, void *buffer,
size_t size)
{
if (strcmp(name, "") != 0)
return -EINVAL;
return generic_acl_get(inode, &shmem_acl_ops, ACL_TYPE_DEFAULT, buffer,
size);
}
static int
shmem_set_acl_default(struct inode *inode, const char *name, const void *value,
size_t size, int flags)
{
if (strcmp(name, "") != 0)
return -EINVAL;
return generic_acl_set(inode, &shmem_acl_ops, ACL_TYPE_DEFAULT, value,
size);
}
struct xattr_handler shmem_xattr_acl_default_handler = {
.prefix = POSIX_ACL_XATTR_DEFAULT,
.list = shmem_list_acl_default,
.get = shmem_get_acl_default,
.set = shmem_set_acl_default,
};
/**
* shmem_acl_init - Inizialize the acl(s) of a new inode
*/
int
shmem_acl_init(struct inode *inode, struct inode *dir)
{
return generic_acl_init(inode, dir, &shmem_acl_ops);
}
/**
* shmem_acl_destroy_inode - destroy acls hanging off the in-memory inode
*
* This is done before destroying the actual inode.
*/
void
shmem_acl_destroy_inode(struct inode *inode)
{
if (SHMEM_I(inode)->i_acl)
posix_acl_release(SHMEM_I(inode)->i_acl);
SHMEM_I(inode)->i_acl = NULL;
if (SHMEM_I(inode)->i_default_acl)
posix_acl_release(SHMEM_I(inode)->i_default_acl);
SHMEM_I(inode)->i_default_acl = NULL;
}
/**
* shmem_check_acl - check_acl() callback for generic_permission()
*/
static int
shmem_check_acl(struct inode *inode, int mask)
{
struct posix_acl *acl = shmem_get_acl(inode, ACL_TYPE_ACCESS);
if (acl) {
int error = posix_acl_permission(inode, acl, mask);
posix_acl_release(acl);
return error;
}
return -EAGAIN;
}
/**
* shmem_permission - permission() inode operation
*/
int
shmem_permission(struct inode *inode, int mask, struct nameidata *nd)
{
return generic_permission(inode, mask, shmem_check_acl);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
反馈
建议
客服 返回
顶部