Commit 0b7b8704 authored by Hao Sun's avatar Hao Sun Committed by Andrew Morton

mm: new primitive kvmemdup()

Similar to kmemdup(), but support large amount of bytes with kvmalloc()
and does *not* guarantee that the result will be physically contiguous. 
Use only in cases where kvmalloc() is needed and free it with kvfree(). 
Also adapt policy_unpack.c in case someone bisect into this.

Link: https://lkml.kernel.org/r/20221221144245.27164-1-sunhao.th@gmail.comSigned-off-by: default avatarHao Sun <sunhao.th@gmail.com>
Suggested-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Cc: Nick Terrell <terrelln@fb.com>
Cc: John Johansen <john.johansen@canonical.com>
Cc: Paul Moore <paul@paul-moore.com>
Cc: James Morris <jmorris@namei.org>
Cc: "Serge E. Hallyn" <serge@hallyn.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 5a9e3474
...@@ -177,6 +177,7 @@ extern char *kstrdup(const char *s, gfp_t gfp) __malloc; ...@@ -177,6 +177,7 @@ extern char *kstrdup(const char *s, gfp_t gfp) __malloc;
extern const char *kstrdup_const(const char *s, gfp_t gfp); extern const char *kstrdup_const(const char *s, gfp_t gfp);
extern char *kstrndup(const char *s, size_t len, gfp_t gfp); extern char *kstrndup(const char *s, size_t len, gfp_t gfp);
extern void *kmemdup(const void *src, size_t len, gfp_t gfp) __realloc_size(2); extern void *kmemdup(const void *src, size_t len, gfp_t gfp) __realloc_size(2);
extern void *kvmemdup(const void *src, size_t len, gfp_t gfp) __realloc_size(2);
extern char *kmemdup_nul(const char *s, size_t len, gfp_t gfp); extern char *kmemdup_nul(const char *s, size_t len, gfp_t gfp);
extern char **argv_split(gfp_t gfp, const char *str, int *argcp); extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
......
...@@ -120,7 +120,8 @@ EXPORT_SYMBOL(kstrndup); ...@@ -120,7 +120,8 @@ EXPORT_SYMBOL(kstrndup);
* @len: memory region length * @len: memory region length
* @gfp: GFP mask to use * @gfp: GFP mask to use
* *
* Return: newly allocated copy of @src or %NULL in case of error * Return: newly allocated copy of @src or %NULL in case of error,
* result is physically contiguous. Use kfree() to free.
*/ */
void *kmemdup(const void *src, size_t len, gfp_t gfp) void *kmemdup(const void *src, size_t len, gfp_t gfp)
{ {
...@@ -133,6 +134,27 @@ void *kmemdup(const void *src, size_t len, gfp_t gfp) ...@@ -133,6 +134,27 @@ void *kmemdup(const void *src, size_t len, gfp_t gfp)
} }
EXPORT_SYMBOL(kmemdup); EXPORT_SYMBOL(kmemdup);
/**
* kvmemdup - duplicate region of memory
*
* @src: memory region to duplicate
* @len: memory region length
* @gfp: GFP mask to use
*
* Return: newly allocated copy of @src or %NULL in case of error,
* result may be not physically contiguous. Use kvfree() to free.
*/
void *kvmemdup(const void *src, size_t len, gfp_t gfp)
{
void *p;
p = kvmalloc(len, gfp);
if (p)
memcpy(p, src, len);
return p;
}
EXPORT_SYMBOL(kvmemdup);
/** /**
* kmemdup_nul - Create a NUL-terminated string from unterminated data * kmemdup_nul - Create a NUL-terminated string from unterminated data
* @s: The data to stringify * @s: The data to stringify
......
...@@ -161,15 +161,6 @@ VISIBLE_IF_KUNIT bool aa_inbounds(struct aa_ext *e, size_t size) ...@@ -161,15 +161,6 @@ VISIBLE_IF_KUNIT bool aa_inbounds(struct aa_ext *e, size_t size)
} }
EXPORT_SYMBOL_IF_KUNIT(aa_inbounds); EXPORT_SYMBOL_IF_KUNIT(aa_inbounds);
static void *kvmemdup(const void *src, size_t len)
{
void *p = kvmalloc(len, GFP_KERNEL);
if (p)
memcpy(p, src, len);
return p;
}
/** /**
* aa_unpack_u16_chunk - test and do bounds checking for a u16 size based chunk * aa_unpack_u16_chunk - test and do bounds checking for a u16 size based chunk
* @e: serialized data read head (NOT NULL) * @e: serialized data read head (NOT NULL)
...@@ -1027,7 +1018,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) ...@@ -1027,7 +1018,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
data->key = key; data->key = key;
data->size = aa_unpack_blob(e, &data->data, NULL); data->size = aa_unpack_blob(e, &data->data, NULL);
data->data = kvmemdup(data->data, data->size); data->data = kvmemdup(data->data, data->size, GFP_KERNEL);
if (data->size && !data->data) { if (data->size && !data->data) {
kfree_sensitive(data->key); kfree_sensitive(data->key);
kfree_sensitive(data); kfree_sensitive(data);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment