|
@@ -321,6 +321,7 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value,
|
|
{
|
|
{
|
|
int error;
|
|
int error;
|
|
void *kvalue = NULL;
|
|
void *kvalue = NULL;
|
|
|
|
+ void *vvalue = NULL; /* If non-NULL, we used vmalloc() */
|
|
char kname[XATTR_NAME_MAX + 1];
|
|
char kname[XATTR_NAME_MAX + 1];
|
|
|
|
|
|
if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
|
|
if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
|
|
@@ -335,13 +336,25 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value,
|
|
if (size) {
|
|
if (size) {
|
|
if (size > XATTR_SIZE_MAX)
|
|
if (size > XATTR_SIZE_MAX)
|
|
return -E2BIG;
|
|
return -E2BIG;
|
|
- kvalue = memdup_user(value, size);
|
|
|
|
- if (IS_ERR(kvalue))
|
|
|
|
- return PTR_ERR(kvalue);
|
|
|
|
|
|
+ kvalue = kmalloc(size, GFP_KERNEL | __GFP_NOWARN);
|
|
|
|
+ if (!kvalue) {
|
|
|
|
+ vvalue = vmalloc(size);
|
|
|
|
+ if (!vvalue)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ kvalue = vvalue;
|
|
|
|
+ }
|
|
|
|
+ if (copy_from_user(kvalue, value, size)) {
|
|
|
|
+ error = -EFAULT;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
error = vfs_setxattr(d, kname, kvalue, size, flags);
|
|
error = vfs_setxattr(d, kname, kvalue, size, flags);
|
|
- kfree(kvalue);
|
|
|
|
|
|
+out:
|
|
|
|
+ if (vvalue)
|
|
|
|
+ vfree(vvalue);
|
|
|
|
+ else
|
|
|
|
+ kfree(kvalue);
|
|
return error;
|
|
return error;
|
|
}
|
|
}
|
|
|
|
|