From mboxrd@z Thu Jan 1 00:00:00 1970 From: Christoph Hellwig Subject: hfs_bnode_find() can fail, resulting in hfs_bnode_split() breakage Date: Tue, 12 Oct 2010 15:57:01 +0200 Message-ID: <20101012135701.GC26867@lst.de> References: <20101012135634.GA26867@lst.de> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii To: linux-fsdevel@vger.kernel.org Return-path: Received: from verein.lst.de ([213.95.11.210]:51592 "EHLO verein.lst.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932477Ab0JLN5D (ORCPT ); Tue, 12 Oct 2010 09:57:03 -0400 Received: from verein.lst.de (localhost [127.0.0.1]) by verein.lst.de (8.12.3/8.12.3/Debian-7.1) with ESMTP id o9CDv188026994 (version=TLSv1/SSLv3 cipher=EDH-RSA-DES-CBC3-SHA bits=168 verify=NO) for ; Tue, 12 Oct 2010 15:57:02 +0200 Received: (from hch@localhost) by verein.lst.de (8.12.3/8.12.3/Debian-7.2) id o9CDv1U7026993 for linux-fsdevel@vger.kernel.org; Tue, 12 Oct 2010 15:57:01 +0200 Content-Disposition: inline In-Reply-To: <20101012135634.GA26867@lst.de> Sender: linux-fsdevel-owner@vger.kernel.org List-ID: From: Al Viro oops and fs corruption; the latter can happen even on valid fs in case of oom. [hch: port of commit 3d10a15d6919488204bdb264050d156ced20d9aa from hfs] Signed-off-by: Al Viro Signed-off-by: Christoph Hellwig Index: linux-2.6/fs/hfsplus/brec.c =================================================================== --- linux-2.6.orig/fs/hfsplus/brec.c 2010-10-06 09:34:17.753004170 +0200 +++ linux-2.6/fs/hfsplus/brec.c 2010-10-06 09:36:36.550004100 +0200 @@ -216,7 +216,7 @@ skip: static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) { struct hfs_btree *tree; - struct hfs_bnode *node, *new_node; + struct hfs_bnode *node, *new_node, *next_node; struct hfs_bnode_desc node_desc; int num_recs, new_rec_off, new_off, old_rec_off; int data_start, data_end, size; @@ -235,6 +235,17 @@ static struct hfs_bnode *hfs_bnode_split new_node->type = node->type; new_node->height = node->height; + if (node->next) + next_node = hfs_bnode_find(tree, node->next); + else + next_node = NULL; + + if (IS_ERR(next_node)) { + hfs_bnode_put(node); + hfs_bnode_put(new_node); + return next_node; + } + size = tree->node_size / 2 - node->num_recs * 2 - 14; old_rec_off = tree->node_size - 4; num_recs = 1; @@ -248,6 +259,8 @@ static struct hfs_bnode *hfs_bnode_split /* panic? */ hfs_bnode_put(node); hfs_bnode_put(new_node); + if (next_node) + hfs_bnode_put(next_node); return ERR_PTR(-ENOSPC); } @@ -302,8 +315,7 @@ static struct hfs_bnode *hfs_bnode_split hfs_bnode_write(node, &node_desc, 0, sizeof(node_desc)); /* update next bnode header */ - if (new_node->next) { - struct hfs_bnode *next_node = hfs_bnode_find(tree, new_node->next); + if (next_node) { next_node->prev = new_node->this; hfs_bnode_read(next_node, &node_desc, 0, sizeof(node_desc)); node_desc.prev = cpu_to_be32(next_node->prev);