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
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]>
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)
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?
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?
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
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
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