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 SELinux and other MAC systems. This support
is used by SE Android,
http://selinuxproject.org/page/SEAndroid.
Signed-off-by: Stephen Smalley <
sds@tycho.nsa.gov>
---
yaffs_vfs_multi.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
yaffs_vfs_single.c | 39 ++++++++++++++++++++++++++
2 files changed, 119 insertions(+)
diff --git a/yaffs_vfs_multi.c b/yaffs_vfs_multi.c
index ce41d6c..ed343e2 100644
--- a/yaffs_vfs_multi.c
+++ b/yaffs_vfs_multi.c
@@ -71,6 +71,8 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/fs.h>
+#include <linux/security.h>
+#include <linux/xattr.h>
#include <linux/proc_fs.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39))
#include <linux/smp_lock.h>
@@ -1618,6 +1620,82 @@ out:
#define YCRED(x) (x->cred)
#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
+int yaffs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
+ void *fs_info)
+{
+ const struct xattr *xattr;
+ struct yaffs_obj *obj = fs_info;
+ struct yaffs_dev *dev = obj->my_dev;
+ char name[XATTR_NAME_MAX];
+ int err = 0;
+ int result = YAFFS_OK;
+
+ yaffs_gross_lock(dev);
+ for (xattr = xattr_array; xattr->name != NULL; xattr++) {
+ snprintf(name, sizeof name, "%s%s", XATTR_SECURITY_PREFIX, xattr->name);
+ /* inlined yaffs_setxattr: no instantiated dentry yet */
+ result = yaffs_set_xattrib(obj, name, xattr->value,
+ xattr->value_len, 0);
+ if (result < 0)
+ break;
+ }
+ yaffs_gross_unlock(dev);
+ if (result == YAFFS_OK)
+ err = 0;
+ else if (result < 0)
+ err = result;
+ return err;
+}
+
+static int yaffs_init_security(struct inode *dir, struct dentry *dentry,
+ struct inode *inode)
+{
+ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
+ return security_inode_init_security(inode, dir, &dentry->d_name,
+ &yaffs_initxattrs, obj);
+}
+#else
+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_obj *obj = yaffs_inode_to_obj(inode);
+ struct yaffs_dev *dev = obj->my_dev;
+ 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 */
+ 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;
+}
+#endif
+
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
dev_t rdev)
@@ -1694,6 +1772,7 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
if (obj) {
inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
+ yaffs_init_security(dir, dentry, inode);
d_instantiate(dentry, inode);
update_dir_time(dir);
yaffs_trace(YAFFS_TRACE_OS,
@@ -1827,6 +1906,7 @@ 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);
+ yaffs_init_security(dir, dentry, inode);
d_instantiate(dentry, inode);
update_dir_time(dir);
yaffs_trace(YAFFS_TRACE_OS, "symlink created OK");
diff --git a/yaffs_vfs_single.c b/yaffs_vfs_single.c
index 8d41f69..f3e83df 100644
--- a/yaffs_vfs_single.c
+++ b/yaffs_vfs_single.c
@@ -41,6 +41,8 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/fs.h>
+#include <linux/security.h>
+#include <linux/xattr.h>
#include <linux/proc_fs.h>
#include <linux/pagemap.h>
#include <linux/mtd/mtd.h>
@@ -187,6 +189,41 @@ struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
return inode;
}
+int yaffs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
+ void *fs_info)
+{
+ const struct xattr *xattr;
+ struct yaffs_obj *obj = fs_info;
+ struct yaffs_dev *dev = obj->my_dev;
+ char name[XATTR_NAME_MAX];
+ int err = 0;
+ int result = YAFFS_OK;
+
+ yaffs_gross_lock(dev);
+ for (xattr = xattr_array; xattr->name != NULL; xattr++) {
+ snprintf(name, sizeof name, "%s%s", XATTR_SECURITY_PREFIX, xattr->name);
+ /* inlined yaffs_setxattr: no instantiated dentry yet */
+ result = yaffs_set_xattrib(obj, name, xattr->value,
+ xattr->value_len, 0);
+ if (result < 0)
+ break;
+ }
+ yaffs_gross_unlock(dev);
+ if (result == YAFFS_OK)
+ err = 0;
+ else if (result < 0)
+ err = result;
+ return err;
+}
+
+static int yaffs_init_security(struct inode *dir, struct dentry *dentry,
+ struct inode *inode)
+{
+ struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
+ return security_inode_init_security(inode, dir, &dentry->d_name,
+ &yaffs_initxattrs, obj);
+}
+
static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
dev_t rdev)
{
@@ -259,6 +296,7 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
+ yaffs_init_security(dir, dentry, inode);
d_instantiate(dentry, inode);
update_dir_time(dir);
yaffs_trace(YAFFS_TRACE_OS,
@@ -357,6 +395,7 @@ static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
}
inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
+ yaffs_init_security(dir, dentry, inode);
d_instantiate(dentry, inode);
update_dir_time(dir);
yaffs_trace(YAFFS_TRACE_OS, "symlink created OK");
--
1.7.11.2
--
Stephen Smalley
National Security Agency