Received: by 10.213.65.68 with SMTP id h4csp2170928imn; Sun, 8 Apr 2018 21:35:03 -0700 (PDT) X-Google-Smtp-Source: AIpwx48d8TM5E19CQTPC2pRG4D+9SWW/+iW/iAhZ4ZmN3dZJQ7nt3mV4/IYtEJBgxu/FZwhlpMNO X-Received: by 2002:a17:902:887:: with SMTP id 7-v6mr37697094pll.319.1523248503887; Sun, 08 Apr 2018 21:35:03 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1523248503; cv=none; d=google.com; s=arc-20160816; b=xmh4ew/W6Vy+GQOAjrpLuoEsuuT4hrdkV5vVyFtVdqMiDTKizeo2ZTjw2lDllndkGb KZkKNdbwfI0E/8XEfG9pCZkP7MRDsk25A+uH0xLSTgaFLl34hhr2gpP41S9sROUB4zNZ w4JKiOGFiGw8WZBGI15gv/Qj1R0vcRJi8ctmW/5PwOCHuySUY3foqMIpcGxzX3g8GIxX 4vSAOTIj2iyI/rDyU7BcwPj1CKtwpqAcCjkwICQ2w9xiK7OuxeCMkBH4xUDRTW+pEOac XEOd3mjzY1aD0AICx6/ZzRbCu4u6iZ88tG+3LeCJml+YtW25Dhi1zh8HZiVYr60te51V TyUw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=pBxi8e1wAuS3cVwekBAcKO353qZCFyUDURieltFxGms=; b=nvmhe62ythFriqJEf9mRaiPxUSLNr04+0gkgFeAcwuW9exy/IztztnOXNORe7XOubm bzvEPnyOISnKeLHuNs+Y7P75duMWNVdTv8PmQCRU6Ze+xD7zSaln7X3biQE6HP+lfKpw +SjJaM89KkAv63Z9WWDfmnrPV28WyUI8yH88nAHXRnW51Ha/OMiq0A4BG/4n9H/J2yOG UsXMHTjHUZdRCvAbN5MoqAH8zRYuGOU5l2Yhx+dTam24x2L7d4dMMIQ1RALLUi/7P6oZ Xstgiv1oPlp67q+D4z35cwkVx7KcgH/t58G/hOScZyPbBXh9BN1JZ06CKCWhIxaawXuB POGg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=BoFMxHbU; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id v8si9949181pff.125.2018.04.08.21.34.26; Sun, 08 Apr 2018 21:35:03 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=BoFMxHbU; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752200AbeDIEb0 (ORCPT + 99 others); Mon, 9 Apr 2018 00:31:26 -0400 Received: from mail-pl0-f66.google.com ([209.85.160.66]:41281 "EHLO mail-pl0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750925AbeDIEbY (ORCPT ); Mon, 9 Apr 2018 00:31:24 -0400 Received: by mail-pl0-f66.google.com with SMTP id bj1-v6so4398833plb.8; Sun, 08 Apr 2018 21:31:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=pBxi8e1wAuS3cVwekBAcKO353qZCFyUDURieltFxGms=; b=BoFMxHbU5tPjZXMBlUMA68+7L1r+iwSl6xGBbI2XjLTRunlXDcTYEpXGhPHPE/OokG e5DQUnAEus2sa/WGY2UBFbH27htAPS4G56K7VH5AMajyCrBz0hUrQOak3r7/GYG4ti+T aWXTTpnMhax+y73ELTMJhsRJ5J7s2aWS/5KAYqwLE6LeL2uIN4M/HYc+vli9eBognpBC LbY5gguJBeSmLhEPz0Zy22q6fvZxsx+R0/NcAekPx/eU5TlnRiEd9UveF9uA01WTNb1H ZusNsl7E7IMf2b7g074DfClwBf7A5GyuO/H31ctWmuT4xs3ECee+QNMpGee+tyTDRVMq TkXQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=pBxi8e1wAuS3cVwekBAcKO353qZCFyUDURieltFxGms=; b=lybZ0poZPLa3ivzQSm9amoj61NEgRwpwJ8zSIwMDqhCkT80Rv7OXqNTx700MQQrrej 2JbMDvuYruMl9qTX0zrxLr1OScb3WUDNXQB/F7eIr+z/HFticdjyLFF/gMYOaw5p0M2r MXPilYb0o2Nzlj5SW7y2B2OP8FKBdo+BuDqpGAderWz4WRPkTZmumMcuUKBhRVXKfLl/ DUQy7jDGjl1vaCnFRk08Yja0NsD5lK1+CqPuVXa2PjFK747OPtLXkLUwxVEoiPQioGOW M05pu8KZpJJ40cW4hzfRrnsWy1xpHmtTEtzG3+fqKQ0z1H40weR6R90+hysvJxyDNRKw rnpQ== X-Gm-Message-State: ALQs6tDVgpRvRRHmXkpH3dm9MldNY2LhqXXReF57zqY7oRvXJHf1FZuY Tqi7Sqciy5Fd6SA3h9ydT5Q= X-Received: by 2002:a17:902:b411:: with SMTP id x17-v6mr2378879plr.402.1523248282147; Sun, 08 Apr 2018 21:31:22 -0700 (PDT) Received: from sol.localdomain (c-67-185-97-198.hsd1.wa.comcast.net. [67.185.97.198]) by smtp.gmail.com with ESMTPSA id j65sm27690174pge.58.2018.04.08.21.31.20 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 08 Apr 2018 21:31:21 -0700 (PDT) From: Eric Biggers To: linux-mm@kvack.org, Andrew Morton Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, "Kirill A . Shutemov" , Davidlohr Bueso , Manfred Spraul , "Eric W . Biederman" , syzkaller-bugs@googlegroups.com Subject: [PATCH] ipc/shm: fix use-after-free of shm file via remap_file_pages() Date: Sun, 8 Apr 2018 21:30:39 -0700 Message-Id: <20180409043039.28915-1-ebiggers3@gmail.com> X-Mailer: git-send-email 2.17.0 In-Reply-To: <94eb2c06f65e5e2467055d036889@google.com> References: <94eb2c06f65e5e2467055d036889@google.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Eric Biggers syzbot reported a use-after-free of shm_file_data(file)->file->f_op in shm_get_unmapped_area(), called via sys_remap_file_pages(). Unfortunately it couldn't generate a reproducer, but I found a bug which I think caused it. When remap_file_pages() is passed a full System V shared memory segment, the memory is first unmapped, then a new map is created using the ->vm_file. Between these steps, the shm ID can be removed and reused for a new shm segment. But, shm_mmap() only checks whether the ID is currently valid before calling the underlying file's ->mmap(); it doesn't check whether it was reused. Thus it can use the wrong underlying file, one that was already freed. Fix this by making the "outer" shm file (the one that gets put in ->vm_file) hold a reference to the real shm file, and by making __shm_open() require that the file associated with the shm ID matches the one associated with the "outer" file. Commit 1ac0b6dec656 ("ipc/shm: handle removed segments gracefully in shm_mmap()") almost fixed this bug, but it didn't go far enough because it didn't consider the case where the shm ID is reused. The following program usually reproduces this bug: #include #include #include #include int main() { int is_parent = (fork() != 0); srand(getpid()); for (;;) { int id = shmget(0xF00F, 4096, IPC_CREAT|0700); if (is_parent) { void *addr = shmat(id, NULL, 0); usleep(rand() % 50); while (!syscall(__NR_remap_file_pages, addr, 4096, 0, 0, 0)); } else { usleep(rand() % 50); shmctl(id, IPC_RMID, NULL); } } } It causes the following NULL pointer dereference due to a 'struct file' being used while it's being freed. (I couldn't actually get a KASAN use-after-free splat like in the syzbot report. But I think it's possible with this bug; it would just take a more extraordinary race...) BUG: unable to handle kernel NULL pointer dereference at 0000000000000058 PGD 0 P4D 0 Oops: 0000 [#1] SMP NOPTI CPU: 9 PID: 258 Comm: syz_ipc Not tainted 4.16.0-05140-gf8cf2f16a7c95 #189 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.11.0-20171110_100015-anatol 04/01/2014 RIP: 0010:d_inode include/linux/dcache.h:519 [inline] RIP: 0010:touch_atime+0x25/0xd0 fs/inode.c:1724 [...] Call Trace: file_accessed include/linux/fs.h:2063 [inline] shmem_mmap+0x25/0x40 mm/shmem.c:2149 call_mmap include/linux/fs.h:1789 [inline] shm_mmap+0x34/0x80 ipc/shm.c:465 call_mmap include/linux/fs.h:1789 [inline] mmap_region+0x309/0x5b0 mm/mmap.c:1712 do_mmap+0x294/0x4a0 mm/mmap.c:1483 do_mmap_pgoff include/linux/mm.h:2235 [inline] SYSC_remap_file_pages mm/mmap.c:2853 [inline] SyS_remap_file_pages+0x232/0x310 mm/mmap.c:2769 do_syscall_64+0x64/0x1a0 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 Reported-by: syzbot+d11f321e7f1923157eac80aa990b446596f46439@syzkaller.appspotmail.com Fixes: c8d78c1823f4 ("mm: replace remap_file_pages() syscall with emulation") Cc: stable@vger.kernel.org Signed-off-by: Eric Biggers --- ipc/shm.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/ipc/shm.c b/ipc/shm.c index acefe44fefefa..c80c5691a9970 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -225,6 +225,12 @@ static int __shm_open(struct vm_area_struct *vma) if (IS_ERR(shp)) return PTR_ERR(shp); + if (shp->shm_file != sfd->file) { + /* ID was reused */ + shm_unlock(shp); + return -EINVAL; + } + shp->shm_atim = ktime_get_real_seconds(); ipc_update_pid(&shp->shm_lprid, task_tgid(current)); shp->shm_nattch++; @@ -455,8 +461,9 @@ static int shm_mmap(struct file *file, struct vm_area_struct *vma) int ret; /* - * In case of remap_file_pages() emulation, the file can represent - * removed IPC ID: propogate shm_lock() error to caller. + * In case of remap_file_pages() emulation, the file can represent an + * IPC ID that was removed, and possibly even reused by another shm + * segment already. Propagate this case as an error to caller. */ ret = __shm_open(vma); if (ret) @@ -480,6 +487,7 @@ static int shm_release(struct inode *ino, struct file *file) struct shm_file_data *sfd = shm_file_data(file); put_ipc_ns(sfd->ns); + fput(sfd->file); shm_file_data(file) = NULL; kfree(sfd); return 0; @@ -1432,7 +1440,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, file->f_mapping = shp->shm_file->f_mapping; sfd->id = shp->shm_perm.id; sfd->ns = get_ipc_ns(ns); - sfd->file = shp->shm_file; + sfd->file = get_file(shp->shm_file); sfd->vm_ops = NULL; err = security_mmap_file(file, prot, flags); -- 2.17.0