From: Eric Paris <eparis@redhat.com>
To: linux-kernel@vger.kernel.org, linux-mm@kvack.org
Cc: hughd@google.com
Subject: [PATCH] tmpfs: implement security.capability xattrs
Date: Tue, 11 Jan 2011 16:07:10 -0500 [thread overview]
Message-ID: <20110111210710.32348.1642.stgit@paris.rdu.redhat.com> (raw)
This patch implements security.capability xattrs for tmpfs filesystems. The
feodra project, while trying to replace suid apps with file capabilities,
realized that tmpfs, which is used on my build systems, does not support file
capabilities and thus cannot be used to build packages which use file
capabilities. The patch only implements security.capability but there is no
reason it could not be easily expanded to support *.* xattrs as most of the
work is already done. I don't know what other xattrs are in use in the world
or if they necessarily make sense on tmpfs so I didn't make this
implementation completely generic.
The basic implementation is that I attach a
struct shmem_xattr {
struct list_head list; /* anchored by shmem_inode_info->xattr_list */
char *name;
size_t size;
char value[0];
};
Into the struct shmem_inode_info for each xattr that is set. Since I only
allow security.capability obviously this list is only every 0 or 1 entry long.
I could have been a little simpler, but then the next person having to
implement an xattr would have to redo everything I did instead of me just
doing 90% of their work :)
Signed-off-by: Eric Paris <eparis@redhat.com>
---
include/linux/shmem_fs.h | 8 +++
mm/shmem.c | 112 ++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 116 insertions(+), 4 deletions(-)
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index 399be5a..6f2ebb8 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -9,6 +9,13 @@
#define SHMEM_NR_DIRECT 16
+struct shmem_xattr {
+ struct list_head list; /* anchored by shmem_inode_info->xattr_list */
+ char *name;
+ size_t size;
+ char value[0];
+};
+
struct shmem_inode_info {
spinlock_t lock;
unsigned long flags;
@@ -19,6 +26,7 @@ struct shmem_inode_info {
struct page *i_indirect; /* top indirect blocks page */
swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* first blocks */
struct list_head swaplist; /* chain of maybes on swap */
+ struct list_head xattr_list; /* list of shmem_xattr */
struct inode vfs_inode;
};
diff --git a/mm/shmem.c b/mm/shmem.c
index 86cd21d..d2bacd6 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -822,6 +822,7 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
static void shmem_evict_inode(struct inode *inode)
{
struct shmem_inode_info *info = SHMEM_I(inode);
+ struct shmem_xattr *xattr, *nxattr;
if (inode->i_mapping->a_ops == &shmem_aops) {
truncate_inode_pages(inode->i_mapping, 0);
@@ -834,6 +835,9 @@ static void shmem_evict_inode(struct inode *inode)
mutex_unlock(&shmem_swaplist_mutex);
}
}
+
+ list_for_each_entry_safe(xattr, nxattr, &info->xattr_list, list)
+ kfree(xattr);
BUG_ON(inode->i_blocks);
shmem_free_inode(inode->i_sb);
end_writeback(inode);
@@ -1597,6 +1601,7 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
spin_lock_init(&info->lock);
info->flags = flags & VM_NORESERVE;
INIT_LIST_HEAD(&info->swaplist);
+ INIT_LIST_HEAD(&info->xattr_list);
cache_no_acl(inode);
switch (mode & S_IFMT) {
@@ -2071,24 +2076,123 @@ static size_t shmem_xattr_security_list(struct dentry *dentry, char *list,
size_t list_len, const char *name,
size_t name_len, int handler_flags)
{
- return security_inode_listsecurity(dentry->d_inode, list, list_len);
+ struct shmem_xattr *xattr;
+ struct shmem_inode_info *shmem_i;
+ size_t used;
+ char *buf = NULL;
+
+ used = security_inode_listsecurity(dentry->d_inode, list, list_len);
+
+ shmem_i = SHMEM_I(dentry->d_inode);
+ if (list)
+ buf = list + used;
+
+ spin_lock(&dentry->d_inode->i_lock);
+ list_for_each_entry(xattr, &shmem_i->xattr_list, list) {
+ size_t len = XATTR_SECURITY_PREFIX_LEN;
+ len += strlen(xattr->name) + 1;
+ if (list_len - (used + len) >= 0 && buf) {
+ strncpy(buf, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN);
+ buf += XATTR_SECURITY_PREFIX_LEN;
+ strncpy(buf, xattr->name, strlen(xattr->name) + 1);
+ buf += strlen(xattr->name) + 1;
+ }
+ used += len;
+ }
+ spin_unlock(&dentry->d_inode->i_lock);
+
+ return used;
}
static int shmem_xattr_security_get(struct dentry *dentry, const char *name,
void *buffer, size_t size, int handler_flags)
{
+ struct shmem_inode_info *shmem_i;
+ struct shmem_xattr *xattr;
+ int ret;
+
if (strcmp(name, "") == 0)
return -EINVAL;
- return xattr_getsecurity(dentry->d_inode, name, buffer, size);
+
+ ret = xattr_getsecurity(dentry->d_inode, name, buffer, size);
+ if (ret != -EOPNOTSUPP)
+ return ret;
+
+ /* if we make this generic this needs to go... */
+ if (strcmp(name, XATTR_CAPS_SUFFIX))
+ return -EOPNOTSUPP;
+
+ ret = -ENODATA;
+ shmem_i = SHMEM_I(dentry->d_inode);
+
+ spin_lock(&dentry->d_inode->i_lock);
+ list_for_each_entry(xattr, &shmem_i->xattr_list, list) {
+ if (!strcmp(name, xattr->name)) {
+ ret = xattr->size;
+ if (buffer) {
+ if (size < xattr->size)
+ ret = -ERANGE;
+ else
+ memcpy(buffer, xattr->value, xattr->size);
+ }
+ break;
+ }
+ }
+ spin_unlock(&dentry->d_inode->i_lock);
+ return ret;
}
static int shmem_xattr_security_set(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags, int handler_flags)
{
+ int ret;
+ struct inode *inode = dentry->d_inode;
+ struct shmem_inode_info *shmem_i = SHMEM_I(inode);
+ struct shmem_xattr *xattr;
+ struct shmem_xattr *new_xattr;
+ size_t len;
+
if (strcmp(name, "") == 0)
return -EINVAL;
- return security_inode_setsecurity(dentry->d_inode, name, value,
- size, flags);
+ ret = security_inode_setsecurity(inode, name, value, size, flags);
+ if (ret != -EOPNOTSUPP)
+ return ret;
+
+ /*
+ * We only store fcaps for now, but this could be a lot more generic.
+ * We could hold the prefix as well as the suffix in the xattr struct
+ * We would also need to hold a copy of the suffix rather than a
+ * pointer to XATTR_CAPS_SUFFIX
+ */
+ if (strcmp(name, XATTR_CAPS_SUFFIX))
+ return -EOPNOTSUPP;
+
+ /* wrap around? */
+ len = sizeof(*new_xattr) + size;
+ if (len <= sizeof(*new_xattr))
+ return -ENOMEM;
+
+ new_xattr = kmalloc(GFP_NOFS, len);
+ if (!new_xattr)
+ return -ENOMEM;
+
+ new_xattr->name = XATTR_CAPS_SUFFIX;
+ new_xattr->size = size;
+ memcpy(new_xattr->value, value, size);
+
+ spin_lock(&inode->i_lock);
+ list_for_each_entry(xattr, &shmem_i->xattr_list, list) {
+ if (!strcmp(name, xattr->name)) {
+ list_replace(&xattr->list, &new_xattr->list);
+ goto out;
+ }
+ }
+ list_add(&new_xattr->list, &shmem_i->xattr_list);
+ xattr = NULL;
+out:
+ spin_unlock(&inode->i_lock);
+ kfree(xattr);
+ return 0;
}
static const struct xattr_handler shmem_xattr_security_handler = {
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom policy in Canada: sign http://dissolvethecrtc.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
next reply other threads:[~2011-01-11 21:13 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-01-11 21:07 Eric Paris [this message]
2011-02-17 21:27 ` [PATCH] tmpfs: implement security.capability xattrs Eric Paris
2011-03-02 19:29 ` Eric Paris
2011-03-05 11:21 ` Bruno Prémont
2011-03-16 15:11 ` Jason L Tibbitts III
2011-03-21 5:17 ` Hugh Dickins
2011-03-21 16:43 ` Eric Paris
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20110111210710.32348.1642.stgit@paris.rdu.redhat.com \
--to=eparis@redhat.com \
--cc=hughd@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).