tmpfs: implement generic xattr support
Merge Eric Paris' patch to add xattr support to tmpfs, so that it can be used to host mockroots for mass rebuilds. Drop IMA disabling patch, which is no longer necessary since it's run time (but unused) cost is now minimized.
This commit is contained in:
parent
480eadaeb5
commit
9787d244d7
@ -1,145 +0,0 @@
|
|||||||
From 785465d9cffd65b5a69dd2f465d2f7c917713220 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Kyle McMartin <kyle@mcmartin.ca>
|
|
||||||
Date: Mon, 18 Oct 2010 13:30:39 -0400
|
|
||||||
Subject: [PATCH] ima: provide a toggle to disable it entirely
|
|
||||||
|
|
||||||
Signed-off-by: Kyle McMartin <kyle@redhat.com>
|
|
||||||
---
|
|
||||||
security/integrity/ima/ima.h | 1 +
|
|
||||||
security/integrity/ima/ima_iint.c | 9 +++++++++
|
|
||||||
security/integrity/ima/ima_main.c | 24 +++++++++++++++++++++---
|
|
||||||
3 files changed, 31 insertions(+), 3 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
|
|
||||||
index 3fbcd1d..65c3977 100644
|
|
||||||
--- a/security/integrity/ima/ima.h
|
|
||||||
+++ b/security/integrity/ima/ima.h
|
|
||||||
@@ -37,6 +37,7 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
|
|
||||||
/* set during initialization */
|
|
||||||
extern int iint_initialized;
|
|
||||||
extern int ima_initialized;
|
|
||||||
+extern int ima_enabled;
|
|
||||||
extern int ima_used_chip;
|
|
||||||
extern char *ima_hash;
|
|
||||||
|
|
||||||
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c
|
|
||||||
index afba4ae..3d191ef 100644
|
|
||||||
--- a/security/integrity/ima/ima_iint.c
|
|
||||||
+++ b/security/integrity/ima/ima_iint.c
|
|
||||||
@@ -54,6 +54,9 @@ int ima_inode_alloc(struct inode *inode)
|
|
||||||
struct ima_iint_cache *iint = NULL;
|
|
||||||
int rc = 0;
|
|
||||||
|
|
||||||
+ if (!ima_enabled)
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
|
|
||||||
if (!iint)
|
|
||||||
return -ENOMEM;
|
|
||||||
@@ -116,6 +119,9 @@ void ima_inode_free(struct inode *inode)
|
|
||||||
{
|
|
||||||
struct ima_iint_cache *iint;
|
|
||||||
|
|
||||||
+ if (!ima_enabled)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
spin_lock(&ima_iint_lock);
|
|
||||||
iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode);
|
|
||||||
spin_unlock(&ima_iint_lock);
|
|
||||||
@@ -139,6 +145,9 @@ static void init_once(void *foo)
|
|
||||||
|
|
||||||
static int __init ima_iintcache_init(void)
|
|
||||||
{
|
|
||||||
+ if (!ima_enabled)
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
iint_cache =
|
|
||||||
kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0,
|
|
||||||
SLAB_PANIC, init_once);
|
|
||||||
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
|
|
||||||
index e662b89..6e91905 100644
|
|
||||||
--- a/security/integrity/ima/ima_main.c
|
|
||||||
+++ b/security/integrity/ima/ima_main.c
|
|
||||||
@@ -26,6 +26,7 @@
|
|
||||||
#include "ima.h"
|
|
||||||
|
|
||||||
int ima_initialized;
|
|
||||||
+int ima_enabled;
|
|
||||||
|
|
||||||
char *ima_hash = "sha1";
|
|
||||||
static int __init hash_setup(char *str)
|
|
||||||
@@ -36,6 +37,14 @@ static int __init hash_setup(char *str)
|
|
||||||
}
|
|
||||||
__setup("ima_hash=", hash_setup);
|
|
||||||
|
|
||||||
+static int __init ima_enable(char *str)
|
|
||||||
+{
|
|
||||||
+ if (strncmp(str, "on", 2) == 0)
|
|
||||||
+ ima_enabled = 1;
|
|
||||||
+ return 1;
|
|
||||||
+}
|
|
||||||
+__setup("ima=", ima_enable);
|
|
||||||
+
|
|
||||||
struct ima_imbalance {
|
|
||||||
struct hlist_node node;
|
|
||||||
unsigned long fsmagic;
|
|
||||||
@@ -148,7 +157,7 @@ void ima_counts_get(struct file *file)
|
|
||||||
struct ima_iint_cache *iint;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
- if (!iint_initialized || !S_ISREG(inode->i_mode))
|
|
||||||
+ if (!ima_enabled || !iint_initialized || !S_ISREG(inode->i_mode))
|
|
||||||
return;
|
|
||||||
iint = ima_iint_find_get(inode);
|
|
||||||
if (!iint)
|
|
||||||
@@ -215,7 +224,7 @@ void ima_file_free(struct file *file)
|
|
||||||
struct inode *inode = file->f_dentry->d_inode;
|
|
||||||
struct ima_iint_cache *iint;
|
|
||||||
|
|
||||||
- if (!iint_initialized || !S_ISREG(inode->i_mode))
|
|
||||||
+ if (!ima_enabled || !iint_initialized || !S_ISREG(inode->i_mode))
|
|
||||||
return;
|
|
||||||
iint = ima_iint_find_get(inode);
|
|
||||||
if (!iint)
|
|
||||||
@@ -269,7 +278,7 @@ int ima_file_mmap(struct file *file, unsigned long prot)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
- if (!file)
|
|
||||||
+ if (!ima_enabled || !file)
|
|
||||||
return 0;
|
|
||||||
if (prot & PROT_EXEC)
|
|
||||||
rc = process_measurement(file, file->f_dentry->d_name.name,
|
|
||||||
@@ -294,6 +303,9 @@ int ima_bprm_check(struct linux_binprm *bprm)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
+ if (!ima_enabled)
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
rc = process_measurement(bprm->file, bprm->filename,
|
|
||||||
MAY_EXEC, BPRM_CHECK);
|
|
||||||
return 0;
|
|
||||||
@@ -313,6 +325,9 @@ int ima_file_check(struct file *file, int mask)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
+ if (!ima_enabled)
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
rc = process_measurement(file, file->f_dentry->d_name.name,
|
|
||||||
mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
|
|
||||||
FILE_CHECK);
|
|
||||||
@@ -324,6 +339,9 @@ static int __init init_ima(void)
|
|
||||||
{
|
|
||||||
int error;
|
|
||||||
|
|
||||||
+ if (!ima_enabled)
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
error = ima_init();
|
|
||||||
ima_initialized = 1;
|
|
||||||
return error;
|
|
||||||
--
|
|
||||||
1.7.3.1
|
|
||||||
|
|
14
kernel.spec
14
kernel.spec
@ -619,6 +619,8 @@ Patch150: linux-2.6.29-sparc-IOC_TYPECHECK.patch
|
|||||||
Patch160: linux-2.6-32bit-mmap-exec-randomization.patch
|
Patch160: linux-2.6-32bit-mmap-exec-randomization.patch
|
||||||
Patch161: linux-2.6-i386-nx-emulation.patch
|
Patch161: linux-2.6-i386-nx-emulation.patch
|
||||||
|
|
||||||
|
Patch170: tmpfs-implement-generic-xattr-support.patch
|
||||||
|
|
||||||
Patch200: linux-2.6-debug-sizeof-structs.patch
|
Patch200: linux-2.6-debug-sizeof-structs.patch
|
||||||
Patch202: linux-2.6-debug-taint-vm.patch
|
Patch202: linux-2.6-debug-taint-vm.patch
|
||||||
Patch203: linux-2.6-debug-vm-would-have-oomkilled.patch
|
Patch203: linux-2.6-debug-vm-would-have-oomkilled.patch
|
||||||
@ -628,8 +630,6 @@ Patch380: linux-2.6-defaults-pci_no_msi.patch
|
|||||||
Patch381: linux-2.6-defaults-pci_use_crs.patch
|
Patch381: linux-2.6-defaults-pci_use_crs.patch
|
||||||
Patch383: linux-2.6-defaults-aspm.patch
|
Patch383: linux-2.6-defaults-aspm.patch
|
||||||
|
|
||||||
Patch385: ima-allow-it-to-be-completely-disabled-and-default-off.patch
|
|
||||||
|
|
||||||
Patch390: linux-2.6-defaults-acpi-video.patch
|
Patch390: linux-2.6-defaults-acpi-video.patch
|
||||||
Patch391: linux-2.6-acpi-video-dos.patch
|
Patch391: linux-2.6-acpi-video-dos.patch
|
||||||
Patch393: acpi-ec-add-delay-before-write.patch
|
Patch393: acpi-ec-add-delay-before-write.patch
|
||||||
@ -1181,6 +1181,7 @@ ApplyPatch linux-2.6-32bit-mmap-exec-randomization.patch
|
|||||||
#
|
#
|
||||||
# bugfixes to drivers and filesystems
|
# bugfixes to drivers and filesystems
|
||||||
#
|
#
|
||||||
|
ApplyPatch tmpfs-implement-generic-xattr-support.patch
|
||||||
|
|
||||||
# ext4
|
# ext4
|
||||||
|
|
||||||
@ -1218,8 +1219,6 @@ ApplyPatch linux-2.6-defaults-pci_use_crs.patch
|
|||||||
# enable ASPM by default on hardware we expect to work
|
# enable ASPM by default on hardware we expect to work
|
||||||
ApplyPatch linux-2.6-defaults-aspm.patch
|
ApplyPatch linux-2.6-defaults-aspm.patch
|
||||||
|
|
||||||
#ApplyPatch ima-allow-it-to-be-completely-disabled-and-default-off.patch
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# SCSI Bits.
|
# SCSI Bits.
|
||||||
#
|
#
|
||||||
@ -1937,6 +1936,13 @@ fi
|
|||||||
# and build.
|
# and build.
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Sat May 14 2011 Kyle McMartin <kmcmartin@redhat.com> 2.6.39-0.rc7.git6.1
|
||||||
|
- tmpfs: implement generic xattr support
|
||||||
|
Merge Eric Paris' patch to add xattr support to tmpfs, so that it can be
|
||||||
|
used to host mockroots for mass rebuilds.
|
||||||
|
- Drop IMA disabling patch, which is no longer necessary since it's run time
|
||||||
|
(but unused) cost is now minimized.
|
||||||
|
|
||||||
* Sat May 14 2011 Kyle McMartin <kmcmartin@redhat.com> 2.6.39-0.rc7.git6.0
|
* Sat May 14 2011 Kyle McMartin <kmcmartin@redhat.com> 2.6.39-0.rc7.git6.0
|
||||||
- Update to 2.6.39-rc7-git6
|
- Update to 2.6.39-rc7-git6
|
||||||
|
|
||||||
|
557
tmpfs-implement-generic-xattr-support.patch
Normal file
557
tmpfs-implement-generic-xattr-support.patch
Normal file
@ -0,0 +1,557 @@
|
|||||||
|
From linux-fsdevel-owner@vger.kernel.org Fri May 13 07:16:45 2011
|
||||||
|
From: Miklos Szeredi <miklos@szeredi.hu>
|
||||||
|
To: Andrew Morton <akpm@linux-foundation.org>,
|
||||||
|
Hugh Dickins <hughd@google.com>
|
||||||
|
Subject: [PATCH v2] tmpfs: implement generic xattr support
|
||||||
|
CC: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org,
|
||||||
|
Michal Suchanek <hramrach@centrum.cz>,
|
||||||
|
Serge Hallyn <serge.hallyn@ubuntu.com>,
|
||||||
|
Eric Paris <eparis@redhat.com>,
|
||||||
|
James Morris <jmorris@namei.org>,
|
||||||
|
Christoph Hellwig <hch@infradead.org>
|
||||||
|
Date: Fri, 13 May 2011 13:16:35 +0200
|
||||||
|
Message-ID: <871v02lujw.fsf@tucsk.pomaz.szeredi.hu>
|
||||||
|
X-Mailing-List: linux-fsdevel@vger.kernel.org
|
||||||
|
|
||||||
|
[This update addresses comments from Hugh and Andrew]
|
||||||
|
|
||||||
|
|
||||||
|
From: Eric Paris <eparis@redhat.com>
|
||||||
|
|
||||||
|
This patch implements generic xattrs for tmpfs filesystems. The feodra
|
||||||
|
project, while trying to replace suid apps with file capabilities,
|
||||||
|
realized that tmpfs, which is used on the build systems, does not
|
||||||
|
support file capabilities and thus cannot be used to build packages
|
||||||
|
which use file capabilities. Xattrs are also needed for overlayfs.
|
||||||
|
|
||||||
|
The xattr interface is a bit, odd. If a filesystem does not implement any
|
||||||
|
{get,set,list}xattr functions the VFS will call into some random LSM hooks and
|
||||||
|
the running LSM can then implement some method for handling xattrs. SELinux
|
||||||
|
for example provides a method to support security.selinux but no other
|
||||||
|
security.* xattrs.
|
||||||
|
|
||||||
|
As it stands today when one enables CONFIG_TMPFS_POSIX_ACL tmpfs will have
|
||||||
|
xattr handler routines specifically to handle acls. Because of this tmpfs
|
||||||
|
would loose the VFS/LSM helpers to support the running LSM. To make up for
|
||||||
|
that tmpfs had stub functions that did nothing but call into the LSM hooks
|
||||||
|
which implement the helpers.
|
||||||
|
|
||||||
|
This new patch does not use the LSM fallback functions and instead
|
||||||
|
just implements a native get/set/list xattr feature for the full
|
||||||
|
security.* and trusted.* namespace like a normal filesystem. This
|
||||||
|
means that tmpfs can now support both security.selinux and
|
||||||
|
security.capability, which was not previously possible.
|
||||||
|
|
||||||
|
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. This
|
||||||
|
implementation could easily support the user.* namespace as well,
|
||||||
|
except some care needs to be taken to prevent large amounts of
|
||||||
|
unswappable memory being allocated for unprivileged users.
|
||||||
|
|
||||||
|
[miklos: new config option, suport trusted.*, support symlinks]
|
||||||
|
|
||||||
|
Signed-off-by: Eric Paris <eparis@redhat.com>
|
||||||
|
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
|
||||||
|
Acked-by: Serge Hallyn <serge.hallyn@ubuntu.com>
|
||||||
|
---
|
||||||
|
fs/Kconfig | 18 ++
|
||||||
|
include/linux/shmem_fs.h | 8 +
|
||||||
|
mm/shmem.c | 320 +++++++++++++++++++++++++++++++++++++++--------
|
||||||
|
3 files changed, 290 insertions(+), 56 deletions(-)
|
||||||
|
|
||||||
|
Index: linux-2.6/fs/Kconfig
|
||||||
|
===================================================================
|
||||||
|
--- linux-2.6.orig/fs/Kconfig 2011-05-13 12:26:31.000000000 +0200
|
||||||
|
+++ linux-2.6/fs/Kconfig 2011-05-13 12:29:34.000000000 +0200
|
||||||
|
@@ -121,9 +121,25 @@ config TMPFS
|
||||||
|
|
||||||
|
See <file:Documentation/filesystems/tmpfs.txt> for details.
|
||||||
|
|
||||||
|
+config TMPFS_XATTR
|
||||||
|
+ bool "Tmpfs extended attributes"
|
||||||
|
+ depends on TMPFS
|
||||||
|
+ default n
|
||||||
|
+ help
|
||||||
|
+ Extended attributes are name:value pairs associated with inodes by
|
||||||
|
+ the kernel or by users (see the attr(5) manual page, or visit
|
||||||
|
+ <http://acl.bestbits.at/> for details).
|
||||||
|
+
|
||||||
|
+ Currently this enables support for the trusted.* and
|
||||||
|
+ security.* namespaces.
|
||||||
|
+
|
||||||
|
+ If unsure, say N.
|
||||||
|
+
|
||||||
|
+ You need this for POSIX ACL support on tmpfs.
|
||||||
|
+
|
||||||
|
config TMPFS_POSIX_ACL
|
||||||
|
bool "Tmpfs POSIX Access Control Lists"
|
||||||
|
- depends on TMPFS
|
||||||
|
+ depends on TMPFS_XATTR
|
||||||
|
select GENERIC_ACL
|
||||||
|
help
|
||||||
|
POSIX Access Control Lists (ACLs) support permissions for users and
|
||||||
|
Index: linux-2.6/include/linux/shmem_fs.h
|
||||||
|
===================================================================
|
||||||
|
--- linux-2.6.orig/include/linux/shmem_fs.h 2011-05-13 12:26:31.000000000 +0200
|
||||||
|
+++ linux-2.6/include/linux/shmem_fs.h 2011-05-13 12:35:36.000000000 +0200
|
||||||
|
@@ -9,6 +9,8 @@
|
||||||
|
|
||||||
|
#define SHMEM_NR_DIRECT 16
|
||||||
|
|
||||||
|
+#define SHMEM_SYMLINK_INLINE_LEN (SHMEM_NR_DIRECT * sizeof(swp_entry_t))
|
||||||
|
+
|
||||||
|
struct shmem_inode_info {
|
||||||
|
spinlock_t lock;
|
||||||
|
unsigned long flags;
|
||||||
|
@@ -17,8 +19,12 @@ struct shmem_inode_info {
|
||||||
|
unsigned long next_index; /* highest alloced index + 1 */
|
||||||
|
struct shared_policy policy; /* NUMA memory alloc policy */
|
||||||
|
struct page *i_indirect; /* top indirect blocks page */
|
||||||
|
- swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* first blocks */
|
||||||
|
+ union {
|
||||||
|
+ swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* first blocks */
|
||||||
|
+ char inline_symlink[SHMEM_SYMLINK_INLINE_LEN];
|
||||||
|
+ };
|
||||||
|
struct list_head swaplist; /* chain of maybes on swap */
|
||||||
|
+ struct list_head xattr_list; /* list of shmem_xattr */
|
||||||
|
struct inode vfs_inode;
|
||||||
|
};
|
||||||
|
|
||||||
|
Index: linux-2.6/mm/shmem.c
|
||||||
|
===================================================================
|
||||||
|
--- linux-2.6.orig/mm/shmem.c 2011-05-13 12:26:31.000000000 +0200
|
||||||
|
+++ linux-2.6/mm/shmem.c 2011-05-13 12:36:08.000000000 +0200
|
||||||
|
@@ -99,6 +99,13 @@ static struct vfsmount *shm_mnt;
|
||||||
|
/* Pretend that each entry is of this size in directory's i_size */
|
||||||
|
#define BOGO_DIRENT_SIZE 20
|
||||||
|
|
||||||
|
+struct shmem_xattr {
|
||||||
|
+ struct list_head list; /* anchored by shmem_inode_info->xattr_list */
|
||||||
|
+ char *name; /* xattr name */
|
||||||
|
+ size_t size;
|
||||||
|
+ char value[0];
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
/* Flag allocation requirements to shmem_getpage and shmem_swp_alloc */
|
||||||
|
enum sgp_type {
|
||||||
|
SGP_READ, /* don't exceed i_size, don't allocate page */
|
||||||
|
@@ -822,6 +829,7 @@ static int shmem_notify_change(struct de
|
||||||
|
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 +842,11 @@ static void shmem_evict_inode(struct ino
|
||||||
|
mutex_unlock(&shmem_swaplist_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ list_for_each_entry_safe(xattr, nxattr, &info->xattr_list, list) {
|
||||||
|
+ kfree(xattr->name);
|
||||||
|
+ kfree(xattr);
|
||||||
|
+ }
|
||||||
|
BUG_ON(inode->i_blocks);
|
||||||
|
shmem_free_inode(inode->i_sb);
|
||||||
|
end_writeback(inode);
|
||||||
|
@@ -1616,6 +1629,7 @@ static struct inode *shmem_get_inode(str
|
||||||
|
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) {
|
||||||
|
@@ -2015,9 +2029,9 @@ static int shmem_symlink(struct inode *d
|
||||||
|
|
||||||
|
info = SHMEM_I(inode);
|
||||||
|
inode->i_size = len-1;
|
||||||
|
- if (len <= (char *)inode - (char *)info) {
|
||||||
|
+ if (len <= SHMEM_SYMLINK_INLINE_LEN) {
|
||||||
|
/* do it inline */
|
||||||
|
- memcpy(info, symname, len);
|
||||||
|
+ memcpy(info->inline_symlink, symname, len);
|
||||||
|
inode->i_op = &shmem_symlink_inline_operations;
|
||||||
|
} else {
|
||||||
|
error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL);
|
||||||
|
@@ -2043,7 +2057,7 @@ static int shmem_symlink(struct inode *d
|
||||||
|
|
||||||
|
static void *shmem_follow_link_inline(struct dentry *dentry, struct nameidata *nd)
|
||||||
|
{
|
||||||
|
- nd_set_link(nd, (char *)SHMEM_I(dentry->d_inode));
|
||||||
|
+ nd_set_link(nd, SHMEM_I(dentry->d_inode)->inline_symlink);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -2067,63 +2081,253 @@ static void shmem_put_link(struct dentry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-static const struct inode_operations shmem_symlink_inline_operations = {
|
||||||
|
- .readlink = generic_readlink,
|
||||||
|
- .follow_link = shmem_follow_link_inline,
|
||||||
|
-};
|
||||||
|
-
|
||||||
|
-static const struct inode_operations shmem_symlink_inode_operations = {
|
||||||
|
- .readlink = generic_readlink,
|
||||||
|
- .follow_link = shmem_follow_link,
|
||||||
|
- .put_link = shmem_put_link,
|
||||||
|
-};
|
||||||
|
-
|
||||||
|
-#ifdef CONFIG_TMPFS_POSIX_ACL
|
||||||
|
+#ifdef CONFIG_TMPFS_XATTR
|
||||||
|
/*
|
||||||
|
- * Superblocks without xattr inode operations will get security.* xattr
|
||||||
|
- * support from the VFS "for free". As soon as we have any other xattrs
|
||||||
|
+ * Superblocks without xattr inode operations may get some security.* xattr
|
||||||
|
+ * support from the LSM "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 dentry *dentry, char *list,
|
||||||
|
- size_t list_len, const char *name,
|
||||||
|
- size_t name_len, int handler_flags)
|
||||||
|
+static int shmem_xattr_get(struct dentry *dentry, const char *name,
|
||||||
|
+ void *buffer, size_t size)
|
||||||
|
{
|
||||||
|
- return security_inode_listsecurity(dentry->d_inode, list, list_len);
|
||||||
|
-}
|
||||||
|
+ struct shmem_inode_info *info;
|
||||||
|
+ struct shmem_xattr *xattr;
|
||||||
|
+ int ret = -ENODATA;
|
||||||
|
|
||||||
|
-static int shmem_xattr_security_get(struct dentry *dentry, const char *name,
|
||||||
|
- void *buffer, size_t size, int handler_flags)
|
||||||
|
-{
|
||||||
|
- if (strcmp(name, "") == 0)
|
||||||
|
- return -EINVAL;
|
||||||
|
- return xattr_getsecurity(dentry->d_inode, name, buffer, size);
|
||||||
|
+ info = SHMEM_I(dentry->d_inode);
|
||||||
|
+
|
||||||
|
+ spin_lock(&info->lock);
|
||||||
|
+ list_for_each_entry(xattr, &info->xattr_list, list) {
|
||||||
|
+ if (strcmp(name, xattr->name))
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ ret = xattr->size;
|
||||||
|
+ if (buffer) {
|
||||||
|
+ if (size < xattr->size)
|
||||||
|
+ ret = -ERANGE;
|
||||||
|
+ else
|
||||||
|
+ memcpy(buffer, xattr->value, xattr->size);
|
||||||
|
+ }
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ spin_unlock(&info->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)
|
||||||
|
+static int shmem_xattr_set(struct dentry *dentry, const char *name,
|
||||||
|
+ const void *value, size_t size, int flags)
|
||||||
|
{
|
||||||
|
- if (strcmp(name, "") == 0)
|
||||||
|
- return -EINVAL;
|
||||||
|
- return security_inode_setsecurity(dentry->d_inode, name, value,
|
||||||
|
- size, flags);
|
||||||
|
+ struct inode *inode = dentry->d_inode;
|
||||||
|
+ struct shmem_inode_info *info = SHMEM_I(inode);
|
||||||
|
+ struct shmem_xattr *xattr;
|
||||||
|
+ struct shmem_xattr *new_xattr = NULL;
|
||||||
|
+ size_t len;
|
||||||
|
+ int err = 0;
|
||||||
|
+
|
||||||
|
+ /* value == NULL means remove */
|
||||||
|
+ if (value) {
|
||||||
|
+ /* wrap around? */
|
||||||
|
+ len = sizeof(*new_xattr) + size;
|
||||||
|
+ if (len <= sizeof(*new_xattr))
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+
|
||||||
|
+ new_xattr = kmalloc(len, GFP_KERNEL);
|
||||||
|
+ if (!new_xattr)
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+
|
||||||
|
+ new_xattr->name = kstrdup(name, GFP_KERNEL);
|
||||||
|
+ if (!new_xattr->name) {
|
||||||
|
+ kfree(new_xattr);
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ new_xattr->size = size;
|
||||||
|
+ memcpy(new_xattr->value, value, size);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ spin_lock(&info->lock);
|
||||||
|
+ list_for_each_entry(xattr, &info->xattr_list, list) {
|
||||||
|
+ if (!strcmp(name, xattr->name)) {
|
||||||
|
+ if (flags & XATTR_CREATE) {
|
||||||
|
+ xattr = new_xattr;
|
||||||
|
+ err = -EEXIST;
|
||||||
|
+ } else if (new_xattr) {
|
||||||
|
+ list_replace(&xattr->list, &new_xattr->list);
|
||||||
|
+ } else {
|
||||||
|
+ list_del(&xattr->list);
|
||||||
|
+ }
|
||||||
|
+ goto out;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ if (flags & XATTR_REPLACE) {
|
||||||
|
+ xattr = new_xattr;
|
||||||
|
+ err = -ENODATA;
|
||||||
|
+ } else {
|
||||||
|
+ list_add(&new_xattr->list, &info->xattr_list);
|
||||||
|
+ xattr = NULL;
|
||||||
|
+ }
|
||||||
|
+out:
|
||||||
|
+ spin_unlock(&info->lock);
|
||||||
|
+ if (xattr)
|
||||||
|
+ kfree(xattr->name);
|
||||||
|
+ kfree(xattr);
|
||||||
|
+ return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static const 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 const struct xattr_handler *shmem_xattr_handlers[] = {
|
||||||
|
+#ifdef CONFIG_TMPFS_POSIX_ACL
|
||||||
|
&generic_acl_access_handler,
|
||||||
|
&generic_acl_default_handler,
|
||||||
|
- &shmem_xattr_security_handler,
|
||||||
|
+#endif
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
+
|
||||||
|
+static int shmem_xattr_validate(const char *name)
|
||||||
|
+{
|
||||||
|
+ struct { const char *prefix; size_t len; } arr[] = {
|
||||||
|
+ { XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN },
|
||||||
|
+ { XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN }
|
||||||
|
+ };
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < ARRAY_SIZE(arr); i++) {
|
||||||
|
+ size_t preflen = arr[i].len;
|
||||||
|
+ if (strncmp(name, arr[i].prefix, preflen) == 0) {
|
||||||
|
+ if (!name[preflen])
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return -EOPNOTSUPP;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static ssize_t shmem_getxattr(struct dentry *dentry, const char *name,
|
||||||
|
+ void *buffer, size_t size)
|
||||||
|
+{
|
||||||
|
+ int err;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * If this is a request for a synthetic attribute in the system.*
|
||||||
|
+ * namespace use the generic infrastructure to resolve a handler
|
||||||
|
+ * for it via sb->s_xattr.
|
||||||
|
+ */
|
||||||
|
+ if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
|
||||||
|
+ return generic_getxattr(dentry, name, buffer, size);
|
||||||
|
+
|
||||||
|
+ err = shmem_xattr_validate(name);
|
||||||
|
+ if (err)
|
||||||
|
+ return err;
|
||||||
|
+
|
||||||
|
+ return shmem_xattr_get(dentry, name, buffer, size);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int shmem_setxattr(struct dentry *dentry, const char *name,
|
||||||
|
+ const void *value, size_t size, int flags)
|
||||||
|
+{
|
||||||
|
+ int err;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * If this is a request for a synthetic attribute in the system.*
|
||||||
|
+ * namespace use the generic infrastructure to resolve a handler
|
||||||
|
+ * for it via sb->s_xattr.
|
||||||
|
+ */
|
||||||
|
+ if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
|
||||||
|
+ return generic_setxattr(dentry, name, value, size, flags);
|
||||||
|
+
|
||||||
|
+ err = shmem_xattr_validate(name);
|
||||||
|
+ if (err)
|
||||||
|
+ return err;
|
||||||
|
+
|
||||||
|
+ if (size == 0)
|
||||||
|
+ value = ""; /* empty EA, do not remove */
|
||||||
|
+
|
||||||
|
+ return shmem_xattr_set(dentry, name, value, size, flags);
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int shmem_removexattr(struct dentry *dentry, const char *name)
|
||||||
|
+{
|
||||||
|
+ int err;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * If this is a request for a synthetic attribute in the system.*
|
||||||
|
+ * namespace use the generic infrastructure to resolve a handler
|
||||||
|
+ * for it via sb->s_xattr.
|
||||||
|
+ */
|
||||||
|
+ if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
|
||||||
|
+ return generic_removexattr(dentry, name);
|
||||||
|
+
|
||||||
|
+ err = shmem_xattr_validate(name);
|
||||||
|
+ if (err)
|
||||||
|
+ return err;
|
||||||
|
+
|
||||||
|
+ return shmem_xattr_set(dentry, name, NULL, 0, XATTR_REPLACE);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static bool xattr_is_trusted(const char *name)
|
||||||
|
+{
|
||||||
|
+ return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
||||||
|
+{
|
||||||
|
+ bool trusted = capable(CAP_SYS_ADMIN);
|
||||||
|
+ struct shmem_xattr *xattr;
|
||||||
|
+ struct shmem_inode_info *info;
|
||||||
|
+ size_t used = 0;
|
||||||
|
+
|
||||||
|
+ info = SHMEM_I(dentry->d_inode);
|
||||||
|
+
|
||||||
|
+ spin_lock(&info->lock);
|
||||||
|
+ list_for_each_entry(xattr, &info->xattr_list, list) {
|
||||||
|
+ size_t len;
|
||||||
|
+
|
||||||
|
+ /* skip "trusted." attributes for unprivileged callers */
|
||||||
|
+ if (!trusted && xattr_is_trusted(xattr->name))
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ len = strlen(xattr->name) + 1;
|
||||||
|
+ used += len;
|
||||||
|
+ if (buffer) {
|
||||||
|
+ if (size < used) {
|
||||||
|
+ used = -ERANGE;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ memcpy(buffer, xattr->name, len);
|
||||||
|
+ buffer += len;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ spin_unlock(&info->lock);
|
||||||
|
+
|
||||||
|
+ return used;
|
||||||
|
+}
|
||||||
|
+#endif /* CONFIG_TMPFS_XATTR */
|
||||||
|
+
|
||||||
|
+static const struct inode_operations shmem_symlink_inline_operations = {
|
||||||
|
+ .readlink = generic_readlink,
|
||||||
|
+ .follow_link = shmem_follow_link_inline,
|
||||||
|
+#ifdef CONFIG_TMPFS_XATTR
|
||||||
|
+ .setxattr = shmem_setxattr,
|
||||||
|
+ .getxattr = shmem_getxattr,
|
||||||
|
+ .listxattr = shmem_listxattr,
|
||||||
|
+ .removexattr = shmem_removexattr,
|
||||||
|
+#endif
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static const struct inode_operations shmem_symlink_inode_operations = {
|
||||||
|
+ .readlink = generic_readlink,
|
||||||
|
+ .follow_link = shmem_follow_link,
|
||||||
|
+ .put_link = shmem_put_link,
|
||||||
|
+#ifdef CONFIG_TMPFS_XATTR
|
||||||
|
+ .setxattr = shmem_setxattr,
|
||||||
|
+ .getxattr = shmem_getxattr,
|
||||||
|
+ .listxattr = shmem_listxattr,
|
||||||
|
+ .removexattr = shmem_removexattr,
|
||||||
|
#endif
|
||||||
|
+};
|
||||||
|
|
||||||
|
static struct dentry *shmem_get_parent(struct dentry *child)
|
||||||
|
{
|
||||||
|
@@ -2403,8 +2607,10 @@ int shmem_fill_super(struct super_block
|
||||||
|
sb->s_magic = TMPFS_MAGIC;
|
||||||
|
sb->s_op = &shmem_ops;
|
||||||
|
sb->s_time_gran = 1;
|
||||||
|
-#ifdef CONFIG_TMPFS_POSIX_ACL
|
||||||
|
+#ifdef CONFIG_TMPFS_XATTR
|
||||||
|
sb->s_xattr = shmem_xattr_handlers;
|
||||||
|
+#endif
|
||||||
|
+#ifdef CONFIG_TMPFS_POSIX_ACL
|
||||||
|
sb->s_flags |= MS_POSIXACL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@@ -2502,11 +2708,13 @@ static const struct file_operations shme
|
||||||
|
static const struct inode_operations shmem_inode_operations = {
|
||||||
|
.setattr = shmem_notify_change,
|
||||||
|
.truncate_range = shmem_truncate_range,
|
||||||
|
+#ifdef CONFIG_TMPFS_XATTR
|
||||||
|
+ .setxattr = shmem_setxattr,
|
||||||
|
+ .getxattr = shmem_getxattr,
|
||||||
|
+ .listxattr = shmem_listxattr,
|
||||||
|
+ .removexattr = shmem_removexattr,
|
||||||
|
+#endif
|
||||||
|
#ifdef CONFIG_TMPFS_POSIX_ACL
|
||||||
|
- .setxattr = generic_setxattr,
|
||||||
|
- .getxattr = generic_getxattr,
|
||||||
|
- .listxattr = generic_listxattr,
|
||||||
|
- .removexattr = generic_removexattr,
|
||||||
|
.check_acl = generic_check_acl,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@@ -2524,23 +2732,27 @@ static const struct inode_operations shm
|
||||||
|
.mknod = shmem_mknod,
|
||||||
|
.rename = shmem_rename,
|
||||||
|
#endif
|
||||||
|
+#ifdef CONFIG_TMPFS_XATTR
|
||||||
|
+ .setxattr = shmem_setxattr,
|
||||||
|
+ .getxattr = shmem_getxattr,
|
||||||
|
+ .listxattr = shmem_listxattr,
|
||||||
|
+ .removexattr = shmem_removexattr,
|
||||||
|
+#endif
|
||||||
|
#ifdef CONFIG_TMPFS_POSIX_ACL
|
||||||
|
.setattr = shmem_notify_change,
|
||||||
|
- .setxattr = generic_setxattr,
|
||||||
|
- .getxattr = generic_getxattr,
|
||||||
|
- .listxattr = generic_listxattr,
|
||||||
|
- .removexattr = generic_removexattr,
|
||||||
|
.check_acl = generic_check_acl,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct inode_operations shmem_special_inode_operations = {
|
||||||
|
+#ifdef CONFIG_TMPFS_XATTR
|
||||||
|
+ .setxattr = shmem_setxattr,
|
||||||
|
+ .getxattr = shmem_getxattr,
|
||||||
|
+ .listxattr = shmem_listxattr,
|
||||||
|
+ .removexattr = shmem_removexattr,
|
||||||
|
+#endif
|
||||||
|
#ifdef CONFIG_TMPFS_POSIX_ACL
|
||||||
|
.setattr = shmem_notify_change,
|
||||||
|
- .setxattr = generic_setxattr,
|
||||||
|
- .getxattr = generic_getxattr,
|
||||||
|
- .listxattr = generic_listxattr,
|
||||||
|
- .removexattr = generic_removexattr,
|
||||||
|
.check_acl = generic_check_acl,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
--
|
||||||
|
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
|
||||||
|
the body of a message to majordomo@vger.kernel.org
|
||||||
|
More majordomo info at http://vger.kernel.org/majordomo-info.html
|
||||||
|
|
Loading…
Reference in New Issue
Block a user