From patchwork Fri Jun 22 21:43:58 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Seth Forshee X-Patchwork-Id: 933619 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41CBst0zxhz9s3R; Sat, 23 Jun 2018 07:44:18 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1fWTqj-0004LV-Ap; Fri, 22 Jun 2018 21:44:09 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:128) (Exim 4.86_2) (envelope-from ) id 1fWTqg-0004Km-Vi for kernel-team@lists.ubuntu.com; Fri, 22 Jun 2018 21:44:06 +0000 Received: from mail-io0-f197.google.com ([209.85.223.197]) by youngberry.canonical.com with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1fWTqg-00029E-LF for kernel-team@lists.ubuntu.com; Fri, 22 Jun 2018 21:44:06 +0000 Received: by mail-io0-f197.google.com with SMTP id v10-v6so6152688iog.18 for ; Fri, 22 Jun 2018 14:44:06 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=ogN82aE4LlomWWCmrZIfbd/oJsAsrflaxyeF5KE0Mps=; b=t5ddRS8tv69oa49yKWlc33AYuM5k2sE/PLHNTEXBJqNc1tF7vFSsiyzMgWaMgbQhdu 3nymMxyL7Wjw1edn8hvzvNkiZ6LiQf0dmhgpN2PUL03ane89wiMdjfydjrCeTlnPJokO VoITqIic4MUg4iFJGoV4SboL4iTVJKN7yqfWAIXVVudw2+efaXJdGTAjFXsvGtwhA6HY yqq1bpyeDttbIkcGifoxYpJyROkSPZKlq/Ncce6/dmEBGVVghX7QNNzmf4mNAwRFU0su F2kTI7BgKscwOYLzZsN/oKX1bacy29Qp3L69P4U4C4uwcWGUPdQxfZq+ifoM0ZU6YZNz YN+w== X-Gm-Message-State: APt69E10jQwUlGKdy23AAHV/UmYmAn7vcehRRC5TnO0eJhxaWbOaAuMt R2Uoy2vVJOVviabs7j0sMb/FKvqZjZjySKHBedC+6Xz0FQNhIUhPMowS1M3b42R6IuhNRYWcibE 7rKe9E9As0nIzrBXBeAxn4K86htMR26cZ4rHL1txh7g== X-Received: by 2002:a6b:3bcb:: with SMTP id i194-v6mr2703867ioa.86.1529703845333; Fri, 22 Jun 2018 14:44:05 -0700 (PDT) X-Google-Smtp-Source: AAOMgpdSyWdw79LObYPb6QUNfnxhlvXzlrGAL31FEEKp6d8Rd901vW4u7gEMZUj5IXtjynS6ckSKHw== X-Received: by 2002:a6b:3bcb:: with SMTP id i194-v6mr2703863ioa.86.1529703845056; Fri, 22 Jun 2018 14:44:05 -0700 (PDT) Received: from localhost ([2605:a601:ac7:2a20:110:4491:9f96:3555]) by smtp.gmail.com with ESMTPSA id 81-v6sm181452itv.39.2018.06.22.14.44.03 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 22 Jun 2018 14:44:04 -0700 (PDT) From: Seth Forshee To: kernel-team@lists.ubuntu.com Subject: [SRU][Xenial][PATCH 3/4] capabilities: fix buffer overread on very short xattr Date: Fri, 22 Jun 2018 16:43:58 -0500 Message-Id: <20180622214359.17903-4-seth.forshee@canonical.com> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180622214359.17903-1-seth.forshee@canonical.com> References: <20180622214359.17903-1-seth.forshee@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Eric Biggers BugLink: http://bugs.launchpad.net/bugs/1778286 If userspace attempted to set a "security.capability" xattr shorter than 4 bytes (e.g. 'setfattr -n security.capability -v x file'), then cap_convert_nscap() read past the end of the buffer containing the xattr value because it accessed the ->magic_etc field without verifying that the xattr value is long enough to contain that field. Fix it by validating the xattr value size first. This bug was found using syzkaller with KASAN. The KASAN report was as follows (cleaned up slightly): BUG: KASAN: slab-out-of-bounds in cap_convert_nscap+0x514/0x630 security/commoncap.c:498 Read of size 4 at addr ffff88002d8741c0 by task syz-executor1/2852 CPU: 0 PID: 2852 Comm: syz-executor1 Not tainted 4.15.0-rc6-00200-gcc0aac99d977 #253 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.11.0-20171110_100015-anatol 04/01/2014 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0xe3/0x195 lib/dump_stack.c:53 print_address_description+0x73/0x260 mm/kasan/report.c:252 kasan_report_error mm/kasan/report.c:351 [inline] kasan_report+0x235/0x350 mm/kasan/report.c:409 cap_convert_nscap+0x514/0x630 security/commoncap.c:498 setxattr+0x2bd/0x350 fs/xattr.c:446 path_setxattr+0x168/0x1b0 fs/xattr.c:472 SYSC_setxattr fs/xattr.c:487 [inline] SyS_setxattr+0x36/0x50 fs/xattr.c:483 entry_SYSCALL_64_fastpath+0x18/0x85 Fixes: 8db6c34f1dbc ("Introduce v3 namespaced file capabilities") Cc: # v4.14+ Signed-off-by: Eric Biggers Reviewed-by: Serge Hallyn Signed-off-by: James Morris (cherry picked from commit dc32b5c3e6e2ef29cef76d9ce1b92d394446150e) Signed-off-by: Seth Forshee --- security/commoncap.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/security/commoncap.c b/security/commoncap.c index 6b4a8788c753..d42373adb762 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -359,21 +359,18 @@ static __u32 sansflags(__u32 m) return m & ~VFS_CAP_FLAGS_EFFECTIVE; } -static bool is_v2header(size_t size, __le32 magic) +static bool is_v2header(size_t size, const struct vfs_cap_data *cap) { - __u32 m = le32_to_cpu(magic); if (size != XATTR_CAPS_SZ_2) return false; - return sansflags(m) == VFS_CAP_REVISION_2; + return sansflags(le32_to_cpu(cap->magic_etc)) == VFS_CAP_REVISION_2; } -static bool is_v3header(size_t size, __le32 magic) +static bool is_v3header(size_t size, const struct vfs_cap_data *cap) { - __u32 m = le32_to_cpu(magic); - if (size != XATTR_CAPS_SZ_3) return false; - return sansflags(m) == VFS_CAP_REVISION_3; + return sansflags(le32_to_cpu(cap->magic_etc)) == VFS_CAP_REVISION_3; } /* @@ -416,7 +413,7 @@ int cap_inode_getsecurity(const struct inode *inode, const char *name, fs_ns = inode->i_sb->s_user_ns; cap = (struct vfs_cap_data *) tmpbuf; - if (is_v2header((size_t) ret, cap->magic_etc)) { + if (is_v2header((size_t) ret, cap)) { /* If this is sizeof(vfs_cap_data) then we're ok with the * on-disk value, so return that. */ if (alloc) @@ -424,7 +421,7 @@ int cap_inode_getsecurity(const struct inode *inode, const char *name, else kfree(tmpbuf); return ret; - } else if (!is_v3header((size_t) ret, cap->magic_etc)) { + } else if (!is_v3header((size_t) ret, cap)) { kfree(tmpbuf); return -EINVAL; } @@ -481,9 +478,9 @@ static kuid_t rootid_from_xattr(const void *value, size_t size, return make_kuid(task_ns, rootid); } -static bool validheader(size_t size, __le32 magic) +static bool validheader(size_t size, const struct vfs_cap_data *cap) { - return is_v2header(size, magic) || is_v3header(size, magic); + return is_v2header(size, cap) || is_v3header(size, cap); } /* @@ -506,7 +503,7 @@ int cap_convert_nscap(struct dentry *dentry, void **ivalue, size_t size) if (!*ivalue) return -EINVAL; - if (!validheader(size, cap->magic_etc)) + if (!validheader(size, cap)) return -EINVAL; if (!capable_wrt_inode_uidgid(inode, CAP_SETFCAP)) return -EPERM;