diff -r ab5eb3e7d582 -r cd2e9206a81f fs/Kconfig --- a/fs/Kconfig Sat Mar 20 12:41:12 2010 +0800 +++ b/fs/Kconfig Mon Mar 22 19:57:54 2010 +0800 @@ -133,6 +133,13 @@ If you don't know what Access Control Lists are, say N. +config MQUEUE_POSIX_ACL + bool "Mqueue POSIX Access Control Lists support" + select GENERIC_ACL + help + Mqueue is a file system which is used to suport POSIX msg queue. + Say y to get Access Control Lists support for mqueue file system. + config HUGETLBFS bool "HugeTLB file system support" depends on X86 || IA64 || SPARC64 || (S390 && 64BIT) || \ diff -r ab5eb3e7d582 -r cd2e9206a81f include/linux/mqueue.h --- a/include/linux/mqueue.h Sat Mar 20 12:41:12 2010 +0800 +++ b/include/linux/mqueue.h Mon Mar 22 19:57:54 2010 +0800 @@ -1,4 +1,5 @@ /* Copyright (C) 2003 Krzysztof Benedyczak & Michal Wronski + Add ACL support by Zhou Peng (ailvpeng25@gmail.com), 2010 This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -50,4 +51,12 @@ #define NOTIFY_COOKIE_LEN 32 +#ifdef CONFIG_MQUEUE_POSIX_ACL +int mqueue_check_acl(struct inode *inode, int mask); +int mqueue_acl_init(struct inode *inode, struct inode *dir); + +extern struct xattr_handler mqueue_xattr_acl_access_handler; +extern struct xattr_handler mqueue_xattr_acl_default_handler; #endif + +#endif diff -r ab5eb3e7d582 -r cd2e9206a81f ipc/Makefile --- a/ipc/Makefile Sat Mar 20 12:41:12 2010 +0800 +++ b/ipc/Makefile Mon Mar 22 19:57:54 2010 +0800 @@ -10,3 +10,4 @@ obj-$(CONFIG_IPC_NS) += namespace.o obj-$(CONFIG_POSIX_MQUEUE_SYSCTL) += mq_sysctl.o +obj-$(CONFIG_MQUEUE_POSIX_ACL) += mqueue_acl.o diff -r ab5eb3e7d582 -r cd2e9206a81f ipc/mqueue.c --- a/ipc/mqueue.c Sat Mar 20 12:41:12 2010 +0800 +++ b/ipc/mqueue.c Mon Mar 22 19:57:54 2010 +0800 @@ -10,6 +10,8 @@ * * Audit: George Wilson (ltcgcw@us.ibm.com) * + * ACL by Zhou Peng (ailvpeng25@gmail.com), 2010 + * * This file is released under the GPL. */ @@ -33,6 +35,8 @@ #include #include #include +#include +#include #include #include "util.h" @@ -77,6 +81,9 @@ static const struct inode_operations mqueue_dir_inode_operations; static const struct file_operations mqueue_file_operations; +#ifdef CONFIG_MQUEUE_POSIX_ACL +static const struct inode_operations mqueue_inode_operations; +#endif static const struct super_operations mqueue_super_ops; static void remove_notification(struct mqueue_inode_info *info); @@ -84,6 +91,53 @@ static struct ctl_table_header * mq_sysctl_table; +#ifdef CONFIG_MQUEUE_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 mqueue_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 mqueue_xattr_security_get(struct inode *inode, const char *name, + void *buffer, size_t size) +{ + if (strcmp(name, "") == 0) + return -EINVAL; + return xattr_getsecurity(inode, name, buffer, size); +} + +static int mqueue_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); +} + +static struct xattr_handler mqueue_xattr_security_handler = { + .prefix = XATTR_SECURITY_PREFIX, + .list = mqueue_xattr_security_list, + .get = mqueue_xattr_security_get, + .set = mqueue_xattr_security_set, +}; + + +static struct xattr_handler *mqueue_xattr_handlers[] = { + &mqueue_xattr_acl_access_handler, + &mqueue_xattr_acl_default_handler, + &mqueue_xattr_security_handler, + NULL +}; +#endif + static inline struct mqueue_inode_info *MQUEUE_I(struct inode *inode) { return container_of(inode, struct mqueue_inode_info, vfs_inode); @@ -121,12 +175,18 @@ inode->i_gid = current_fsgid(); inode->i_mtime = inode->i_ctime = inode->i_atime = CURRENT_TIME; - +#ifdef CONFIG_MQUEUE_POSIX_ACL + cache_no_acl(inode); +#endif + if (S_ISREG(mode)) { struct mqueue_inode_info *info; struct task_struct *p = current; unsigned long mq_bytes, mq_msg_tblsz; +#ifdef CONFIG_MQUEUE_POSIX_ACL + inode->i_op = &mqueue_inode_operations; +#endif inode->i_fop = &mqueue_file_operations; inode->i_size = FILENT_SIZE; /* mqueue specific info */ @@ -195,6 +255,11 @@ sb->s_magic = MQUEUE_MAGIC; sb->s_op = &mqueue_super_ops; +#ifdef CONFIG_MQUEUE_POSIX_ACL + sb->s_xattr = mqueue_xattr_handlers; + sb->s_flags |= MS_POSIXACL; +#endif + inode = mqueue_get_inode(sb, ns, S_IFDIR | S_ISVTX | S_IRWXUGO, NULL); if (!inode) { @@ -316,6 +381,13 @@ goto out_unlock; } +#ifdef CONFIG_MQUEUE_POSIX_ACL + error = mqueue_acl_init(inode, dir); + if (error) { + iput(inode); + goto out_unlock; + } +#endif put_ipc_ns(ipc_ns); dir->i_size += DIRENT_SIZE; dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME; @@ -1216,6 +1288,23 @@ .lookup = simple_lookup, .create = mqueue_create, .unlink = mqueue_unlink, +#ifdef CONFIG_MQUEUE_POSIX_ACL + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = generic_listxattr, + .removexattr = generic_removexattr, + .check_acl = mqueue_check_acl, +#endif +}; + +static const struct inode_operations mqueue_inode_operations = { +#ifdef CONFIG_MQUEUE_POSIX_ACL + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = generic_listxattr, + .removexattr = generic_removexattr, + .check_acl = mqueue_check_acl, +#endif }; static const struct file_operations mqueue_file_operations = { diff -r ab5eb3e7d582 -r cd2e9206a81f ipc/mqueue_acl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ipc/mqueue_acl.c Mon Mar 22 19:57:54 2010 +0800 @@ -0,0 +1,172 @@ +/* + * ipc/mqueue_acl.c + * + * Copyright (C) 2010 ZhouPeng + * + * This file is released under the GPL. + */ + +#include +#include +#include +#include + +/** + * mqueue_get_acl - generic_acl_operations->getacl() operation + */ +static struct posix_acl * +mqueue_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(inode->i_acl); + break; + + case ACL_TYPE_DEFAULT: + acl = posix_acl_dup(inode->i_default_acl); + break; + } + spin_unlock(&inode->i_lock); + + return acl; +} + +/** + * mqueue_set_acl - generic_acl_operations->setacl() operation + */ +static void +mqueue_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 = inode->i_acl; + inode->i_acl = posix_acl_dup(acl); + break; + + case ACL_TYPE_DEFAULT: + free = inode->i_default_acl; + inode->i_default_acl = posix_acl_dup(acl); + break; + } + spin_unlock(&inode->i_lock); + posix_acl_release(free); +} + +struct generic_acl_operations mqueue_acl_ops = { + .getacl = mqueue_get_acl, + .setacl = mqueue_set_acl, +}; + +/** + * mqueue_list_acl_access, mqueue_get_acl_access, mqueue_set_acl_access, + * mqueue_xattr_acl_access_handler - plumbing code to implement the + * system.posix_acl_access xattr using the generic acl functions. + */ + +static size_t +mqueue_list_acl_access(struct inode *inode, char *list, size_t list_size, + const char *name, size_t name_len) +{ + return generic_acl_list(inode, &mqueue_acl_ops, ACL_TYPE_ACCESS, + list, list_size); +} + +static int +mqueue_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, &mqueue_acl_ops, ACL_TYPE_ACCESS, buffer, + size); +} + +static int +mqueue_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, &mqueue_acl_ops, ACL_TYPE_ACCESS, value, + size); +} + +struct xattr_handler mqueue_xattr_acl_access_handler = { + .prefix = POSIX_ACL_XATTR_ACCESS, + .list = mqueue_list_acl_access, + .get = mqueue_get_acl_access, + .set = mqueue_set_acl_access, +}; + +/** + * mqueue_list_acl_default, mqueue_get_acl_default, mqueue_set_acl_default, + * mqueue_xattr_acl_default_handler - plumbing code to implement the + * system.posix_acl_default xattr using the generic acl functions. + */ + +static size_t +mqueue_list_acl_default(struct inode *inode, char *list, size_t list_size, + const char *name, size_t name_len) +{ + return generic_acl_list(inode, &mqueue_acl_ops, ACL_TYPE_DEFAULT, + list, list_size); +} + +static int +mqueue_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, &mqueue_acl_ops, ACL_TYPE_DEFAULT, buffer, + size); +} + +static int +mqueue_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, &mqueue_acl_ops, ACL_TYPE_DEFAULT, value, + size); +} + +struct xattr_handler mqueue_xattr_acl_default_handler = { + .prefix = POSIX_ACL_XATTR_DEFAULT, + .list = mqueue_list_acl_default, + .get = mqueue_get_acl_default, + .set = mqueue_set_acl_default, +}; + +/** + * mqueue_acl_init - Inizialize the acl(s) of a new inode + */ +int +mqueue_acl_init(struct inode *inode, struct inode *dir) +{ + return generic_acl_init(inode, dir, &mqueue_acl_ops); +} + +/** + * mqueue_check_acl - check_acl() callback for generic_permission() + */ +int +mqueue_check_acl(struct inode *inode, int mask) +{ + struct posix_acl *acl = mqueue_get_acl(inode, ACL_TYPE_ACCESS); + + if (acl) { + int error = posix_acl_permission(inode, acl, mask); + posix_acl_release(acl); + return error; + } + return -EAGAIN; +}