On Wed, 2011-04-13 at 16:36 -0400, Stephen Smalley wrote:
> 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>
BTW, if it is helpful, the code added by this patch can be considered to
be public domain, i.e. not copyrighted. Not clear it matters since
yaffs_vfs_multi.c is already marked as GPLv2 but wasn't sure if you had
concerns about retaining exclusive copyright on it.
>
> ---
>
> 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