]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/3.10.72/nilfs2-fix-potential-memory-overrun-on-inode.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 3.10.72 / nilfs2-fix-potential-memory-overrun-on-inode.patch
1 From 957ed60b53b519064a54988c4e31e0087e47d091 Mon Sep 17 00:00:00 2001
2 From: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
3 Date: Fri, 27 Feb 2015 15:51:56 -0800
4 Subject: nilfs2: fix potential memory overrun on inode
5
6 From: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
7
8 commit 957ed60b53b519064a54988c4e31e0087e47d091 upstream.
9
10 Each inode of nilfs2 stores a root node of a b-tree, and it turned out to
11 have a memory overrun issue:
12
13 Each b-tree node of nilfs2 stores a set of key-value pairs and the number
14 of them (in "bn_nchildren" member of nilfs_btree_node struct), as well as
15 a few other "bn_*" members.
16
17 Since the value of "bn_nchildren" is used for operations on the key-values
18 within the b-tree node, it can cause memory access overrun if a large
19 number is incorrectly set to "bn_nchildren".
20
21 For instance, nilfs_btree_node_lookup() function determines the range of
22 binary search with it, and too large "bn_nchildren" leads
23 nilfs_btree_node_get_key() in that function to overrun.
24
25 As for intermediate b-tree nodes, this is prevented by a sanity check
26 performed when each node is read from a drive, however, no sanity check
27 has been done for root nodes stored in inodes.
28
29 This patch fixes the issue by adding missing sanity check against b-tree
30 root nodes so that it's called when on-memory inodes are read from ifile,
31 inode metadata file.
32
33 Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
34 Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
35 Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
36 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
37
38 ---
39 fs/nilfs2/btree.c | 47 ++++++++++++++++++++++++++++++++++++++++++++---
40 1 file changed, 44 insertions(+), 3 deletions(-)
41
42 --- a/fs/nilfs2/btree.c
43 +++ b/fs/nilfs2/btree.c
44 @@ -31,6 +31,8 @@
45 #include "alloc.h"
46 #include "dat.h"
47
48 +static void __nilfs_btree_init(struct nilfs_bmap *bmap);
49 +
50 static struct nilfs_btree_path *nilfs_btree_alloc_path(void)
51 {
52 struct nilfs_btree_path *path;
53 @@ -368,6 +370,34 @@ static int nilfs_btree_node_broken(const
54 return ret;
55 }
56
57 +/**
58 + * nilfs_btree_root_broken - verify consistency of btree root node
59 + * @node: btree root node to be examined
60 + * @ino: inode number
61 + *
62 + * Return Value: If node is broken, 1 is returned. Otherwise, 0 is returned.
63 + */
64 +static int nilfs_btree_root_broken(const struct nilfs_btree_node *node,
65 + unsigned long ino)
66 +{
67 + int level, flags, nchildren;
68 + int ret = 0;
69 +
70 + level = nilfs_btree_node_get_level(node);
71 + flags = nilfs_btree_node_get_flags(node);
72 + nchildren = nilfs_btree_node_get_nchildren(node);
73 +
74 + if (unlikely(level < NILFS_BTREE_LEVEL_NODE_MIN ||
75 + level > NILFS_BTREE_LEVEL_MAX ||
76 + nchildren < 0 ||
77 + nchildren > NILFS_BTREE_ROOT_NCHILDREN_MAX)) {
78 + pr_crit("NILFS: bad btree root (inode number=%lu): level = %d, flags = 0x%x, nchildren = %d\n",
79 + ino, level, flags, nchildren);
80 + ret = 1;
81 + }
82 + return ret;
83 +}
84 +
85 int nilfs_btree_broken_node_block(struct buffer_head *bh)
86 {
87 int ret;
88 @@ -1713,7 +1743,7 @@ nilfs_btree_commit_convert_and_insert(st
89
90 /* convert and insert */
91 dat = NILFS_BMAP_USE_VBN(btree) ? nilfs_bmap_get_dat(btree) : NULL;
92 - nilfs_btree_init(btree);
93 + __nilfs_btree_init(btree);
94 if (nreq != NULL) {
95 nilfs_bmap_commit_alloc_ptr(btree, dreq, dat);
96 nilfs_bmap_commit_alloc_ptr(btree, nreq, dat);
97 @@ -2294,12 +2324,23 @@ static const struct nilfs_bmap_operation
98 .bop_gather_data = NULL,
99 };
100
101 -int nilfs_btree_init(struct nilfs_bmap *bmap)
102 +static void __nilfs_btree_init(struct nilfs_bmap *bmap)
103 {
104 bmap->b_ops = &nilfs_btree_ops;
105 bmap->b_nchildren_per_block =
106 NILFS_BTREE_NODE_NCHILDREN_MAX(nilfs_btree_node_size(bmap));
107 - return 0;
108 +}
109 +
110 +int nilfs_btree_init(struct nilfs_bmap *bmap)
111 +{
112 + int ret = 0;
113 +
114 + __nilfs_btree_init(bmap);
115 +
116 + if (nilfs_btree_root_broken(nilfs_btree_get_root(bmap),
117 + bmap->b_inode->i_ino))
118 + ret = -EIO;
119 + return ret;
120 }
121
122 void nilfs_btree_init_gc(struct nilfs_bmap *bmap)