Received: by 2002:ab2:7b86:0:b0:1f7:5705:b850 with SMTP id q6csp3807lqh; Fri, 3 May 2024 11:26:48 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCU2ECjATYU23qn/5tjGhE4fopjrF/bIhLKGqiBrLrzT0/tC7jXFYUbwr0EyEZYq7Vlu4ToxZB1/sT/BrSyvpCpiZeBVN/VNd6KWN95gYw== X-Google-Smtp-Source: AGHT+IGntwzKd2vEAuuBKcFpGCDJHjg9Ter/ckXvNsErQJiezAniVWnFr5wmCp4pAoQtWgTasI7K X-Received: by 2002:a25:df08:0:b0:de0:f74b:25f3 with SMTP id w8-20020a25df08000000b00de0f74b25f3mr3829536ybg.60.1714760808259; Fri, 03 May 2024 11:26:48 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1714760808; cv=pass; d=google.com; s=arc-20160816; b=G80DSqYpPrx86p+oKADitsGQwHGOJMfbaXP/8bdncpM66gya8/yw43I2GPRLhpPPex 9udVm8CEX2Jv2VNKRHgFhSE+G/bGQG0UhKpPKx2HQLz2eAiVUzyZafGl86dCiARqgUR9 vr76yEdtWv6qP+LI2WwKfhgb3z6IBbE/4Z20dqcTwrdFDG0f++L3N1JruYKmLTfVK8NA 8pn7sNiJshdFDP7+DrRUtIeNwuaTjp0rXjvH/0Pj403KlPmVK6NtR2/dA9Ix2inHZVDS CGvHOARUKN+mPivJoTxa1Am2bLTBdVoAdAghI/GD8PLs67TN4RLSyc9zOU1+AlqKzaCZ jSwg== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=in-reply-to:content-disposition:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:message-id:subject:cc :to:from:date:dkim-signature; bh=jqBoL43PMGyCqFXn3ehXdH+uWie7AbSm2FUzxDYORqI=; fh=bH555N4XewqLk30F/myIqtPKx8ZuT2QU738PkLKdVkA=; b=yRK5EJL9btLxHzKzi9zErND0Yr50OxXL8hum7u3e5Xk8lZOFc0SLF6mWqoq+o+Gsi9 UtxH/Ou1S1Hxa2oNIgBxawmIT90OwM6tKU07I748SkOVqKEWb1jgmIVCAUEnBFSKWAGf JR1+15MDHaYHxwffRaiotJdvC9jH3/9eBICfHz+Y+rX/ER1LLsFTcMJfNjHCYRuaAA9C 1vhqhr+LjKPGP8FGvYEgLQB0Nob5ELyA16ncuOi2Mv9riOzkMaKhlRK6Cek3zYkXRbm/ Ryc047jymrIr6erCpN/tanNotDKcYnmldjuINvd5tnix0EYJlLpEjDSkuJ8ntdWbNUTT 1dKg==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=M9aS+qkc; arc=pass (i=1 spf=pass spfdomain=chromium.org dkim=pass dkdomain=chromium.org dmarc=pass fromdomain=chromium.org); spf=pass (google.com: domain of linux-kernel+bounces-168048-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-168048-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Return-Path: Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [2604:1380:45d1:ec00::1]) by mx.google.com with ESMTPS id bp33-20020a05622a1ba100b0043a29fe920csi3927164qtb.273.2024.05.03.11.26.48 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 03 May 2024 11:26:48 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel+bounces-168048-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) client-ip=2604:1380:45d1:ec00::1; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=M9aS+qkc; arc=pass (i=1 spf=pass spfdomain=chromium.org dkim=pass dkdomain=chromium.org dmarc=pass fromdomain=chromium.org); spf=pass (google.com: domain of linux-kernel+bounces-168048-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-168048-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id E40741C21E79 for ; Fri, 3 May 2024 18:26:47 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 3029A15886E; Fri, 3 May 2024 18:26:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="M9aS+qkc" Received: from mail-pf1-f176.google.com (mail-pf1-f176.google.com [209.85.210.176]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CB68541A80 for ; Fri, 3 May 2024 18:26:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.176 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714760795; cv=none; b=ciC6rNJj1IqvouWdS1POp2eHwmGWZKB59xvynbAlJ7E+9OU9qBcfCrzPEFs28mS91jNFZk+dcFlZJNL+IcQ9ihPOJ1CM16rt5iQs5KjLJaEsM9SCM342Pjb5YIwYa0Au4MUUd7yGX6C8I8FA5Wfr7llvU02C7lFv+H37JVDw28o= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714760795; c=relaxed/simple; bh=Wuw0XjND+rfJBPzq21zocszfotHkDyVdJzVpWm3AfNA=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=b8TNv+04J0ZHoj2vkzl2RHGazEa7qgN5dsXTOhT/dLXsXasHFGfGbGAMtc5uvWmbQ8cyiBtLcBN6UFZ2vgPLj0+/Rlk9TsCugx5crzeDjLPU9UExPGyuSO+Dq382+so3K9Yrg5flZBiFuCHbKunmvenmm5Gt3A71p7yY/y2mfvA= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org; spf=pass smtp.mailfrom=chromium.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b=M9aS+qkc; arc=none smtp.client-ip=209.85.210.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=chromium.org Received: by mail-pf1-f176.google.com with SMTP id d2e1a72fcca58-6f44dc475f4so9154b3a.2 for ; Fri, 03 May 2024 11:26:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1714760793; x=1715365593; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=jqBoL43PMGyCqFXn3ehXdH+uWie7AbSm2FUzxDYORqI=; b=M9aS+qkcreF0Yq+Via4wsh9ECoELo5LsqMdjIkxYRdFFs3834dJmEBcqVBDy3YC9dA 9Cl0NMBRX/qO+kAXJw4gI8IGiM20H3aVk7DKvhzAnRHjyEBGDpz5RqbhVzuTUJ3emQAM sTrp36RbAklquQmS/09Glw8lYjzH2a7p3P/Yc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1714760793; x=1715365593; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=jqBoL43PMGyCqFXn3ehXdH+uWie7AbSm2FUzxDYORqI=; b=uYqIngU8Rhl9Ln3veNZpcgPNiLH8t2RmaSnFUNv43xrIvSZT2Q+1NTXkAHNj1BA1th Ab4B46b3iw76mm+uHIGc8bh8R/F0jczQdhzUH18PkaqNL2ugz12Ad0+ECdqghk4jYhQB Ink20uYQv4PHAJCTzVvC4d3oxOyCfH8ge68pvtFK9vVdzZTqS72LdHgck5LW+AC/lcDX Y11xjiULiulk/quHm609/o3ZlfDAUd6dySwPqMi0nJ/pvuuvOqcHn1FoLQDmV773nJhq TNKvoTZbxEwWw4Zd3skn8o5BX1qrQJKF3/QW6WlBCwJ2zes+NCzg66hTv6AtjImtE85z ViXA== X-Forwarded-Encrypted: i=1; AJvYcCVz5nmraGsjmgX+mU9+W/HoyistoywNHm6Rj2Z4tFrAmhHVzwBBoVdP5apEsGW4dp4E1sLkWLQK5UI5Jd1ZEaYX9lZO1y3RGnYa+I54 X-Gm-Message-State: AOJu0YwWBSD94AhRLRrnzIzZ8cYGInld/dWxVx+qnw4FNPfu53Mki/47 Z3ajwiDfSVpkpVp78FSje4QTEYU1NIfmr7EUo3km4xFRXTI09pcYlx3avid1uw== X-Received: by 2002:a05:6a00:3d06:b0:6e7:20a7:9fc0 with SMTP id lo6-20020a056a003d0600b006e720a79fc0mr3768000pfb.34.1714760793183; Fri, 03 May 2024 11:26:33 -0700 (PDT) Received: from www.outflux.net ([198.0.35.241]) by smtp.gmail.com with ESMTPSA id gp9-20020a056a003b8900b006ea8cc9250bsm3361952pfb.44.2024.05.03.11.26.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 03 May 2024 11:26:32 -0700 (PDT) Date: Fri, 3 May 2024 11:26:32 -0700 From: Kees Cook To: Bui Quang Minh , Al Viro , Christian Brauner Cc: syzbot , axboe@kernel.dk, brauner@kernel.org, io-uring@vger.kernel.org, jack@suse.cz, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com, viro@zeniv.linux.org.uk, Sumit Semwal , Christian =?iso-8859-1?Q?K=F6nig?= , linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org, Laura Abbott Subject: get_file() unsafe under epoll (was Re: [syzbot] [fs?] [io-uring?] general protection fault in __ep_remove) Message-ID: <202405031110.6F47982593@keescook> References: <0000000000002d631f0615918f1e@google.com> <7c41cf3c-2a71-4dbb-8f34-0337890906fc@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <7c41cf3c-2a71-4dbb-8f34-0337890906fc@gmail.com> On Fri, May 03, 2024 at 06:54:22PM +0700, Bui Quang Minh wrote: > [...] > Root cause: > AFAIK, eventpoll (epoll) does not increase the registered file's reference. > To ensure the safety, when the registered file is deallocated in __fput, > eventpoll_release is called to unregister the file from epoll. When calling > poll on epoll, epoll will loop through registered files and call vfs_poll on > these files. In the file's poll, file is guaranteed to be alive, however, as > epoll does not increase the registered file's reference, the file may be > dying > and it's not safe the get the file for later use. And dma_buf_poll violates > this. In the dma_buf_poll, it tries to get_file to use in the callback. This > leads to a race where the dmabuf->file can be fput twice. > > Here is the race occurs in the above proof-of-concept > > close(dmabuf->file) > __fput_sync (f_count == 1, last ref) > f_count-- (f_count == 0 now) > __fput > epoll_wait > vfs_poll(dmabuf->file) > get_file(dmabuf->file)(f_count == 1) > eventpoll_release > dmabuf->file deallocation > fput(dmabuf->file) (f_count == 1) > f_count-- > dmabuf->file deallocation > > I am not familiar with the dma_buf so I don't know the proper fix for the > issue. About the rule that don't get the file for later use in poll callback > of > file, I wonder if it is there when only select/poll exist or just after > epoll > appears. > > I hope the analysis helps us to fix the issue. Thanks for doing this analysis! I suspect at least a start of a fix would be this: diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 8fe5aa67b167..15e8f74ee0f2 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -267,9 +267,8 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll) if (events & EPOLLOUT) { /* Paired with fput in dma_buf_poll_cb */ - get_file(dmabuf->file); - - if (!dma_buf_poll_add_cb(resv, true, dcb)) + if (!atomic_long_inc_not_zero(&dmabuf->file) && + !dma_buf_poll_add_cb(resv, true, dcb)) /* No callback queued, wake up any other waiters */ dma_buf_poll_cb(NULL, &dcb->cb); else @@ -290,9 +289,8 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll) if (events & EPOLLIN) { /* Paired with fput in dma_buf_poll_cb */ - get_file(dmabuf->file); - - if (!dma_buf_poll_add_cb(resv, false, dcb)) + if (!atomic_long_inc_not_zero(&dmabuf->file) && + !dma_buf_poll_add_cb(resv, false, dcb)) /* No callback queued, wake up any other waiters */ dma_buf_poll_cb(NULL, &dcb->cb); else But this ends up leaving "active" non-zero, and at close time it runs into: BUG_ON(dmabuf->cb_in.active || dmabuf->cb_out.active); But the bottom line is that get_file() is unsafe to use in some places, one of which appears to be in the poll handler. There are maybe some other fragile places too, like in drivers/gpu/drm/vmwgfx/ttm_object.c: static bool __must_check get_dma_buf_unless_doomed(struct dma_buf *dmabuf) { return atomic_long_inc_not_zero(&dmabuf->file->f_count) != 0L; } Which I also note involves a dmabuf... Due to this issue I've proposed fixing get_file() to detect pathological states: https://lore.kernel.org/lkml/20240502222252.work.690-kees@kernel.org/ But that has run into some push-back. I'm hoping that seeing this epoll example will help illustrate what needs fixing a little better. I think the best current proposal is to just WARN sooner instead of a full refcount_t implementation: diff --git a/include/linux/fs.h b/include/linux/fs.h index 8dfd53b52744..e09107d0a3d6 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1040,7 +1040,8 @@ struct file_handle { static inline struct file *get_file(struct file *f) { - atomic_long_inc(&f->f_count); + long prior = atomic_long_fetch_inc_relaxed(&f->f_count); + WARN_ONCE(!prior, "struct file::f_count incremented from zero; use-after-free condition present!\n"); return f; } What's the right way to deal with the dmabuf situation? (And I suspect it applies to get_dma_buf_unless_doomed() as well...) -Kees -- Kees Cook