From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S966644AbbLPSAE (ORCPT ); Wed, 16 Dec 2015 13:00:04 -0500 Received: from youngberry.canonical.com ([91.189.89.112]:49967 "EHLO youngberry.canonical.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S966574AbbLPRkg (ORCPT ); Wed, 16 Dec 2015 12:40:36 -0500 From: Kamal Mostafa To: linux-kernel@vger.kernel.org, stable@vger.kernel.org, kernel-team@lists.ubuntu.com Cc: David Sterba , Chris Mason , Kamal Mostafa Subject: [PATCH 3.19.y-ckt 079/128] btrfs: fix signed overflows in btrfs_sync_file Date: Wed, 16 Dec 2015 09:38:39 -0800 Message-Id: <1450287568-19808-80-git-send-email-kamal@canonical.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1450287568-19808-1-git-send-email-kamal@canonical.com> References: <1450287568-19808-1-git-send-email-kamal@canonical.com> X-Extended-Stable: 3.19 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 3.19.8-ckt12 -stable review patch. If anyone has any objections, please let me know. ------------------ From: David Sterba commit 9dcbeed4d7e11e1dcf5e55475de3754f0855d1c2 upstream. The calculation of range length in btrfs_sync_file leads to signed overflow. This was caught by PaX gcc SIZE_OVERFLOW plugin. https://forums.grsecurity.net/viewtopic.php?f=1&t=4284 The fsync call passes 0 and LLONG_MAX, the range length does not fit to loff_t and overflows, but the value is converted to u64 so it silently works as expected. The minimal fix is a typecast to u64, switching functions to take (start, end) instead of (start, len) would be more intrusive. Coccinelle script found that there's one more opencoded calculation of the length. @@ loff_t start, end; @@ * end - start Signed-off-by: David Sterba Signed-off-by: Chris Mason [ kamal: backport to 3.19-stable: use len in both btrfs_wait_ordered_range calls, like b659ef0 Btrfs: avoid syncing log in the fast fsync path when not necessary ] Signed-off-by: Kamal Mostafa --- fs/btrfs/file.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 11ec6e5..1e54adf 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1884,7 +1884,13 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) struct btrfs_log_ctx ctx; int ret = 0; bool full_sync = 0; + u64 len; + /* + * The range length can be represented by u64, we have to do the typecasts + * to avoid signed overflow if it's [0, LLONG_MAX] eg. from fsync() + */ + len = (u64)end - (u64)start + 1; trace_btrfs_sync_file(file, datasync); /* @@ -1912,7 +1918,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) * all extents are persisted and the respective file extent * items are in the fs/subvol btree. */ - ret = btrfs_wait_ordered_range(inode, start, end - start + 1); + ret = btrfs_wait_ordered_range(inode, start, len); } else { /* * Start any new ordered operations before starting to log the @@ -2070,8 +2076,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) } } if (!full_sync) { - ret = btrfs_wait_ordered_range(inode, start, - end - start + 1); + ret = btrfs_wait_ordered_range(inode, start, len); if (ret) { btrfs_end_transaction(trans, root); goto out; -- 1.9.1