lkml.org 
[lkml]   [2015]   [Mar]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.16.y-ckt 041/165] nilfs2: fix potential memory overrun on inode
    Date
    3.16.7-ckt9 -stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>

    commit 957ed60b53b519064a54988c4e31e0087e47d091 upstream.

    Each inode of nilfs2 stores a root node of a b-tree, and it turned out to
    have a memory overrun issue:

    Each b-tree node of nilfs2 stores a set of key-value pairs and the number
    of them (in "bn_nchildren" member of nilfs_btree_node struct), as well as
    a few other "bn_*" members.

    Since the value of "bn_nchildren" is used for operations on the key-values
    within the b-tree node, it can cause memory access overrun if a large
    number is incorrectly set to "bn_nchildren".

    For instance, nilfs_btree_node_lookup() function determines the range of
    binary search with it, and too large "bn_nchildren" leads
    nilfs_btree_node_get_key() in that function to overrun.

    As for intermediate b-tree nodes, this is prevented by a sanity check
    performed when each node is read from a drive, however, no sanity check
    has been done for root nodes stored in inodes.

    This patch fixes the issue by adding missing sanity check against b-tree
    root nodes so that it's called when on-memory inodes are read from ifile,
    inode metadata file.

    Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: Luis Henriques <luis.henriques@canonical.com>
    ---
    fs/nilfs2/btree.c | 47 ++++++++++++++++++++++++++++++++++++++++++++---
    1 file changed, 44 insertions(+), 3 deletions(-)

    diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c
    index b2e3ff347620..ecdbae19a766 100644
    --- a/fs/nilfs2/btree.c
    +++ b/fs/nilfs2/btree.c
    @@ -31,6 +31,8 @@
    #include "alloc.h"
    #include "dat.h"

    +static void __nilfs_btree_init(struct nilfs_bmap *bmap);
    +
    static struct nilfs_btree_path *nilfs_btree_alloc_path(void)
    {
    struct nilfs_btree_path *path;
    @@ -368,6 +370,34 @@ static int nilfs_btree_node_broken(const struct nilfs_btree_node *node,
    return ret;
    }

    +/**
    + * nilfs_btree_root_broken - verify consistency of btree root node
    + * @node: btree root node to be examined
    + * @ino: inode number
    + *
    + * Return Value: If node is broken, 1 is returned. Otherwise, 0 is returned.
    + */
    +static int nilfs_btree_root_broken(const struct nilfs_btree_node *node,
    + unsigned long ino)
    +{
    + int level, flags, nchildren;
    + int ret = 0;
    +
    + level = nilfs_btree_node_get_level(node);
    + flags = nilfs_btree_node_get_flags(node);
    + nchildren = nilfs_btree_node_get_nchildren(node);
    +
    + if (unlikely(level < NILFS_BTREE_LEVEL_NODE_MIN ||
    + level > NILFS_BTREE_LEVEL_MAX ||
    + nchildren < 0 ||
    + nchildren > NILFS_BTREE_ROOT_NCHILDREN_MAX)) {
    + pr_crit("NILFS: bad btree root (inode number=%lu): level = %d, flags = 0x%x, nchildren = %d\n",
    + ino, level, flags, nchildren);
    + ret = 1;
    + }
    + return ret;
    +}
    +
    int nilfs_btree_broken_node_block(struct buffer_head *bh)
    {
    int ret;
    @@ -1713,7 +1743,7 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *btree,

    /* convert and insert */
    dat = NILFS_BMAP_USE_VBN(btree) ? nilfs_bmap_get_dat(btree) : NULL;
    - nilfs_btree_init(btree);
    + __nilfs_btree_init(btree);
    if (nreq != NULL) {
    nilfs_bmap_commit_alloc_ptr(btree, dreq, dat);
    nilfs_bmap_commit_alloc_ptr(btree, nreq, dat);
    @@ -2294,12 +2324,23 @@ static const struct nilfs_bmap_operations nilfs_btree_ops_gc = {
    .bop_gather_data = NULL,
    };

    -int nilfs_btree_init(struct nilfs_bmap *bmap)
    +static void __nilfs_btree_init(struct nilfs_bmap *bmap)
    {
    bmap->b_ops = &nilfs_btree_ops;
    bmap->b_nchildren_per_block =
    NILFS_BTREE_NODE_NCHILDREN_MAX(nilfs_btree_node_size(bmap));
    - return 0;
    +}
    +
    +int nilfs_btree_init(struct nilfs_bmap *bmap)
    +{
    + int ret = 0;
    +
    + __nilfs_btree_init(bmap);
    +
    + if (nilfs_btree_root_broken(nilfs_btree_get_root(bmap),
    + bmap->b_inode->i_ino))
    + ret = -EIO;
    + return ret;
    }

    void nilfs_btree_init_gc(struct nilfs_bmap *bmap)

    \
     
     \ /
      Last update: 2015-03-25 16:01    [W:2.398 / U:0.420 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site