aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fib_trie.c
diff options
context:
space:
mode:
authorEric Dumazet <dada1@cosmosbay.com>2008-01-14 01:31:44 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:02:04 -0500
commit8d96544475b236a0f319e492f4828aa8c0801c7f (patch)
tree874099e668f97c55867349e417e402d33f13250c /net/ipv4/fib_trie.c
parentf16f3026db6fa63cbb0f4a37833562aa999c93e5 (diff)
[FIB]: full_children & empty_children should be uint, not ushort
If declared as unsigned short, these fields can overflow, and whole trie logic is broken. I could not make the machine crash, but some tnode can never be freed. Note for 64 bit arches : By reordering t_key and parent in [node, leaf, tnode] structures, we can use 32 bits hole after t_key so that sizeof(struct tnode) doesnt change after this patch. Signed-off-by: Eric Dumazet <dada1@cosmosbay.com> Signed-off-by: Robert Olsson <robert.olsson@its.uu.se> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/fib_trie.c')
-rw-r--r--net/ipv4/fib_trie.c25
1 files changed, 12 insertions, 13 deletions
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index da6681ddc509..18fb73958a49 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -97,13 +97,13 @@ typedef unsigned int t_key;
97#define IS_LEAF(n) (n->parent & T_LEAF) 97#define IS_LEAF(n) (n->parent & T_LEAF)
98 98
99struct node { 99struct node {
100 t_key key;
101 unsigned long parent; 100 unsigned long parent;
101 t_key key;
102}; 102};
103 103
104struct leaf { 104struct leaf {
105 t_key key;
106 unsigned long parent; 105 unsigned long parent;
106 t_key key;
107 struct hlist_head list; 107 struct hlist_head list;
108 struct rcu_head rcu; 108 struct rcu_head rcu;
109}; 109};
@@ -116,12 +116,12 @@ struct leaf_info {
116}; 116};
117 117
118struct tnode { 118struct tnode {
119 t_key key;
120 unsigned long parent; 119 unsigned long parent;
120 t_key key;
121 unsigned char pos; /* 2log(KEYLENGTH) bits needed */ 121 unsigned char pos; /* 2log(KEYLENGTH) bits needed */
122 unsigned char bits; /* 2log(KEYLENGTH) bits needed */ 122 unsigned char bits; /* 2log(KEYLENGTH) bits needed */
123 unsigned short full_children; /* KEYLENGTH bits needed */ 123 unsigned int full_children; /* KEYLENGTH bits needed */
124 unsigned short empty_children; /* KEYLENGTH bits needed */ 124 unsigned int empty_children; /* KEYLENGTH bits needed */
125 struct rcu_head rcu; 125 struct rcu_head rcu;
126 struct node *child[0]; 126 struct node *child[0];
127}; 127};
@@ -329,12 +329,12 @@ static inline void free_leaf_info(struct leaf_info *leaf)
329 call_rcu(&leaf->rcu, __leaf_info_free_rcu); 329 call_rcu(&leaf->rcu, __leaf_info_free_rcu);
330} 330}
331 331
332static struct tnode *tnode_alloc(unsigned int size) 332static struct tnode *tnode_alloc(size_t size)
333{ 333{
334 struct page *pages; 334 struct page *pages;
335 335
336 if (size <= PAGE_SIZE) 336 if (size <= PAGE_SIZE)
337 return kcalloc(size, 1, GFP_KERNEL); 337 return kzalloc(size, GFP_KERNEL);
338 338
339 pages = alloc_pages(GFP_KERNEL|__GFP_ZERO, get_order(size)); 339 pages = alloc_pages(GFP_KERNEL|__GFP_ZERO, get_order(size));
340 if (!pages) 340 if (!pages)
@@ -346,8 +346,8 @@ static struct tnode *tnode_alloc(unsigned int size)
346static void __tnode_free_rcu(struct rcu_head *head) 346static void __tnode_free_rcu(struct rcu_head *head)
347{ 347{
348 struct tnode *tn = container_of(head, struct tnode, rcu); 348 struct tnode *tn = container_of(head, struct tnode, rcu);
349 unsigned int size = sizeof(struct tnode) + 349 size_t size = sizeof(struct tnode) +
350 (1 << tn->bits) * sizeof(struct node *); 350 (sizeof(struct node *) << tn->bits);
351 351
352 if (size <= PAGE_SIZE) 352 if (size <= PAGE_SIZE)
353 kfree(tn); 353 kfree(tn);
@@ -386,8 +386,7 @@ static struct leaf_info *leaf_info_new(int plen)
386 386
387static struct tnode* tnode_new(t_key key, int pos, int bits) 387static struct tnode* tnode_new(t_key key, int pos, int bits)
388{ 388{
389 int nchildren = 1<<bits; 389 size_t sz = sizeof(struct tnode) + (sizeof(struct node *) << bits);
390 int sz = sizeof(struct tnode) + nchildren * sizeof(struct node *);
391 struct tnode *tn = tnode_alloc(sz); 390 struct tnode *tn = tnode_alloc(sz);
392 391
393 if (tn) { 392 if (tn) {
@@ -399,8 +398,8 @@ static struct tnode* tnode_new(t_key key, int pos, int bits)
399 tn->empty_children = 1<<bits; 398 tn->empty_children = 1<<bits;
400 } 399 }
401 400
402 pr_debug("AT %p s=%u %u\n", tn, (unsigned int) sizeof(struct tnode), 401 pr_debug("AT %p s=%u %lu\n", tn, (unsigned int) sizeof(struct tnode),
403 (unsigned int) (sizeof(struct node) * 1<<bits)); 402 (unsigned long) (sizeof(struct node) << bits));
404 return tn; 403 return tn;
405} 404}
406 405