Add support to yaffs to set the security attribute of new inodes when
they are created. This parallels similar support in other filesystems,
and is a requirement for e.g. SELinux and other MAC systems.
I'm not entirely sure about the error path in the unlikely case where
yaffs_init_security() returns an error; the intent is to unwind the file
creation in that situation as if it had never been created. This error
case is however unlikely. The file must have a security attribute
assigned before it becomes accessible to userspace.
I only updated yaffs_vfs_multi.c, but the same code should work for
yaffs_vfs_single.c, using whichever branch of the #if that corresponds
to your target upstream kernel version.
Signed-off-by: Stephen Smalley <
sds@tycho.nsa.gov>
---
yaffs_vfs_multi.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 71 insertions(+), 2 deletions(-)
diff --git a/yaffs_vfs_multi.c b/yaffs_vfs_multi.c
index 7e28c40..5acd1de 100644
--- a/yaffs_vfs_multi.c
+++ b/yaffs_vfs_multi.c
@@ -78,6 +78,7 @@
#include <linux/interrupt.h>
#include <linux/string.h>
#include <linux/ctype.h>
+#include <linux/security.h>
#if (YAFFS_NEW_FOLLOW_LINK == 1)
#include <linux/namei.h>
@@ -1603,6 +1604,54 @@ out:
return ret_val;
}
+#ifdef CONFIG_YAFFS_XATTR
+static int yaffs_init_security(struct inode *dir, struct dentry *dentry,
+ struct inode *inode)
+{
+ int err;
+ size_t size;
+ void *value;
+ char *suffix;
+ char name[XATTR_NAME_MAX];
+ struct yaffs_dev *dev;
+ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
+ int result;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+ err = security_inode_init_security(inode, dir, &dentry->d_name,
+ &suffix, &value, &size);
+#else
+ err = security_inode_init_security(inode, dir, &suffix, &value, &size);
+#endif
+ if (err) {
+ if (err == -EOPNOTSUPP)
+ return 0;
+ return err;
+ }
+ snprintf(name, sizeof name, "%s%s", XATTR_SECURITY_PREFIX, suffix);
+
+ /* inlined yaffs_setxattr: no instantiated dentry yet */
+ dev = obj->my_dev;
+ yaffs_gross_lock(dev);
+ result = yaffs_set_xattrib(obj, name, value, size, 0);
+ if (result == YAFFS_OK)
+ err = 0;
+ else if (result < 0)
+ err = result;
+ yaffs_gross_unlock(dev);
+
+ kfree(value);
+ kfree(suffix);
+ return err;
+}
+#else
+static int yaffs_init_security(struct inode *dir, struct dentry *dentry,
+ struct inode *inode)
+{
+ return 0;
+}
+#endif
+
/*
* File creation. Allocate an inode, and we're done..
*/
@@ -1689,6 +1738,15 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
if (obj) {
inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
+ error = yaffs_init_security(dir, dentry, inode);
+ if (error) {
+ /* undo! */
+ iput(inode);
+ yaffs_gross_lock(dev);
+ yaffs_unlinker(parent, dentry->d_name.name);
+ yaffs_gross_unlock(dev);
+ return error;
+ }
d_instantiate(dentry, inode);
update_dir_time(dir);
yaffs_trace(YAFFS_TRACE_OS,
@@ -1802,12 +1860,14 @@ static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
uid_t uid = YCRED(current)->fsuid;
gid_t gid =
(dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
+ struct yaffs_obj *parent = yaffs_inode_to_obj(dir);
+ int error;
yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink");
- dev = yaffs_inode_to_obj(dir)->my_dev;
+ dev = parent->my_dev;
yaffs_gross_lock(dev);
- obj = yaffs_create_symlink(yaffs_inode_to_obj(dir), dentry->d_name.name,
+ obj = yaffs_create_symlink(parent, dentry->d_name.name,
S_IFLNK | S_IRWXUGO, uid, gid, symname);
yaffs_gross_unlock(dev);
@@ -1815,6 +1875,15 @@ static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
struct inode *inode;
inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
+ error = yaffs_init_security(dir, dentry, inode);
+ if (error) {
+ /* undo! */
+ iput(inode);
+ yaffs_gross_lock(dev);
+ yaffs_unlinker(parent, dentry->d_name.name);
+ yaffs_gross_unlock(dev);
+ return error;
+ }
d_instantiate(dentry, inode);
update_dir_time(dir);
yaffs_trace(YAFFS_TRACE_OS, "symlink created OK");
--
Stephen Smalley
National Security Agency