2012-02-23 09:46:19

by Sakkinen, Jarkko

[permalink] [raw]
Subject: [PATCH] tmpfs: security xattr setting on inode creation

Adds to generic xattr support introduced in Linux 3.0 by
implementing initxattrs callback. This enables consulting
of security attributes from LSM and EVM when inode is
created.

Signed-off-by: Jarkko Sakkinen <[email protected]>
---
mm/shmem.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 66 insertions(+), 16 deletions(-)

diff --git a/mm/shmem.c b/mm/shmem.c
index 7a45ad0..cd367b1 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1478,6 +1478,64 @@ static int shmem_statfs(struct dentry *dentry, struct kstatfs *buf)
}

/*
+ * Allocate new xattr.
+ */
+static int shmem_xattr_alloc(size_t size, struct shmem_xattr **new_xattr)
+{
+ /* wrap around? */
+ size_t len = sizeof(**new_xattr) + size;
+ if (len <= sizeof(**new_xattr))
+ return -ENOMEM;
+
+ *new_xattr = kmalloc(len, GFP_KERNEL);
+ if (*new_xattr == NULL)
+ return -ENOMEM;
+
+ (*new_xattr)->size = size;
+ return 0;
+}
+
+/*
+ * Callback for security_inode_init_security() for acquiring xattrs.
+ */
+static int shmem_initxattrs(struct inode *inode,
+ const struct xattr *xattr_array,
+ void *fs_info)
+{
+ const struct xattr *xattr;
+ struct shmem_inode_info *info = SHMEM_I(inode);
+ struct shmem_xattr *new_xattr = NULL;
+ size_t len;
+ int err = 0;
+
+ for (xattr = xattr_array; xattr->name != NULL; xattr++) {
+ err = shmem_xattr_alloc(xattr->value_len, &new_xattr);
+ if (err < 0)
+ return err;
+
+ len = strlen(xattr->name) + 1;
+ new_xattr->name = kmalloc(XATTR_SECURITY_PREFIX_LEN + len,
+ GFP_KERNEL);
+ if (new_xattr->name == NULL) {
+ kfree(new_xattr);
+ return -ENOMEM;
+ }
+
+ memcpy(new_xattr->name, XATTR_SECURITY_PREFIX,
+ XATTR_SECURITY_PREFIX_LEN);
+ memcpy(new_xattr->name + XATTR_SECURITY_PREFIX_LEN,
+ xattr->name, len);
+ memcpy(new_xattr->value, xattr->value, xattr->value_len);
+
+ spin_lock(&info->lock);
+ list_add(&new_xattr->list, &info->xattr_list);
+ spin_unlock(&info->lock);
+ }
+
+ return 0;
+}
+
+/*
* File creation. Allocate an inode, and we're done..
*/
static int
@@ -1490,7 +1548,7 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
if (inode) {
error = security_inode_init_security(inode, dir,
&dentry->d_name,
- NULL, NULL);
+ &shmem_initxattrs, NULL);
if (error) {
if (error != -EOPNOTSUPP) {
iput(inode);
@@ -1630,7 +1688,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
return -ENOSPC;

error = security_inode_init_security(inode, dir, &dentry->d_name,
- NULL, NULL);
+ &shmem_initxattrs, NULL);
if (error) {
if (error != -EOPNOTSUPP) {
iput(inode);
@@ -1731,26 +1789,19 @@ static int shmem_xattr_get(struct dentry *dentry, const char *name,
return ret;
}

-static int shmem_xattr_set(struct dentry *dentry, const char *name,
+static int shmem_xattr_set(struct inode *inode, const char *name,
const void *value, size_t size, int 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;
+ err = shmem_xattr_alloc(size, &new_xattr);
+ if (err < 0)
+ return err;

new_xattr->name = kstrdup(name, GFP_KERNEL);
if (!new_xattr->name) {
@@ -1758,7 +1809,6 @@ static int shmem_xattr_set(struct dentry *dentry, const char *name,
return -ENOMEM;
}

- new_xattr->size = size;
memcpy(new_xattr->value, value, size);
}

@@ -1858,7 +1908,7 @@ static int shmem_setxattr(struct dentry *dentry, const char *name,
if (size == 0)
value = ""; /* empty EA, do not remove */

- return shmem_xattr_set(dentry, name, value, size, flags);
+ return shmem_xattr_set(dentry->d_inode, name, value, size, flags);

}

@@ -1878,7 +1928,7 @@ static int shmem_removexattr(struct dentry *dentry, const char *name)
if (err)
return err;

- return shmem_xattr_set(dentry, name, NULL, 0, XATTR_REPLACE);
+ return shmem_xattr_set(dentry->d_inode, name, NULL, 0, XATTR_REPLACE);
}

static bool xattr_is_trusted(const char *name)
--
1.7.5.4


2012-02-24 08:14:06

by James Morris

[permalink] [raw]
Subject: Re: [PATCH] tmpfs: security xattr setting on inode creation

On Thu, 23 Feb 2012, Jarkko Sakkinen wrote:

> Adds to generic xattr support introduced in Linux 3.0 by
> implementing initxattrs callback. This enables consulting
> of security attributes from LSM and EVM when inode is
> created.
>
> Signed-off-by: Jarkko Sakkinen <[email protected]>

Reviewed-by: James Morris <[email protected]>

> mm/shmem.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++-----------
> 1 files changed, 66 insertions(+), 16 deletions(-)
>
> diff --git a/mm/shmem.c b/mm/shmem.c
> index 7a45ad0..cd367b1 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -1478,6 +1478,64 @@ static int shmem_statfs(struct dentry *dentry, struct kstatfs *buf)
> }
>
> /*
> + * Allocate new xattr.
> + */
> +static int shmem_xattr_alloc(size_t size, struct shmem_xattr **new_xattr)
> +{
> + /* wrap around? */
> + size_t len = sizeof(**new_xattr) + size;
> + if (len <= sizeof(**new_xattr))
> + return -ENOMEM;
> +
> + *new_xattr = kmalloc(len, GFP_KERNEL);
> + if (*new_xattr == NULL)
> + return -ENOMEM;
> +
> + (*new_xattr)->size = size;
> + return 0;
> +}
> +
> +/*
> + * Callback for security_inode_init_security() for acquiring xattrs.
> + */
> +static int shmem_initxattrs(struct inode *inode,
> + const struct xattr *xattr_array,
> + void *fs_info)
> +{
> + const struct xattr *xattr;
> + struct shmem_inode_info *info = SHMEM_I(inode);
> + struct shmem_xattr *new_xattr = NULL;
> + size_t len;
> + int err = 0;
> +
> + for (xattr = xattr_array; xattr->name != NULL; xattr++) {
> + err = shmem_xattr_alloc(xattr->value_len, &new_xattr);
> + if (err < 0)
> + return err;
> +
> + len = strlen(xattr->name) + 1;
> + new_xattr->name = kmalloc(XATTR_SECURITY_PREFIX_LEN + len,
> + GFP_KERNEL);
> + if (new_xattr->name == NULL) {
> + kfree(new_xattr);
> + return -ENOMEM;
> + }
> +
> + memcpy(new_xattr->name, XATTR_SECURITY_PREFIX,
> + XATTR_SECURITY_PREFIX_LEN);
> + memcpy(new_xattr->name + XATTR_SECURITY_PREFIX_LEN,
> + xattr->name, len);
> + memcpy(new_xattr->value, xattr->value, xattr->value_len);
> +
> + spin_lock(&info->lock);
> + list_add(&new_xattr->list, &info->xattr_list);
> + spin_unlock(&info->lock);
> + }
> +
> + return 0;
> +}
> +
> +/*
> * File creation. Allocate an inode, and we're done..
> */
> static int
> @@ -1490,7 +1548,7 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
> if (inode) {
> error = security_inode_init_security(inode, dir,
> &dentry->d_name,
> - NULL, NULL);
> + &shmem_initxattrs, NULL);
> if (error) {
> if (error != -EOPNOTSUPP) {
> iput(inode);
> @@ -1630,7 +1688,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
> return -ENOSPC;
>
> error = security_inode_init_security(inode, dir, &dentry->d_name,
> - NULL, NULL);
> + &shmem_initxattrs, NULL);
> if (error) {
> if (error != -EOPNOTSUPP) {
> iput(inode);
> @@ -1731,26 +1789,19 @@ static int shmem_xattr_get(struct dentry *dentry, const char *name,
> return ret;
> }
>
> -static int shmem_xattr_set(struct dentry *dentry, const char *name,
> +static int shmem_xattr_set(struct inode *inode, const char *name,
> const void *value, size_t size, int 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;
> + err = shmem_xattr_alloc(size, &new_xattr);
> + if (err < 0)
> + return err;
>
> new_xattr->name = kstrdup(name, GFP_KERNEL);
> if (!new_xattr->name) {
> @@ -1758,7 +1809,6 @@ static int shmem_xattr_set(struct dentry *dentry, const char *name,
> return -ENOMEM;
> }
>
> - new_xattr->size = size;
> memcpy(new_xattr->value, value, size);
> }
>
> @@ -1858,7 +1908,7 @@ static int shmem_setxattr(struct dentry *dentry, const char *name,
> if (size == 0)
> value = ""; /* empty EA, do not remove */
>
> - return shmem_xattr_set(dentry, name, value, size, flags);
> + return shmem_xattr_set(dentry->d_inode, name, value, size, flags);
>
> }
>
> @@ -1878,7 +1928,7 @@ static int shmem_removexattr(struct dentry *dentry, const char *name)
> if (err)
> return err;
>
> - return shmem_xattr_set(dentry, name, NULL, 0, XATTR_REPLACE);
> + return shmem_xattr_set(dentry->d_inode, name, NULL, 0, XATTR_REPLACE);
> }
>
> static bool xattr_is_trusted(const char *name)
> --
> 1.7.5.4
>
> --
> To unsubscribe, send a message with 'unsubscribe linux-mm' in
> the body to [email protected]. For more info on Linux MM,
> see: http://www.linux-mm.org/ .
> Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
> Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
>

--
James Morris
<[email protected]>

2012-02-25 03:19:55

by Hugh Dickins

[permalink] [raw]
Subject: Re: [PATCH] tmpfs: security xattr setting on inode creation

Thanks a lot for doing this, Jarkko: I knew nothing about it.
And thank you James for reviewing, I felt much happier seeing that.

I did fiddle around with it slightly, to reduce the added textsize,
and eliminate it when CONFIG_TMPFS_XATTR is off. Please, Jarkko
and James, complain bitterly if I've messed up the good work.

[PATCH] tmpfs: security xattr setting on inode creation

From: Jarkko Sakkinen <[email protected]>

Adds to generic xattr support introduced in Linux 3.0 by
implementing initxattrs callback. This enables consulting
of security attributes from LSM and EVM when inode is created.

[hughd: moved under CONFIG_TMPFS_XATTR, with memcpy in shmem_xattr_alloc]

Signed-off-by: Jarkko Sakkinen <[email protected]>
Reviewed-by: James Morris <[email protected]>
Signed-off-by: Hugh Dickins <[email protected]>
---
mm/shmem.c | 88 +++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 72 insertions(+), 16 deletions(-)

--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1178,6 +1178,12 @@ static struct inode *shmem_get_inode(str
static const struct inode_operations shmem_symlink_inode_operations;
static const struct inode_operations shmem_short_symlink_operations;

+#ifdef CONFIG_TMPFS_XATTR
+static int shmem_initxattrs(struct inode *, const struct xattr *, void *);
+#else
+#define shmem_initxattrs NULL
+#endif
+
static int
shmem_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
@@ -1490,7 +1496,7 @@ shmem_mknod(struct inode *dir, struct de
if (inode) {
error = security_inode_init_security(inode, dir,
&dentry->d_name,
- NULL, NULL);
+ shmem_initxattrs, NULL);
if (error) {
if (error != -EOPNOTSUPP) {
iput(inode);
@@ -1630,7 +1636,7 @@ static int shmem_symlink(struct inode *d
return -ENOSPC;

error = security_inode_init_security(inode, dir, &dentry->d_name,
- NULL, NULL);
+ shmem_initxattrs, NULL);
if (error) {
if (error != -EOPNOTSUPP) {
iput(inode);
@@ -1704,6 +1710,66 @@ static void shmem_put_link(struct dentry
* filesystem level, though.
*/

+/*
+ * Allocate new xattr and copy in the value; but leave the name to callers.
+ */
+static struct shmem_xattr *shmem_xattr_alloc(const void *value, size_t size)
+{
+ struct shmem_xattr *new_xattr;
+ size_t len;
+
+ /* wrap around? */
+ len = sizeof(*new_xattr) + size;
+ if (len <= sizeof(*new_xattr))
+ return NULL;
+
+ new_xattr = kmalloc(len, GFP_KERNEL);
+ if (!new_xattr)
+ return NULL;
+
+ new_xattr->size = size;
+ memcpy(new_xattr->value, value, size);
+ return new_xattr;
+}
+
+/*
+ * Callback for security_inode_init_security() for acquiring xattrs.
+ */
+static int shmem_initxattrs(struct inode *inode,
+ const struct xattr *xattr_array,
+ void *fs_info)
+{
+ struct shmem_inode_info *info = SHMEM_I(inode);
+ const struct xattr *xattr;
+ struct shmem_xattr *new_xattr;
+ size_t len;
+
+ for (xattr = xattr_array; xattr->name != NULL; xattr++) {
+ new_xattr = shmem_xattr_alloc(xattr->value, xattr->value_len);
+ if (!new_xattr)
+ return -ENOMEM;
+
+ len = strlen(xattr->name) + 1;
+ new_xattr->name = kmalloc(XATTR_SECURITY_PREFIX_LEN + len,
+ GFP_KERNEL);
+ if (!new_xattr->name) {
+ kfree(new_xattr);
+ return -ENOMEM;
+ }
+
+ memcpy(new_xattr->name, XATTR_SECURITY_PREFIX,
+ XATTR_SECURITY_PREFIX_LEN);
+ memcpy(new_xattr->name + XATTR_SECURITY_PREFIX_LEN,
+ xattr->name, len);
+
+ spin_lock(&info->lock);
+ list_add(&new_xattr->list, &info->xattr_list);
+ spin_unlock(&info->lock);
+ }
+
+ return 0;
+}
+
static int shmem_xattr_get(struct dentry *dentry, const char *name,
void *buffer, size_t size)
{
@@ -1731,24 +1797,17 @@ static int shmem_xattr_get(struct dentry
return ret;
}

-static int shmem_xattr_set(struct dentry *dentry, const char *name,
+static int shmem_xattr_set(struct inode *inode, const char *name,
const void *value, size_t size, int 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);
+ new_xattr = shmem_xattr_alloc(value, size);
if (!new_xattr)
return -ENOMEM;

@@ -1757,9 +1816,6 @@ static int shmem_xattr_set(struct dentry
kfree(new_xattr);
return -ENOMEM;
}
-
- new_xattr->size = size;
- memcpy(new_xattr->value, value, size);
}

spin_lock(&info->lock);
@@ -1858,7 +1914,7 @@ static int shmem_setxattr(struct dentry
if (size == 0)
value = ""; /* empty EA, do not remove */

- return shmem_xattr_set(dentry, name, value, size, flags);
+ return shmem_xattr_set(dentry->d_inode, name, value, size, flags);

}

@@ -1878,7 +1934,7 @@ static int shmem_removexattr(struct dent
if (err)
return err;

- return shmem_xattr_set(dentry, name, NULL, 0, XATTR_REPLACE);
+ return shmem_xattr_set(dentry->d_inode, name, NULL, 0, XATTR_REPLACE);
}

static bool xattr_is_trusted(const char *name)

2012-02-25 07:03:43

by Sakkinen, Jarkko

[permalink] [raw]
Subject: Re: [PATCH] tmpfs: security xattr setting on inode creation

Hi Hugh,

On Sat, Feb 25, 2012 at 5:19 AM, Hugh Dickins <[email protected]> wrote:
> Thanks a lot for doing this, Jarkko: I knew nothing about it.
> And thank you James for reviewing, I felt much happier seeing that.
>
> I did fiddle around with it slightly, to reduce the added textsize,
> and eliminate it when CONFIG_TMPFS_XATTR is off.  Please, Jarkko
> and James, complain bitterly if I've messed up the good work.

Thank you for the nice feedback :) LGTM.

>
> [PATCH] tmpfs: security xattr setting on inode creation
>
> From: Jarkko Sakkinen <[email protected]>
>
> Adds to generic xattr support introduced in Linux 3.0 by
> implementing initxattrs callback. This enables consulting
> of security attributes from LSM and EVM when inode is created.
>
> [hughd: moved under CONFIG_TMPFS_XATTR, with memcpy in shmem_xattr_alloc]
>
> Signed-off-by: Jarkko Sakkinen <[email protected]>
> Reviewed-by: James Morris <[email protected]>
> Signed-off-by: Hugh Dickins <[email protected]>
> ---
>  mm/shmem.c |   88 +++++++++++++++++++++++++++++++++++++++++----------
>  1 file changed, 72 insertions(+), 16 deletions(-)
>
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -1178,6 +1178,12 @@ static struct inode *shmem_get_inode(str
>  static const struct inode_operations shmem_symlink_inode_operations;
>  static const struct inode_operations shmem_short_symlink_operations;
>
> +#ifdef CONFIG_TMPFS_XATTR
> +static int shmem_initxattrs(struct inode *, const struct xattr *, void *);
> +#else
> +#define shmem_initxattrs NULL
> +#endif
> +
>  static int
>  shmem_write_begin(struct file *file, struct address_space *mapping,
>                        loff_t pos, unsigned len, unsigned flags,
> @@ -1490,7 +1496,7 @@ shmem_mknod(struct inode *dir, struct de
>        if (inode) {
>                error = security_inode_init_security(inode, dir,
>                                                     &dentry->d_name,
> -                                                    NULL, NULL);
> +                                                    shmem_initxattrs, NULL);
>                if (error) {
>                        if (error != -EOPNOTSUPP) {
>                                iput(inode);
> @@ -1630,7 +1636,7 @@ static int shmem_symlink(struct inode *d
>                return -ENOSPC;
>
>        error = security_inode_init_security(inode, dir, &dentry->d_name,
> -                                            NULL, NULL);
> +                                            shmem_initxattrs, NULL);
>        if (error) {
>                if (error != -EOPNOTSUPP) {
>                        iput(inode);
> @@ -1704,6 +1710,66 @@ static void shmem_put_link(struct dentry
>  * filesystem level, though.
>  */
>
> +/*
> + * Allocate new xattr and copy in the value; but leave the name to callers.
> + */
> +static struct shmem_xattr *shmem_xattr_alloc(const void *value, size_t size)
> +{
> +       struct shmem_xattr *new_xattr;
> +       size_t len;
> +
> +       /* wrap around? */
> +       len = sizeof(*new_xattr) + size;
> +       if (len <= sizeof(*new_xattr))
> +               return NULL;
> +
> +       new_xattr = kmalloc(len, GFP_KERNEL);
> +       if (!new_xattr)
> +               return NULL;
> +
> +       new_xattr->size = size;
> +       memcpy(new_xattr->value, value, size);
> +       return new_xattr;
> +}
> +
> +/*
> + * Callback for security_inode_init_security() for acquiring xattrs.
> + */
> +static int shmem_initxattrs(struct inode *inode,
> +                           const struct xattr *xattr_array,
> +                           void *fs_info)
> +{
> +       struct shmem_inode_info *info = SHMEM_I(inode);
> +       const struct xattr *xattr;
> +       struct shmem_xattr *new_xattr;
> +       size_t len;
> +
> +       for (xattr = xattr_array; xattr->name != NULL; xattr++) {
> +               new_xattr = shmem_xattr_alloc(xattr->value, xattr->value_len);
> +               if (!new_xattr)
> +                       return -ENOMEM;
> +
> +               len = strlen(xattr->name) + 1;
> +               new_xattr->name = kmalloc(XATTR_SECURITY_PREFIX_LEN + len,
> +                                         GFP_KERNEL);
> +               if (!new_xattr->name) {
> +                       kfree(new_xattr);
> +                       return -ENOMEM;
> +               }
> +
> +               memcpy(new_xattr->name, XATTR_SECURITY_PREFIX,
> +                      XATTR_SECURITY_PREFIX_LEN);
> +               memcpy(new_xattr->name + XATTR_SECURITY_PREFIX_LEN,
> +                      xattr->name, len);
> +
> +               spin_lock(&info->lock);
> +               list_add(&new_xattr->list, &info->xattr_list);
> +               spin_unlock(&info->lock);
> +       }
> +
> +       return 0;
> +}
> +
>  static int shmem_xattr_get(struct dentry *dentry, const char *name,
>                           void *buffer, size_t size)
>  {
> @@ -1731,24 +1797,17 @@ static int shmem_xattr_get(struct dentry
>        return ret;
>  }
>
> -static int shmem_xattr_set(struct dentry *dentry, const char *name,
> +static int shmem_xattr_set(struct inode *inode, const char *name,
>                           const void *value, size_t size, int 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);
> +               new_xattr = shmem_xattr_alloc(value, size);
>                if (!new_xattr)
>                        return -ENOMEM;
>
> @@ -1757,9 +1816,6 @@ static int shmem_xattr_set(struct dentry
>                        kfree(new_xattr);
>                        return -ENOMEM;
>                }
> -
> -               new_xattr->size = size;
> -               memcpy(new_xattr->value, value, size);
>        }
>
>        spin_lock(&info->lock);
> @@ -1858,7 +1914,7 @@ static int shmem_setxattr(struct dentry
>        if (size == 0)
>                value = "";  /* empty EA, do not remove */
>
> -       return shmem_xattr_set(dentry, name, value, size, flags);
> +       return shmem_xattr_set(dentry->d_inode, name, value, size, flags);
>
>  }
>
> @@ -1878,7 +1934,7 @@ static int shmem_removexattr(struct dent
>        if (err)
>                return err;
>
> -       return shmem_xattr_set(dentry, name, NULL, 0, XATTR_REPLACE);
> +       return shmem_xattr_set(dentry->d_inode, name, NULL, 0, XATTR_REPLACE);
>  }
>
>  static bool xattr_is_trusted(const char *name)

/Jarkko
????{.n?+???????+%?????ݶ??w??{.n?+????{??G?????{ay?ʇڙ?,j??f???h?????????z_??(?階?ݢj"???m??????G????????????&???~???iO???z??v?^?m???? ????????I?

2012-02-27 22:46:08

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH] tmpfs: security xattr setting on inode creation

On Fri, 24 Feb 2012 19:19:22 -0800 (PST)
Hugh Dickins <[email protected]> wrote:

> +/*
> + * Callback for security_inode_init_security() for acquiring xattrs.
> + */
> +static int shmem_initxattrs(struct inode *inode,
> + const struct xattr *xattr_array,
> + void *fs_info)
> +{
> + struct shmem_inode_info *info = SHMEM_I(inode);
> + const struct xattr *xattr;
> + struct shmem_xattr *new_xattr;
> + size_t len;
> +
> + for (xattr = xattr_array; xattr->name != NULL; xattr++) {
> + new_xattr = shmem_xattr_alloc(xattr->value, xattr->value_len);
> + if (!new_xattr)
> + return -ENOMEM;
> +
> + len = strlen(xattr->name) + 1;
> + new_xattr->name = kmalloc(XATTR_SECURITY_PREFIX_LEN + len,
> + GFP_KERNEL);
> + if (!new_xattr->name) {
> + kfree(new_xattr);
> + return -ENOMEM;
> + }
> +
> + memcpy(new_xattr->name, XATTR_SECURITY_PREFIX,
> + XATTR_SECURITY_PREFIX_LEN);
> + memcpy(new_xattr->name + XATTR_SECURITY_PREFIX_LEN,
> + xattr->name, len);
> +
> + spin_lock(&info->lock);
> + list_add(&new_xattr->list, &info->xattr_list);
> + spin_unlock(&info->lock);
> + }
> +
> + return 0;
> +}

So if there's a kmalloc failure partway through the array, we leave a
partially xattrified inode in place.

Are we sure this is OK?

2012-02-28 03:46:36

by Ware, Ryan R

[permalink] [raw]
Subject: Re: [PATCH] tmpfs: security xattr setting on inode creation

On Tue, Feb 28, 2012 at 7:46 AM, Andrew Morton
<[email protected]> wrote:
>
> On Fri, 24 Feb 2012 19:19:22 -0800 (PST)
> Hugh Dickins <[email protected]> wrote:
>
> > +/*
> > + * Callback for security_inode_init_security() for acquiring xattrs.
> > + */
> > +static int shmem_initxattrs(struct inode *inode,
> > + ? ? ? ? ? ? ? ? ? ? ? ? const struct xattr *xattr_array,
> > + ? ? ? ? ? ? ? ? ? ? ? ? void *fs_info)
> > +{
> > + ? ? struct shmem_inode_info *info = SHMEM_I(inode);
> > + ? ? const struct xattr *xattr;
> > + ? ? struct shmem_xattr *new_xattr;
> > + ? ? size_t len;
> > +
> > + ? ? for (xattr = xattr_array; xattr->name != NULL; xattr++) {
> > + ? ? ? ? ? ? new_xattr = shmem_xattr_alloc(xattr->value,
> > xattr->value_len);
> > + ? ? ? ? ? ? if (!new_xattr)
> > + ? ? ? ? ? ? ? ? ? ? return -ENOMEM;
> > +
> > + ? ? ? ? ? ? len = strlen(xattr->name) + 1;
> > + ? ? ? ? ? ? new_xattr->name = kmalloc(XATTR_SECURITY_PREFIX_LEN + len,
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? GFP_KERNEL);
> > + ? ? ? ? ? ? if (!new_xattr->name) {
> > + ? ? ? ? ? ? ? ? ? ? kfree(new_xattr);
> > + ? ? ? ? ? ? ? ? ? ? return -ENOMEM;
> > + ? ? ? ? ? ? }
> > +
> > + ? ? ? ? ? ? memcpy(new_xattr->name, XATTR_SECURITY_PREFIX,
> > + ? ? ? ? ? ? ? ? ? ?XATTR_SECURITY_PREFIX_LEN);
> > + ? ? ? ? ? ? memcpy(new_xattr->name + XATTR_SECURITY_PREFIX_LEN,
> > + ? ? ? ? ? ? ? ? ? ?xattr->name, len);
> > +
> > + ? ? ? ? ? ? spin_lock(&info->lock);
> > + ? ? ? ? ? ? list_add(&new_xattr->list, &info->xattr_list);
> > + ? ? ? ? ? ? spin_unlock(&info->lock);
> > + ? ? }
> > +
> > + ? ? return 0;
> > +}
>
> So if there's a kmalloc failure partway through the array, we leave a
> partially xattrified inode in place.
>
> Are we sure this is OK?

I'm guessing Jarkko can clean that up a bit. It wouldn't be a good
idea to leave inaccurate data structures laying around during failure
cases.

Ryan

2012-02-28 04:11:30

by Hugh Dickins

[permalink] [raw]
Subject: Re: [PATCH] tmpfs: security xattr setting on inode creation

On Tue, 28 Feb 2012, Ware, Ryan R wrote:
> On Tue, Feb 28, 2012 at 7:46 AM, Andrew Morton <[email protected]>wrote:
> > On Fri, 24 Feb 2012 19:19:22 -0800 (PST)
> > Hugh Dickins <[email protected]> wrote:
> >...
> > > + if (!new_xattr->name) {
> > > + kfree(new_xattr);
> > > + return -ENOMEM;
> > > + }
> > > +
> > > + memcpy(new_xattr->name, XATTR_SECURITY_PREFIX,
> > > + XATTR_SECURITY_PREFIX_LEN);
> > > + memcpy(new_xattr->name + XATTR_SECURITY_PREFIX_LEN,
> > > + xattr->name, len);
> > > +
> > > + spin_lock(&info->lock);
> > > + list_add(&new_xattr->list, &info->xattr_list);
> > > + spin_unlock(&info->lock);
> > > + }
> > > +
> > > + return 0;
> > > +}
> >
> > So if there's a kmalloc failure partway through the array, we leave a
> > partially xattrified inode in place.
> >
> > Are we sure this is OK?
> >
>
> I'm guessing Jarkko can clean that up a bit. It wouldn't be a good idea to
> leave inaccurate data structures laying around during failure cases.

Andrew raises a good concern, but Jarkko got it just right and no
change is needed: any xattrs already allocated are properly linked
on info->xattr_list, then when security_inode_init_security() fails
(with an error other than EOPNOTSUPP) the failing inode is iput(),
which ends up in shmem_evict_inode(), which kfree()s those xattrs
(and their names) on info->xattr_list.

Hugh

2012-02-28 05:51:28

by Sakkinen, Jarkko

[permalink] [raw]
Subject: Re: [PATCH] tmpfs: security xattr setting on inode creation

On Tue, Feb 28, 2012 at 6:10 AM, Hugh Dickins <[email protected]> wrote:
> On Tue, 28 Feb 2012, Ware, Ryan R wrote:
>> On Tue, Feb 28, 2012 at 7:46 AM, Andrew Morton <[email protected]>wrote:
>> > On Fri, 24 Feb 2012 19:19:22 -0800 (PST)
>> > Hugh Dickins <[email protected]> wrote:
>> >...
>> > > +             if (!new_xattr->name) {
>> > > +                     kfree(new_xattr);
>> > > +                     return -ENOMEM;
>> > > +             }
>> > > +
>> > > +             memcpy(new_xattr->name, XATTR_SECURITY_PREFIX,
>> > > +                    XATTR_SECURITY_PREFIX_LEN);
>> > > +             memcpy(new_xattr->name + XATTR_SECURITY_PREFIX_LEN,
>> > > +                    xattr->name, len);
>> > > +
>> > > +             spin_lock(&info->lock);
>> > > +             list_add(&new_xattr->list, &info->xattr_list);
>> > > +             spin_unlock(&info->lock);
>> > > +     }
>> > > +
>> > > +     return 0;
>> > > +}
>> >
>> > So if there's a kmalloc failure partway through the array, we leave a
>> > partially xattrified inode in place.
>> >
>> > Are we sure this is OK?
>> >
>>
>> I'm guessing Jarkko can clean that up a bit.  It wouldn't be a good idea to
>> leave inaccurate data structures laying around during failure cases.
>
> Andrew raises a good concern, but Jarkko got it just right and no
> change is needed: any xattrs already allocated are properly linked
> on info->xattr_list, then when security_inode_init_security() fails
> (with an error other than EOPNOTSUPP) the failing inode is iput(),
> which ends up in shmem_evict_inode(), which kfree()s those xattrs
> (and their names) on info->xattr_list.

Yeah, that's how I understood it too. These the are places where
security_inode_init_security() is called:

- http://lxr.free-electrons.com/source/mm/shmem.c#L1459
- http://lxr.free-electrons.com/source/mm/shmem.c#L1590

>
> Hugh

/Jarkko