Filipe David Borba Manana
2014-Mar-27 20:17 UTC
[PATCH] Btrfs: send, don't crash if we attempt to build a too long path
There were recently fixed issues where an incremental send would enter
an infinite loop when building a path string, which made it krealloc the
path buffer over and over. This eventually lead to a kernel crash because
we track the buffer's size in a 15 bits unsigned integer and eventually we
ended up assigning it 32768 (returned by ksize) which made
it get a value of 0. We then use this size to compute an offset into our
buffer which falls outside its range (by 1 byte to the left) when the size
is 0, which would make the memmove operation crash with the following trace:
[ 8541.781613] BUG: unable to handle kernel paging request at ffff88009069c000
[ 8541.781618] IP: [<ffffffff8136cf91>] memmove+0x81/0x1a0
[ 8541.781623] PGD 2a2b067 PUD 21fb01067 PMD 21fa7d067 PTE 800000009069c060
[ 8541.781626] Oops: 0002 [#1] SMP DEBUG_PAGEALLOC
[ 8541.781628] Modules linked in: btrfs raid6_pq xor bnep rfcomm bluetooth
binfmt_misc nfsd auth_rpcgss oid_registry nfs_acl nfs lockd fscache sunrpc
parport_pc psmouse serio_raw parport i2c_piix4 pcspkr evbug e1000 floppy [last
unloaded: btrfs]
[ 8541.781641] CPU: 3 PID: 28970 Comm: btrfs Not tainted
3.13.0-fdm-btrfs-next-24+ #1
[ 8541.781642] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011
[ 8541.781643] task: ffff88020967c920 ti: ffff880091246000 task.ti:
ffff880091246000
[ 8541.781644] RIP: 0010:[<ffffffff8136cf91>] [<ffffffff8136cf91>]
memmove+0x81/0x1a0
[ 8541.781647] RSP: 0018:ffff8800912477c0 EFLAGS: 00010206
[ 8541.781647] RAX: ffff88009069c000 RBX: ffff8800caed46d8 RCX: 0000000000000800
[ 8541.781648] RDX: 0000000000004000 RSI: ffff8800906a0000 RDI: ffff88009069c000
[ 8541.781649] RBP: ffff8800912477e8 R08: 0000000000000001 R09: 0000000000000000
[ 8541.781650] R10: ffff88009069fff8 R11: 6b6b6b6b6b6b6b6b R12: 0000000000000000
[ 8541.781651] R13: 0000000000004000 R14: 0000000000000113 R15: 0000000000000000
[ 8541.781652] FS: 00007fb6c960e800(0000) GS:ffff880216400000(0000)
knlGS:0000000000000000
[ 8541.781653] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[ 8541.781656] CR2: ffff88009069c000 CR3: 00000000cce87000 CR4: 00000000000006e0
[ 8541.781660] Stack:
[ 8541.781660] ffffffffa02dbfd3 ffffea0007a54300 ffff8800caed46d8
ffff880091247830
[ 8541.781663] 0000000000000003 ffff880091247818 ffffffffa02dc316
000c000000000000
[ 8541.781665] ffff8800caed5918 ffff8800caed5918 0000000000000003
ffff880091247848
[ 8541.781667] Call Trace:
[ 8541.781679] [<ffffffffa02dbfd3>] ? fs_path_ensure_buf+0xf3/0x110
[btrfs]
[ 8541.781687] [<ffffffffa02dc316>] fs_path_prepare_for_add+0x46/0xc0
[btrfs]
[ 8541.781694] [<ffffffffa02dc418>] fs_path_add_path+0x28/0x50 [btrfs]
[ 8541.781701] [<ffffffffa02de5a3>] get_cur_path+0x1f3/0x5a0 [btrfs]
(...)
Since we can't have path strings larger than PATH_MAX, just return with an
ENAMETOOLONG error, which is likely caused by infinite path build loops due
to changes in directory hierarchy. This is better then crashing the kernel
and requiring a system reboot.
Signed-off-by: Filipe David Borba Manana <fdmanana@gmail.com>
---
fs/btrfs/send.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index e2e422c..41a4a45 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -349,6 +349,9 @@ static int fs_path_ensure_buf(struct fs_path *p, int len)
if (p->buf_len >= len)
return 0;
+ if (unlikely(len > PATH_MAX))
+ return -ENAMETOOLONG;
+
path_len = p->end - p->start;
old_buf_len = p->buf_len;
@@ -2140,6 +2143,7 @@ static int get_cur_path(struct send_ctx *sctx, u64 ino,
u64 gen,
u64 parent_inode = 0;
u64 parent_gen = 0;
int stop = 0;
+ u64 start_ino = ino;
name = fs_path_alloc();
if (!name) {
@@ -2187,6 +2191,12 @@ out:
fs_path_free(name);
if (!ret)
fs_path_unreverse(dest);
+ else if (unlikely(ret == -ENAMETOOLONG))
+ btrfs_warn(sctx->send_root->fs_info,
+ "Possible path build loop in send operation, inode %llu, send root
%llu, parent root %llu",
+ start_ino, sctx->send_root->root_key.objectid,
+ sctx->parent_root ?
+ sctx->parent_root->root_key.objectid : 0);
return ret;
}
--
1.7.10.4
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs"
in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html