2007-05-11 19:10:51

by Jeremy Fitzhardinge

[permalink] [raw]
Subject: [patch 3/7] add kstrndup

Add a kstrndup function, modelled on strndup. Like strndup this
returns a string copied into its own allocated memory, but it copies
no more than the specified number of bytes from the source.

Remove private strndup() from irda code.

Signed-off-by: Jeremy Fitzhardinge <[email protected]>
Cc: Chris Wright <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Randy Dunlap <[email protected]>
Cc: YOSHIFUJI Hideaki <[email protected]>
Cc: Akinobu Mita <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Al Viro <[email protected]>
Cc: Panagiotis Issaris <[email protected]>

---
include/linux/string.h | 1 +
mm/util.c | 30 +++++++++++++++++++++++++++---
net/irda/irias_object.c | 43 +++++--------------------------------------
3 files changed, 33 insertions(+), 41 deletions(-)

===================================================================
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -105,6 +105,7 @@ extern void * memchr(const void *,int,__
#endif

extern char *kstrdup(const char *s, 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);

#ifdef __cplusplus
===================================================================
--- a/mm/util.c
+++ b/mm/util.c
@@ -18,9 +18,8 @@ void *__kzalloc(size_t size, gfp_t flags
}
EXPORT_SYMBOL(__kzalloc);

-/*
+/**
* kstrdup - allocate space for and copy an existing string
- *
* @s: the string to duplicate
* @gfp: the GFP mask used in the kmalloc() call when allocating memory
*/
@@ -39,6 +38,32 @@ char *kstrdup(const char *s, gfp_t gfp)
return buf;
}
EXPORT_SYMBOL(kstrdup);
+
+/**
+ * kstrndup - allocate space for and copy an existing string
+ * @s: the string to duplicate
+ * @max: read at most @max chars from @s
+ * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ */
+char *kstrndup(const char *s, size_t max, gfp_t gfp)
+{
+ size_t len;
+ char *buf;
+
+ if (!s)
+ return NULL;
+
+ len = strlen(s);
+ if (len > max)
+ len = max;
+ buf = kmalloc_track_caller(len+1, gfp);
+ if (buf) {
+ memcpy(buf, s, len);
+ buf[len] = '\0';
+ }
+ return buf;
+}
+EXPORT_SYMBOL(kstrndup);

/**
* kmemdup - duplicate region of memory
@@ -60,7 +85,6 @@ EXPORT_SYMBOL(kmemdup);

/*
* strndup_user - duplicate an existing string from user space
- *
* @s: The string to duplicate
* @n: Maximum number of bytes to copy, including the trailing NUL.
*/
===================================================================
--- a/net/irda/irias_object.c
+++ b/net/irda/irias_object.c
@@ -36,39 +36,6 @@ hashbin_t *irias_objects;
*/
struct ias_value irias_missing = { IAS_MISSING, 0, 0, 0, {0}};

-/*
- * Function strndup (str, max)
- *
- * My own kernel version of strndup!
- *
- * Faster, check boundary... Jean II
- */
-static char *strndup(char *str, size_t max)
-{
- char *new_str;
- int len;
-
- /* Check string */
- if (str == NULL)
- return NULL;
- /* Check length, truncate */
- len = strlen(str);
- if(len > max)
- len = max;
-
- /* Allocate new string */
- new_str = kmalloc(len + 1, GFP_ATOMIC);
- if (new_str == NULL) {
- IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
- return NULL;
- }
-
- /* Copy and truncate */
- memcpy(new_str, str, len);
- new_str[len] = '\0';
-
- return new_str;
-}

/*
* Function ias_new_object (name, id)
@@ -90,7 +57,7 @@ struct ias_object *irias_new_object( cha
}

obj->magic = IAS_OBJECT_MAGIC;
- obj->name = strndup(name, IAS_MAX_CLASSNAME);
+ obj->name = kstrndup(name, IAS_MAX_CLASSNAME, GFP_ATOMIC);
if (!obj->name) {
IRDA_WARNING("%s(), Unable to allocate name!\n",
__FUNCTION__);
@@ -360,7 +327,7 @@ void irias_add_integer_attrib(struct ias
}

attrib->magic = IAS_ATTRIB_MAGIC;
- attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
+ attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC);

/* Insert value */
attrib->value = irias_new_integer_value(value);
@@ -404,7 +371,7 @@ void irias_add_octseq_attrib(struct ias_
}

attrib->magic = IAS_ATTRIB_MAGIC;
- attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
+ attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC);

attrib->value = irias_new_octseq_value( octets, len);
if (!attrib->name || !attrib->value) {
@@ -446,7 +413,7 @@ void irias_add_string_attrib(struct ias_
}

attrib->magic = IAS_ATTRIB_MAGIC;
- attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
+ attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC);

attrib->value = irias_new_string_value(value);
if (!attrib->name || !attrib->value) {
@@ -506,7 +473,7 @@ struct ias_value *irias_new_string_value

value->type = IAS_STRING;
value->charset = CS_ASCII;
- value->t.string = strndup(string, IAS_MAX_STRING);
+ value->t.string = kstrndup(string, IAS_MAX_STRING, GFP_ATOMIC);
if (!value->t.string) {
IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
kfree(value);

--


2007-05-11 20:52:55

by René Scharfe

[permalink] [raw]
Subject: Re: [patch 3/7] add kstrndup

> + len = strlen(s);
> + if (len > max)
> + len = max;

You can avoid to run beyond max and save two lines by using strnlen:

len = strnlen(s, max);

Ren?

2007-05-11 21:18:49

by Jeremy Fitzhardinge

[permalink] [raw]
Subject: Re: [patch 3/7] add kstrndup

Ren? Scharfe wrote:
>> + len = strlen(s);
>> + if (len > max)
>> + len = max;
>>
>
> You can avoid to run beyond max and save two lines by using strnlen:
>
> len = strnlen(s, max);
>

OK. Didn't know about strnlen.

Subject: Use strnlen in kstrndup

strnlen prevents over-reading the input.

Signed-off-by: Jeremy Fitzhardinge <[email protected]>
Cc: Ren? Scharfe <[email protected]>

---
mm/util.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)

===================================================================
--- a/mm/util.c
+++ b/mm/util.c
@@ -53,9 +53,7 @@ char *kstrndup(const char *s, size_t max
if (!s)
return NULL;

- len = strlen(s);
- if (len > max)
- len = max;
+ len = strnlen(s, max);
buf = kmalloc_track_caller(len+1, gfp);
if (buf) {
memcpy(buf, s, len);