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 --- 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 #include #include +#include #if (YAFFS_NEW_FOLLOW_LINK == 1) #include @@ -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