From patchwork Fri Mar 30 19:13:20 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Theodore Ts'o X-Patchwork-Id: 893478 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-ext4-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=mit.edu Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=thunk.org header.i=@thunk.org header.b="CyFWMUe5"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 40CWVb5gkdz9s2b for ; Sat, 31 Mar 2018 06:13:27 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752299AbeC3TNZ (ORCPT ); Fri, 30 Mar 2018 15:13:25 -0400 Received: from imap.thunk.org ([74.207.234.97]:48542 "EHLO imap.thunk.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752106AbeC3TNZ (ORCPT ); Fri, 30 Mar 2018 15:13:25 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=thunk.org; s=ef5046eb; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Sender:Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=e61YTo/5EAmC2VSzB+NyfSuZ8CTuqeZ0uA44xny2G1A=; b=CyFWMUe59TLML9moPSwJf4+05G Vu4L3GER21g3JQ+GZBx2RpXL5qLCsxQ4sFUTE2EHDSNWBsJRfOSX145f8b7JbA93TlVut6G4qYoMJ CgjXEMwsvtMFgg3FlxKier59X1Cd0uEojKbgYmljrZnVhWybPNGaALkbN+hHeI650+bA=; Received: from root (helo=callcc.thunk.org) by imap.thunk.org with local-esmtp (Exim 4.89) (envelope-from ) id 1f1zSl-0005Wy-Ij; Fri, 30 Mar 2018 19:13:23 +0000 Received: by callcc.thunk.org (Postfix, from userid 15806) id BF7B77A017E; Fri, 30 Mar 2018 15:13:22 -0400 (EDT) From: Theodore Ts'o To: Ext4 Developers List Cc: adilger@dilger.ca, ebiggers3@gmail.com, wen.xu@gatech.edu, ebiggers@google.com, Theodore Ts'o , stable@vger.kernel.org Subject: [PATCH -v2] ext4: limit xattr size to INT_MAX Date: Fri, 30 Mar 2018 15:13:20 -0400 Message-Id: <20180330191320.7270-1-tytso@mit.edu> X-Mailer: git-send-email 2.16.1.72.g5be1f00a9a In-Reply-To: <20180329194125.GC3790@thunk.org> References: <20180329194125.GC3790@thunk.org> X-SA-Exim-Connect-IP: X-SA-Exim-Mail-From: tytso@thunk.org X-SA-Exim-Scanned: No (on imap.thunk.org); SAEximRunCond expanded to false Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org From: Eric Biggers ext4 isn't validating the sizes of xattrs. This is problematic because ->e_value_size is a u32, but ext4_xattr_get() returns an int. A very large size is misinterpreted as an error code, which ext4_get_acl() translates into a bogus ERR_PTR() for which IS_ERR() returns false, causing a crash. Fix this by validating that all xattrs are <= INT_MAX bytes. Also add explicit checks in ext4_xattr_block_get() and ext4_xattr_ibody_get() just in case the xattr block is corrupted in memory. Also if the xattr block is corrupted, mark the file system as containing an error. This issue has been assigned CVE-2018-1095. https://bugzilla.kernel.org/show_bug.cgi?id=199185 https://bugzilla.redhat.com/show_bug.cgi?id=1560793 Reported-by: Wen Xu Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org --- fs/ext4/xattr.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 63656dbafdc4..d2a9b078e121 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -195,10 +195,14 @@ ext4_xattr_check_entries(struct ext4_xattr_entry *entry, void *end, /* Check the values */ while (!IS_LAST_ENTRY(entry)) { + u32 size = le32_to_cpu(entry->e_value_size); + + if (size > INT_MAX) + return -EFSCORRUPTED; + if (entry->e_value_size != 0 && entry->e_value_inum == 0) { u16 offs = le16_to_cpu(entry->e_value_offs); - u32 size = le32_to_cpu(entry->e_value_size); void *value; /* @@ -523,8 +527,10 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, if (error) goto cleanup; size = le32_to_cpu(entry->e_value_size); + error = -ERANGE; + if (unlikely(size > INT_MAX)) + goto cleanup; if (buffer) { - error = -ERANGE; if (size > buffer_size) goto cleanup; if (entry->e_value_inum) { @@ -572,8 +578,10 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name, if (error) goto cleanup; size = le32_to_cpu(entry->e_value_size); + error = -ERANGE; + if (unlikely(size > INT_MAX)) + goto cleanup; if (buffer) { - error = -ERANGE; if (size > buffer_size) goto cleanup; if (entry->e_value_inum) {