Skip to contentSkip to conversation

kernel: use kcalloc instead kmalloc/memset

PATCH In review Pekka Enberg 9 participants 25 messages Aug 5, 2005 – Aug 9, 2005

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 kernel: use kcalloc instead kmalloc/memset

This patch converts kernel/ to use kcalloc instead of kmalloc/memset.

---

 intermodule.c |    3 +--
 params.c      |    4 ++--
 power/pm.c    |    3 +--
 resource.c    |    3 +--
 workqueue.c   |    3 +--
 5 files changed, 6 insertions(+), 10 deletions(-)
kernel/resource.c +1 -2
Index: 2.6/kernel/resource.c
===================================================================
@@ -430,10 +430,9 @@ EXPORT_SYMBOL(adjust_resource);
  */
 struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name)
 {
-	struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
+	struct resource *res = kcalloc(1, sizeof(*res), GFP_KERNEL);
 
 	if (res) {
-		memset(res, 0, sizeof(*res));
 		res->name = name;
 		res->start = start;
 		res->end = start + n - 1;
kernel/intermodule.c +1 -2
Index: 2.6/kernel/intermodule.c
===================================================================
@@ -39,7 +39,7 @@ void inter_module_register(const char *i
 	struct list_head *tmp;
 	struct inter_module_entry *ime, *ime_new;
 
-	if (!(ime_new = kmalloc(sizeof(*ime), GFP_KERNEL))) {
+	if (!(ime_new = kcalloc(1, sizeof(*ime), GFP_KERNEL))) {
 		/* Overloaded kernel, not fatal */
 		printk(KERN_ERR
 			"Aiee, inter_module_register: cannot kmalloc entry for '%s'\n",
@@ -47,7 +47,6 @@ void inter_module_register(const char *i
 		kmalloc_failed = 1;
 		return;
 	}
-	memset(ime_new, 0, sizeof(*ime_new));
 	ime_new->im_name = im_name;
 	ime_new->owner = owner;
 	ime_new->userdata = userdata;
kernel/params.c +2 -2
Index: 2.6/kernel/params.c
===================================================================
@@ -542,8 +542,8 @@ static void __init kernel_param_sysfs_se
 {
 	struct module_kobject *mk;
 
-	mk = kmalloc(sizeof(struct module_kobject), GFP_KERNEL);
-	memset(mk, 0, sizeof(struct module_kobject));
+	mk = kcalloc(1, sizeof(struct module_kobject), GFP_KERNEL);
+	BUG_ON(!mk);
 
 	mk->mod = THIS_MODULE;
 	kobj_set_kset_s(mk, module_subsys);
kernel/power/pm.c +1 -2
Index: 2.6/kernel/power/pm.c
===================================================================
@@ -60,9 +60,8 @@ struct pm_dev *pm_register(pm_dev_t type
 			   unsigned long id,
 			   pm_callback callback)
 {
-	struct pm_dev *dev = kmalloc(sizeof(struct pm_dev), GFP_KERNEL);
+	struct pm_dev *dev = kcalloc(1, sizeof(struct pm_dev), GFP_KERNEL);
 	if (dev) {
-		memset(dev, 0, sizeof(*dev));
 		dev->type = type;
 		dev->id = id;
 		dev->callback = callback;
kernel/workqueue.c +1 -2
Index: 2.6/kernel/workqueue.c
===================================================================
@@ -310,10 +310,9 @@ struct workqueue_struct *__create_workqu
 
 	BUG_ON(strlen(name) > 10);
 
-	wq = kmalloc(sizeof(*wq), GFP_KERNEL);
+	wq = kcalloc(1, sizeof(*wq), GFP_KERNEL);
 	if (!wq)
 		return NULL;
-	memset(wq, 0, sizeof(*wq));
 
 	wq->name = name;
 	/* We don't need the distraction of CPUs appearing and vanishing. */
#1 lore raw
Quoted 3 lines · Pekka Enberg

This patch converts kernel/ to use kcalloc instead of kmalloc/memset.

grr.

Quoted 2 lines

- struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
+ struct resource *res = kcalloc(1, sizeof(*res), GFP_KERNEL);

Notice how every conversion you did passes in `1' in the first argument?

And that's going to happen again and again and again. Each callsite needlessly passing that silly third argument, adding more kernel text.

If we're going to do this, we should add a two-arg helper function first, and use that, no?

#2 lore raw

Hi Andrew,

Quoted 1 line · Pekka Enberg
Quoted 1 line

This patch converts kernel/ to use kcalloc instead of kmalloc/memset.

Quoted 1 line · Andrew Morton

grr.

I am learning grep. Please don't eat me!

Quoted 10 lines
Quoted 2 lines

- struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
+ struct resource *res = kcalloc(1, sizeof(*res), GFP_KERNEL);

Notice how every conversion you did passes in `1' in the first argument?

And that's going to happen again and again and again. Each callsite needlessly passing that silly third argument, adding more kernel text.

If we're going to do this, we should add a two-arg helper function first, and use that, no?

This was discussed some time ago [1] and here's a patch for you to do that.

Pekka

1. http://marc.theaimsgroup.com/?l=linux-kernel&m=111279001428661&w=2

[PATCH] use kzalloc instead of kmalloc/memset

This patch introduces a kzalloc wrapper and converts kernel/ to use it.

---

 include/linux/slab.h |    5 +++++
 kernel/intermodule.c |    3 +--
 kernel/params.c      |    4 ++--
 kernel/power/pm.c    |    3 +--
 kernel/resource.c    |    3 +--
 kernel/workqueue.c   |    3 +--
 6 files changed, 11 insertions(+), 10 deletions(-)
kernel/resource.c +1 -2
Index: 2.6/kernel/resource.c
===================================================================
@@ -430,10 +430,9 @@ EXPORT_SYMBOL(adjust_resource);
  */
 struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name)
 {
-	struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
+	struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
 
 	if (res) {
-		memset(res, 0, sizeof(*res));
 		res->name = name;
 		res->start = start;
 		res->end = start + n - 1;
kernel/intermodule.c +1 -2
Index: 2.6/kernel/intermodule.c
===================================================================
@@ -39,7 +39,7 @@ void inter_module_register(const char *i
 	struct list_head *tmp;
 	struct inter_module_entry *ime, *ime_new;
 
-	if (!(ime_new = kmalloc(sizeof(*ime), GFP_KERNEL))) {
+	if (!(ime_new = kzalloc(sizeof(*ime), GFP_KERNEL))) {
 		/* Overloaded kernel, not fatal */
 		printk(KERN_ERR
 			"Aiee, inter_module_register: cannot kmalloc entry for '%s'\n",
@@ -47,7 +47,6 @@ void inter_module_register(const char *i
 		kmalloc_failed = 1;
 		return;
 	}
-	memset(ime_new, 0, sizeof(*ime_new));
 	ime_new->im_name = im_name;
 	ime_new->owner = owner;
 	ime_new->userdata = userdata;
kernel/params.c +2 -2
Index: 2.6/kernel/params.c
===================================================================
@@ -542,8 +542,8 @@ static void __init kernel_param_sysfs_se
 {
 	struct module_kobject *mk;
 
-	mk = kmalloc(sizeof(struct module_kobject), GFP_KERNEL);
-	memset(mk, 0, sizeof(struct module_kobject));
+	mk = kzalloc(sizeof(struct module_kobject), GFP_KERNEL);
+	BUG_ON(!mk);
 
 	mk->mod = THIS_MODULE;
 	kobj_set_kset_s(mk, module_subsys);
kernel/power/pm.c +1 -2
Index: 2.6/kernel/power/pm.c
===================================================================
@@ -60,9 +60,8 @@ struct pm_dev *pm_register(pm_dev_t type
 			   unsigned long id,
 			   pm_callback callback)
 {
-	struct pm_dev *dev = kmalloc(sizeof(struct pm_dev), GFP_KERNEL);
+	struct pm_dev *dev = kzalloc(sizeof(struct pm_dev), GFP_KERNEL);
 	if (dev) {
-		memset(dev, 0, sizeof(*dev));
 		dev->type = type;
 		dev->id = id;
 		dev->callback = callback;
kernel/workqueue.c +1 -2
Index: 2.6/kernel/workqueue.c
===================================================================
@@ -310,10 +310,9 @@ struct workqueue_struct *__create_workqu
 
 	BUG_ON(strlen(name) > 10);
 
-	wq = kmalloc(sizeof(*wq), GFP_KERNEL);
+	wq = kzalloc(sizeof(*wq), GFP_KERNEL);
 	if (!wq)
 		return NULL;
-	memset(wq, 0, sizeof(*wq));
 
 	wq->name = name;
 	/* We don't need the distraction of CPUs appearing and vanishing. */
include/linux/slab.h +5 -0
Index: 2.6/include/linux/slab.h
===================================================================
@@ -103,6 +103,11 @@ extern void *kcalloc(size_t, size_t, uns
 extern void kfree(const void *);
 extern unsigned int ksize(const void *);
 
+static inline void *kzalloc(size_t size, unsigned int __nocast flags)
+{
+	return kcalloc(1, size, flags);
+}
+
 #ifdef CONFIG_NUMA
 extern void *kmem_cache_alloc_node(kmem_cache_t *, int flags, int node);
 extern void *kmalloc_node(size_t size, unsigned int __nocast flags, int node);
#3 lore raw
Quoted 3 lines · Pekka J Enberg

[PATCH] use kzalloc instead of kmalloc/memset

dammit, I was hoping for akpmalloc()

include/linux/slab.h extern void *kcalloc(size_t, size_t, uns · line 110

Quoted 6 lines
include/linux/slab.h +5 -0
+static inline void *kzalloc(size_t size, unsigned int __nocast flags)
+{
+	return kcalloc(1, size, flags);
+}
+

That'll generate just as much code as simply using kcalloc(1, ...). This function should be out-of-line and EXPORT_SYMBOL()ed. And kcalloc() can call it too..

#4 lore raw
Quoted 3 lines · Andrew Morton

That'll generate just as much code as simply using kcalloc(1, ...). This function should be out-of-line and EXPORT_SYMBOL()ed. And kcalloc() can call it too..

Yes, much better now. Thanks Andrew.

Pekka

[PATCH] introduce kzalloc

This patch introduces a kzalloc wrapper and converts kernel/ to use it.

---

 include/linux/slab.h |    1 +
 kernel/intermodule.c |    3 +--
 kernel/params.c      |    4 ++--
 kernel/power/pm.c    |    3 +--
 kernel/resource.c    |    3 +--
 kernel/workqueue.c   |    3 +--
 mm/slab.c            |   19 +++++++++++++++----
 7 files changed, 22 insertions(+), 14 deletions(-)
kernel/resource.c +1 -2
Index: 2.6/kernel/resource.c
===================================================================
@@ -430,10 +430,9 @@ EXPORT_SYMBOL(adjust_resource);
  */
 struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name)
 {
-	struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
+	struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
 
 	if (res) {
-		memset(res, 0, sizeof(*res));
 		res->name = name;
 		res->start = start;
 		res->end = start + n - 1;
kernel/intermodule.c +1 -2
Index: 2.6/kernel/intermodule.c
===================================================================
@@ -39,7 +39,7 @@ void inter_module_register(const char *i
 	struct list_head *tmp;
 	struct inter_module_entry *ime, *ime_new;
 
-	if (!(ime_new = kmalloc(sizeof(*ime), GFP_KERNEL))) {
+	if (!(ime_new = kzalloc(sizeof(*ime), GFP_KERNEL))) {
 		/* Overloaded kernel, not fatal */
 		printk(KERN_ERR
 			"Aiee, inter_module_register: cannot kmalloc entry for '%s'\n",
@@ -47,7 +47,6 @@ void inter_module_register(const char *i
 		kmalloc_failed = 1;
 		return;
 	}
-	memset(ime_new, 0, sizeof(*ime_new));
 	ime_new->im_name = im_name;
 	ime_new->owner = owner;
 	ime_new->userdata = userdata;
kernel/params.c +2 -2
Index: 2.6/kernel/params.c
===================================================================
@@ -542,8 +542,8 @@ static void __init kernel_param_sysfs_se
 {
 	struct module_kobject *mk;
 
-	mk = kmalloc(sizeof(struct module_kobject), GFP_KERNEL);
-	memset(mk, 0, sizeof(struct module_kobject));
+	mk = kzalloc(sizeof(struct module_kobject), GFP_KERNEL);
+	BUG_ON(!mk);
 
 	mk->mod = THIS_MODULE;
 	kobj_set_kset_s(mk, module_subsys);
kernel/power/pm.c +1 -2
Index: 2.6/kernel/power/pm.c
===================================================================
@@ -60,9 +60,8 @@ struct pm_dev *pm_register(pm_dev_t type
 			   unsigned long id,
 			   pm_callback callback)
 {
-	struct pm_dev *dev = kmalloc(sizeof(struct pm_dev), GFP_KERNEL);
+	struct pm_dev *dev = kzalloc(sizeof(struct pm_dev), GFP_KERNEL);
 	if (dev) {
-		memset(dev, 0, sizeof(*dev));
 		dev->type = type;
 		dev->id = id;
 		dev->callback = callback;
kernel/workqueue.c +1 -2
Index: 2.6/kernel/workqueue.c
===================================================================
@@ -310,10 +310,9 @@ struct workqueue_struct *__create_workqu
 
 	BUG_ON(strlen(name) > 10);
 
-	wq = kmalloc(sizeof(*wq), GFP_KERNEL);
+	wq = kzalloc(sizeof(*wq), GFP_KERNEL);
 	if (!wq)
 		return NULL;
-	memset(wq, 0, sizeof(*wq));
 
 	wq->name = name;
 	/* We don't need the distraction of CPUs appearing and vanishing. */
include/linux/slab.h +1 -0
Index: 2.6/include/linux/slab.h
===================================================================
@@ -100,6 +100,7 @@ found:
 }
 
 extern void *kcalloc(size_t, size_t, unsigned int __nocast);
+extern void *kzalloc(size_t, unsigned int __nocast);
 extern void kfree(const void *);
 extern unsigned int ksize(const void *);
 
mm/slab.c +15 -4
Index: 2.6/mm/slab.c
===================================================================
@@ -2555,6 +2555,20 @@ void kmem_cache_free(kmem_cache_t *cache
 EXPORT_SYMBOL(kmem_cache_free);
 
 /**
+ * kzalloc - allocate memory. The memory is set to zero.
+ * @size: how many bytes of memory are required.
+ * @flags: the type of memory to allocate.
+ */
+void *kzalloc(size_t size, unsigned int __nocast flags)
+{
+	void *ret = kmalloc(size, flags);
+	if (ret)
+		memset(ret, 0, size);
+	return ret;
+}
+EXPORT_SYMBOL(kzalloc);
+
+/**
  * kcalloc - allocate memory for an array. The memory is set to zero.
  * @n: number of elements.
  * @size: element size.
@@ -2567,10 +2581,7 @@ void *kcalloc(size_t n, size_t size, uns
 	if (n != 0 && size > INT_MAX / n)
 		return ret;
 
-	ret = kmalloc(n * size, flags);
-	if (ret)
-		memset(ret, 0, n * size);
-	return ret;
+	return kzalloc(n * size, flags);
 }
 EXPORT_SYMBOL(kcalloc);
 
#9 lore raw
In reply to Andrew Morton

Hi,

Quoted 9 lines · Andrew Morton

include/linux/slab.h extern void *kcalloc(size_t, size_t, uns · line 110

Quoted 5 lines
include/linux/slab.h +5 -0
+static inline void *kzalloc(size_t size, unsigned int __nocast flags)
+{
+	return kcalloc(1, size, flags);
+}
+

That'll generate just as much code as simply using kcalloc(1, ...). This function should be out-of-line and EXPORT_SYMBOL()ed. And kcalloc() can call it too..

BTW we already have 420 "kcalloc(1, ...)" user and 41 without the 1 argument, most of them are in sound, which introduced it in first place. Can we please deprecate that function before it spreads any further?

bye, Roman

#10 lore raw
Quoted 14 lines · Roman Zippel

Hi,

Quoted 9 lines · Andrew Morton

include/linux/slab.h extern void *kcalloc(size_t, size_t, uns · line 110

Quoted 5 lines
include/linux/slab.h +5 -0
+static inline void *kzalloc(size_t size, unsigned int __nocast flags)
+{
+	return kcalloc(1, size, flags);
+}
+

That'll generate just as much code as simply using kcalloc(1, ...). This function should be out-of-line and EXPORT_SYMBOL()ed. And kcalloc() can call it too..

Quoted 3 lines

BTW we already have 420 "kcalloc(1, ...)" user and 41 without the 1 argument, most of them are in sound, which introduced it in first place. Can we please deprecate that function before it spreads any further?

kcalloc does have value, in that it's a nice api to avoid multiplication overflows. Just for "1" it's indeed not the most useful API.

#11 lore raw
Quoted 2 lines · Roman Zippel
Quoted 2 lines

BTW we already have 420 "kcalloc(1, ...)" user and 41 without the 1 argument, most of them are in sound, which introduced it in first place. Can we please deprecate that function before it spreads any further?

Quoted 2 lines · Arjan van de Ven

kcalloc does have value, in that it's a nice api to avoid multiplication overflows. Just for "1" it's indeed not the most useful API.

Indeed, kcalloc should not be deprecated as it is meant for array allocation. I can send patches that replace kcalloc(1,...) with kzalloc if there are no other janitors interested...

Pekka

#12 lore raw
In reply to Arjan van de Ven

Hi,

Quoted 2 lines · Arjan van de Ven

kcalloc does have value, in that it's a nice api to avoid multiplication overflows. Just for "1" it's indeed not the most useful API.

This would imply a similiar kmalloc() would be useful as well. Second, how relevant is it for the kernel? Is that really the best place to check for rogue user parameters?

bye, Roman

#13 lore raw
Quoted 9 lines · Roman Zippel

Hi,

Quoted 2 lines · Arjan van de Ven

kcalloc does have value, in that it's a nice api to avoid multiplication overflows. Just for "1" it's indeed not the most useful API.

This would imply a similiar kmalloc() would be useful as well. Second, how relevant is it for the kernel?

we've had a non-negliable amount of security holes because of this

Quoted 2 lines

Is that really the best place
to check for rogue user parameters?

it makes it easy and safe. Of course you can and should check it in all users. Just that using a safer API is generally better than forcing everyone to do it themselves.

#24 lore raw
In reply to Roman Zippel
Quoted 2 lines · Arjan van de Ven
Quoted 2 lines

kcalloc does have value, in that it's a nice api to avoid multiplication overflows. Just for "1" it's indeed not the most useful API.

Quoted 2 lines · Roman Zippel

This would imply a similiar kmalloc() would be useful as well.
Second, how relevant is it for the kernel? Is that really the best place to check for rogue user parameters?

Please note that the first version of kcalloc() carried over from ALSA took only one size parameter but we decided to make it similar to standard calloc(). It is useful as an array allocator which is why I think we should keep both and simply get rid of the kcalloc(1,...) form.

Pekka

#14 lore raw
In reply to Arjan van de Ven

Hi,

Quoted 4 lines · Arjan van de Ven
Quoted 2 lines

This would imply a similiar kmalloc() would be useful as well. Second, how relevant is it for the kernel?

we've had a non-negliable amount of security holes because of this

So why don't we have a similiar kmalloc()?

Quoted 6 lines
Quoted 2 lines

Is that really the best place
to check for rogue user parameters?

it makes it easy and safe. Of course you can and should check it in all users. Just that using a safer API is generally better than forcing everyone to do it themselves.

How exactly does this make it a "safe API"? Even if it checks for this one case, it still makes the user suspectible for allocating big amounts of unswappable memory.

bye, Roman

#15 lore raw
Quoted 10 lines · Roman Zippel

Hi,

Quoted 4 lines · Arjan van de Ven
Quoted 2 lines

This would imply a similiar kmalloc() would be useful as well. Second, how relevant is it for the kernel?

we've had a non-negliable amount of security holes because of this

So why don't we have a similiar kmalloc()?

nope kmalloc is not an array allocator

Quoted 11 lines
Quoted 7 lines
Quoted 3 lines

Is that really the best place
to check for rogue user parameters?

it makes it easy and safe. Of course you can and should check it in all users. Just that using a safer API is generally better than forcing everyone to do it themselves.

How exactly does this make it a "safe API"? Even if it checks for this one case, it still makes the user suspectible for allocating big amounts of unswappable memory.

128Kb max.

#16 lore raw

Hi,

Quoted 10 lines · Arjan van de Ven
Quoted 3 lines
Quoted 1 line

we've had a non-negliable amount of security holes because of this

So why don't we have a similiar kmalloc()?

nope kmalloc is not an array allocator

Quoted 4 lines
Quoted 3 lines

it makes it easy and safe. Of course you can and should check it in all users. Just that using a safer API is generally better than forcing everyone to do it themselves.

Quoted 5 lines
Quoted 3 lines

How exactly does this make it a "safe API"? Even if it checks for this one case, it still makes the user suspectible for allocating big amounts of unswappable memory.

128Kb max.

You completely missed the point and didn't answer my questions at all... :-(

bye, Roman

#17 lore raw
Quoted 14 lines · Roman Zippel

Hi,

Quoted 10 lines · Arjan van de Ven
Quoted 3 lines
Quoted 1 line

we've had a non-negliable amount of security holes because of this

So why don't we have a similiar kmalloc()?

nope kmalloc is not an array allocator

Quoted 4 lines
Quoted 3 lines

it makes it easy and safe. Of course you can and should check it in all users. Just that using a safer API is generally better than forcing everyone to do it themselves.

Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

How exactly does this make it a "safe API"? Even if it checks for this one case, it still makes the user suspectible for allocating big amounts of unswappable memory.

128Kb max.

You completely missed the point and didn't answer my questions at all... :-(

I found it hard to understand your question.

Maybe it helps if I give the basic bug scenario first (pseudo C)

void some_ioctl_func(...)
{
int count, i;
struct foo *ptr;

  copy_from_user(&count,...);

  ptr = kmalloc(sizeof(struct foo) * count);

if (!ptr)

     return -ENOMEM;
  for (i=0; i<count; i++) {
      initialize(ptr+i);

}
}

if the user picks count such that the multiplication overflows, the kmalloc will actually *succeed* in getting a chunk between 0 and 128Kb. The subsequent "fill the array up" will overwrite a LOT of kernel memory though.

Fixing the hole of course involves checking "count" for too high a value. Using kcalloc() will check for this same overflow inside kcalloc and prevent it (eg return NULL) if one of these slips through.

#21 lore raw
In reply to Roman Zippel
Quoted 7 lines · Roman Zippel
Quoted 4 lines · Arjan van de Ven
Quoted 2 lines

This would imply a similiar kmalloc() would be useful as well. Second, how relevant is it for the kernel?

we've had a non-negliable amount of security holes because of this

So why don't we have a similiar kmalloc()?

You mean something like:

static void __bad_kmalloc_safe_nonconstant_size(void); static void __bad_kmalloc_safe_zero_size(void); static void __bad_kmalloc_safe_too_large_size(void); static void __bad_kmalloc_safe_too_large(void);

static inline void *kmalloc_safe(size_t nmemb, size_t size,int flags) {
        if (!__builtin_constant_p(size))
               __bad_kmalloc_safe_nonconstant_size();
        if ( !size )
                __bad_kmalloc_safe_zero_size();
        if ( size > 0x10000)
                __bad_kmalloc_safe_too_large_size();
        if (__builtin_constant_p(nmemb) && nmemb > 0x20000/size)
                __bad_kmalloc_safe_too_large();
        if (nmemb <= 0x20000/size)
                return kmalloc(nmemb*size,flags);
        else return 0; }
Signature · 4 lines
http://dmoz.org/profiles/pollei.html
http://sourceforge.net/users/stephen_pollei/
http://www.orkut.com/Profile.aspx?uid=2455954990164098214
http://stephen_pollei.home.comcast.net/
#22 lore raw
Quoted 7 lines · Stephen Pollei
Quoted 5 lines · Arjan van de Ven
Quoted 3 lines
Quoted 2 lines

This would imply a similiar kmalloc() would be useful as well. Second, how relevant is it for the kernel?

we've had a non-negliable amount of security holes because of this

So why don't we have a similiar kmalloc()?

You mean something like:
static void __bad_kmalloc_safe_nonconstant_size(void);

Hmm. If we had kcmalloc then we may be able to add a zero bit to the slab allocator. If we would obtain zeroed pages for the slab then we may skip zeroing of individual entries. However, the cache warming effect of the current zeroing is then not occurring. Not sure if this would make sense but this is a possible optimization if we had kcmalloc.

#23 lore raw
Quoted 5 lines · Christoph Lameter

Hmm. If we had kcmalloc then we may be able to add a zero bit to the slab allocator. If we would obtain zeroed pages for the slab then we may skip zeroing of individual entries. However, the cache warming effect of the current zeroing is then not occurring. Not sure if this would make sense but this is a possible optimization if we had kcmalloc.

Well there is kzalloc and kcalloc. I just thought a safe non-zeroing version would be nice.
You could warm the cache with prefetch, but you'd need to profile the diferent cases to see what is worth doing and what isn't.

Signature · 4 lines
http://dmoz.org/profiles/pollei.html
http://sourceforge.net/users/stephen_pollei/
http://www.orkut.com/Profile.aspx?uid=2455954990164098214
http://stephen_pollei.home.comcast.net/
#18 lore raw
In reply to Arjan van de Ven

Hi,

Quoted 20 lines · Arjan van de Ven

Maybe it helps if I give the basic bug scenario first (pseudo C)

void some_ioctl_func(...)
{
int count, i;
struct foo *ptr;

  copy_from_user(&count,...);

  ptr = kmalloc(sizeof(struct foo) * count);

if (!ptr)

     return -ENOMEM;
  for (i=0; i<count; i++) {
      initialize(ptr+i);

}
}

Quoted 8 lines

if the user picks count such that the multiplication overflows, the kmalloc will actually *succeed* in getting a chunk between 0 and 128Kb. The subsequent "fill the array up" will overwrite a LOT of kernel memory though.

Fixing the hole of course involves checking "count" for too high a value. Using kcalloc() will check for this same overflow inside kcalloc and prevent it (eg return NULL) if one of these slips through.

What prevents a rogue user to call this function a number of times to waste resources?
kcalloc() covers only small part of what is needed to make an interface secure, once one checked everything else, the safety provided by kcalloc() is pretty much redundant.
Relying on the current allocation limits would be rather foolish as these can change anytime and hardcoding such assumptions is a really bad idea. Kernel coding requires a careful use of the memory resource, so it's the job of the driver to define reasonable limits, e.g. such arrays don't make much sense if they require too much space and the driver should define a limit like (PAGESIZE/sizeof(struct foo)). If the driver writer doesn't think about memory usage, then kcalloc() will do pretty much nothing too improve the driver, it may avoid a few problem cases, but there will be certainly more than enough problems left.
I actually looked at the current kcalloc users and besides a few unchecked module parameters, the arguments were either constant or had to be checked anyway. I didn't find a single example which required the "safety" of kcalloc().

bye, Roman

#19 lore raw
Quoted 4 lines · Roman Zippel

I actually looked at the current kcalloc users and besides a few unchecked module parameters, the arguments were either constant or had to be checked anyway. I didn't find a single example which required the "safety" of kcalloc().

Every caller of kcalloc() should do proper bounds checking. It's just that when they forget to do it, we hopefully avoid a buffer overflow which can be exploited.

Pekka

#5 lore raw
In reply to Pekka J Enberg
Quoted 25 lines · Pekka J Enberg

...

mm/slab.c +14 -0
@@ -2555,6 +2555,20 @@ void kmem_cache_free(kmem_cache_t *cache
 EXPORT_SYMBOL(kmem_cache_free);
 
 /**
+ * kzalloc - allocate memory. The memory is set to zero.
+ * @size: how many bytes of memory are required.
+ * @flags: the type of memory to allocate.
+ */
+void *kzalloc(size_t size, unsigned int __nocast flags)
+{
+	void *ret = kmalloc(size, flags);
+	if (ret)
+		memset(ret, 0, size);
+	return ret;
+}
+EXPORT_SYMBOL(kzalloc);
+
+/**
  * kcalloc - allocate memory for an array. The memory is set to zero.
  * @n: number of elements.
  * @size: element size.

mm/slab.c void *kcalloc(size_t n, size_t size, uns · line 2586

Quoted 10 lines
mm/slab.c +1 -4
@@ -2567,10 +2581,7 @@ void *kcalloc(size_t n, size_t size, uns
 	if (n != 0 && size > INT_MAX / n)
 		return ret;
 
-	ret = kmalloc(n * size, flags);
-	if (ret)
-		memset(ret, 0, n * size);
-	return ret;
+	return kzalloc(n * size, flags);
 }
 EXPORT_SYMBOL(kcalloc);

Looking at how few is left from kcalloc, can't we make it a "static inline" function in slab.h?

This would optimize nicely for all of the users where the first or even the first two parameters are constant at compile-time and shouldn't do much harm for the other users.

As a side effect, the difference between kcalloc(1, ...) and kzalloc() would become a coding style question without any effect on the generated code.

cu
Adrian

Signature · 4 lines
       "Is there not promise of rain?" Ling Tan asked suddenly out
        of the darkness. There had been need of rain for many days.
       "Only a promise," Lao Er said.
                                       Pearl S. Buck - Dragon Seed
#20 lore raw
In reply to Roman Zippel
Quoted 3 lines

What prevents a rogue user to call this function a number of times to waste resources?

Sorry to jump in, but wasting resources is a different matter than overwriting kernel memory.

Jan Engelhardt

#6 lore raw
In reply to Adrian Bunk

At Sat, 6 Aug 2005 17:09:40 +0200,

Quoted 42 lines · Adrian Bunk
Quoted 25 lines · Pekka J Enberg

...

mm/slab.c +14 -0
@@ -2555,6 +2555,20 @@ void kmem_cache_free(kmem_cache_t *cache
 EXPORT_SYMBOL(kmem_cache_free);
 
 /**
+ * kzalloc - allocate memory. The memory is set to zero.
+ * @size: how many bytes of memory are required.
+ * @flags: the type of memory to allocate.
+ */
+void *kzalloc(size_t size, unsigned int __nocast flags)
+{
+	void *ret = kmalloc(size, flags);
+	if (ret)
+		memset(ret, 0, size);
+	return ret;
+}
+EXPORT_SYMBOL(kzalloc);
+
+/**
  * kcalloc - allocate memory for an array. The memory is set to zero.
  * @n: number of elements.
  * @size: element size.

mm/slab.c void *kcalloc(size_t n, size_t size, uns · line 2586

Quoted 10 lines
mm/slab.c +1 -4
@@ -2567,10 +2581,7 @@ void *kcalloc(size_t n, size_t size, uns
 	if (n != 0 && size > INT_MAX / n)
 		return ret;
 
-	ret = kmalloc(n * size, flags);
-	if (ret)
-		memset(ret, 0, n * size);
-	return ret;
+	return kzalloc(n * size, flags);
 }
 EXPORT_SYMBOL(kcalloc);

Looking at how few is left from kcalloc, can't we make it a "static inline" function in slab.h?

Quoted 7 lines

This would optimize nicely for all of the users where the first or even the first two parameters are constant at compile-time and shouldn't do much harm for the other users.

As a side effect, the difference between kcalloc(1, ...) and kzalloc() would become a coding style question without any effect on the generated code.

How about to use __builtin_constant_p() like kmalloc? The code readability would be worsen, though...

Takashi

#7 lore raw
Quoted 11 lines · Takashi Iwai

At Sat, 6 Aug 2005 17:09:40 +0200,

Quoted 9 lines · Adrian Bunk

Looking at how few is left from kcalloc, can't we make it a "static inline" function in slab.h?

This would optimize nicely for all of the users where the first or even the first two parameters are constant at compile-time and shouldn't do much harm for the other users.

Quoted 6 lines
Quoted 3 lines

As a side effect, the difference between kcalloc(1, ...) and kzalloc() would become a coding style question without any effect on the generated code.

How about to use __builtin_constant_p() like kmalloc? The code readability would be worsen, though...

Where should this make any difference?

If the function is "static inline", gcc can e.g. always determine at compile-time that 1 >= 0 can never be false and therefore optimize it away.

Quoted 1 line

Takashi

cu
Adrian

Signature · 4 lines
       "Is there not promise of rain?" Ling Tan asked suddenly out
        of the darkness. There had been need of rain for many days.
       "Only a promise," Lao Er said.
                                       Pearl S. Buck - Dragon Seed
#8 lore raw

At Mon, 8 Aug 2005 23:05:24 +0200,

Quoted 17 lines · Adrian Bunk
Quoted 15 lines · Takashi Iwai

At Sat, 6 Aug 2005 17:09:40 +0200,

Quoted 12 lines · Adrian Bunk

Looking at how few is left from kcalloc, can't we make it a "static inline" function in slab.h?

This would optimize nicely for all of the users where the first or even the first two parameters are constant at compile-time and shouldn't do much harm for the other users.

As a side effect, the difference between kcalloc(1, ...) and kzalloc() would become a coding style question without any effect on the generated code.

Quoted 8 lines
Quoted 2 lines

How about to use __builtin_constant_p() like kmalloc? The code readability would be worsen, though...

Where should this make any difference?

If the function is "static inline", gcc can e.g. always determine at compile-time that 1 >= 0 can never be false and therefore optimize it away.

Argh, forget my post. It was just lack of caffeine :)

Takashi