aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOGAWA Hirofumi <hirofumi@mail.parknet.co.jp>2013-01-23 02:27:07 +0900
committerDaniel Phillips <daniel@tux3.org>2013-01-23 02:27:07 +0900
commita0f6539af2c994b6b1ea835548c711cb01df8399 (patch)
treeabbbb5af84944850ef9a0ca1c6e4a2c993852b67
parent26f4917d459d5db77141181c435379c396d00a10 (diff)
downloadlinux-tux3-a0f6539af2c994b6b1ea835548c711cb01df8399.tar.gz
tux3: Fix overflow in ileaf.c
inum can be so big, so "at = key - ibase()" can overflow. This fixes it. Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
-rw-r--r--fs/tux3/ileaf.c60
1 files changed, 34 insertions, 26 deletions
diff --git a/fs/tux3/ileaf.c b/fs/tux3/ileaf.c
index e661a9cfbfea00..0a89cc12fd2221 100644
--- a/fs/tux3/ileaf.c
+++ b/fs/tux3/ileaf.c
@@ -143,10 +143,10 @@ static void ileaf_dump(struct btree *btree, void *vleaf)
void *ileaf_lookup(struct btree *btree, inum_t inum, struct ileaf *leaf, unsigned *result)
{
assert(inum >= ibase(leaf));
- unsigned at = inum - ibase(leaf), size = 0;
+ tuxkey_t at = inum - ibase(leaf), size = 0;
void *attrs = NULL;
- trace("lookup inode 0x%Lx, %Lx + %x", inum, ibase(leaf), at);
+ trace("lookup inode 0x%Lx, %Lx + %Lx", inum, ibase(leaf), at);
if (at < icount(leaf)) {
__be16 *dict = ileaf_dict(btree, leaf);
unsigned offset = atdict(dict, at);
@@ -310,7 +310,7 @@ static int ileaf_chop(struct btree *btree, tuxkey_t start, u64 len, void *leaf)
__be16 *dict = ileaf_dict(btree, leaf);
tuxkey_t base = ibase(ileaf);
unsigned count = icount(ileaf);
- unsigned at = start - base;
+ tuxkey_t at = start - base;
void *startp, *endp, *tailp;
unsigned size;
@@ -346,13 +346,17 @@ static void *ileaf_resize(struct btree *btree, tuxkey_t inum, void *vleaf,
struct ileaf *ileaf = vleaf;
__be16 *dict = ileaf_dict(btree, ileaf);
unsigned count = icount(ileaf);
- unsigned at = inum - ibase(ileaf);
+ tuxkey_t at = inum - ibase(ileaf);
int extend_dict, offset, size;
assert(inum >= ibase(ileaf));
/* Get existent attributes, and calculate expand/shrink size */
if (at + 1 > count) {
+ /* Check size roughly to avoid overflow int */
+ if ((at + 1) * sizeof(*dict) >= btree->sb->blocksize)
+ goto overflow;
+
/* Need to extend dict */
extend_dict = (at + 1 - count) * sizeof(*dict);
offset = atdict(dict, count);
@@ -364,8 +368,10 @@ static void *ileaf_resize(struct btree *btree, tuxkey_t inum, void *vleaf,
size = __atdict(dict, at + 1) - offset;
}
- if (ileaf_free(btree, ileaf) < newsize - size + extend_dict)
+ if (ileaf_free(btree, ileaf) < newsize - size + extend_dict) {
+overflow:
return NULL;
+ }
/* Extend dict */
if (extend_dict) {
@@ -504,7 +510,7 @@ int ileaf_find_free(struct btree *btree, tuxkey_t key_bottom,
tuxkey_t key_limit, void *leaf,
tuxkey_t key, u64 len, void *data)
{
- unsigned at = key - ibase(leaf);
+ tuxkey_t at = key - ibase(leaf);
unsigned count = icount(leaf);
key_limit = min(key_limit, key + len);
@@ -543,31 +549,33 @@ int ileaf_enumerate(struct btree *btree, tuxkey_t key_bottom,
struct ileaf *ileaf = leaf;
__be16 *dict = ileaf_dict(btree, ileaf);
struct ileaf_enumrate_cb *cb = data;
- tuxkey_t base = ibase(ileaf);
- unsigned at, count, offset;
+ tuxkey_t at, base = ibase(ileaf);
+ unsigned count;
at = key - base;
count = min_t(u64, key + len - base, icount(ileaf));
- offset = atdict(dict, at);
- for (; at < count; at++) {
- unsigned size, limit;
- inum_t inum;
- void *attrs;
- int err;
-
- limit = __atdict(dict, at + 1);
- if (limit <= offset)
- continue;
- attrs = ileaf->table + offset;
- size = limit - offset;
-
- inum = base + at;
- err = cb->callback(btree, inum, attrs, size, cb->data);
- if (err)
- return err;
+ if (at < count) {
+ unsigned offset = atdict(dict, at);
+ for (; at < count; at++) {
+ unsigned size, limit;
+ inum_t inum;
+ void *attrs;
+ int err;
+
+ limit = __atdict(dict, at + 1);
+ if (limit <= offset)
+ continue;
+ attrs = ileaf->table + offset;
+ size = limit - offset;
+
+ inum = base + at;
+ err = cb->callback(btree, inum, attrs, size, cb->data);
+ if (err)
+ return err;
- offset = limit;
+ offset = limit;
+ }
}
return 0;