From patchwork Fri Aug 23 22:34:48 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vinicius Peixoto X-Patchwork-Id: 1976308 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ubuntu.com (client-ip=185.125.189.65; helo=lists.ubuntu.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=patchwork.ozlabs.org) Received: from lists.ubuntu.com (lists.ubuntu.com [185.125.189.65]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4WrFJK0gqnz1ydn for ; Sat, 24 Aug 2024 08:35:12 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=lists.ubuntu.com) by lists.ubuntu.com with esmtp (Exim 4.86_2) (envelope-from ) id 1shcs2-0000GG-Vq; Fri, 23 Aug 2024 22:35:02 +0000 Received: from smtp-relay-internal-0.internal ([10.131.114.225] helo=smtp-relay-internal-0.canonical.com) by lists.ubuntu.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1shcs1-0000FF-1p for kernel-team@lists.ubuntu.com; Fri, 23 Aug 2024 22:35:01 +0000 Received: from mail-pf1-f198.google.com (mail-pf1-f198.google.com [209.85.210.198]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id 9AC063FD49 for ; Fri, 23 Aug 2024 22:35:00 +0000 (UTC) Received: by mail-pf1-f198.google.com with SMTP id d2e1a72fcca58-7142a78918bso2837873b3a.0 for ; Fri, 23 Aug 2024 15:35:00 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1724452498; x=1725057298; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=IfTsEJGMrD2KvPztTMtEDRoomXz0/RYiUdhiDWEf0wk=; b=ZfdCYbZKEN9lWLgYgtsWPmpmAsIQz9nojj0DnB1f0i/NtCKqjvnFI2H3Z0+SvULu3G XP+J5afulPZqiuARDeb3m/yHwPh1IRr+jD5QDs1UMiY9y8msAvU8X/WBVmIEUijIB45+ L3iZqXf1j6dV5443ytAcih6aZgdksnYcXSD62fmDhl39gdylCZomDOq2wi/hUbuAd6ad t0uKY3dxUTDTpPQkd3yiC1Vq+/llKH8Jjx6bY8AFg6WF0N5o1+0xrT8jH4FOWPfSEomT nO8j59XvOPti7/Ozm2AP8STD6Y0TOVqomNHuKyCH/tsCfD8Q/IyUOcMIWOgxw3cBMn4H NkFw== X-Gm-Message-State: AOJu0YxLUQRVPsatHmF7kIPP7KIaNsWAAzJvZB+jvHuWS36uC8wobHxO KTEkGihEdzG3tygy9BBuvEKexMGOCfPIuXFmTeFEnXoNHfnz+zWd+c+WYK8vnaU6jyDcAKXFVf9 1leKor4XndE5xGFTA4C3ptnKVJK0DLcOpiSOC6N/tPMMx7fcYaTbrmqsv54KcQfoD9PO4kDISfo fo/fAdl96aTQ== X-Received: by 2002:a05:6a00:1805:b0:714:3325:d8e9 with SMTP id d2e1a72fcca58-71445e1153fmr4823745b3a.22.1724452497483; Fri, 23 Aug 2024 15:34:57 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGkMtgM74qAQ1NwE8SWRXF260FG1E/Jj8SKb36K6XV/OlqJueDHBgBevDsNE5RoaSHpcYCdCw== X-Received: by 2002:a05:6a00:1805:b0:714:3325:d8e9 with SMTP id d2e1a72fcca58-71445e1153fmr4823722b3a.22.1724452497023; Fri, 23 Aug 2024 15:34:57 -0700 (PDT) Received: from canonical.com ([2804:1b3:a700:61a1:441f:b276:abf6:ca1f]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7143422ed7esm3523572b3a.6.2024.08.23.15.34.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 23 Aug 2024 15:34:56 -0700 (PDT) From: Vinicius Peixoto To: kernel-team@lists.ubuntu.com Subject: [SRU][J][PATCH 1/1] btrfs: zoned: fix use-after-free due to race with dev replace Date: Fri, 23 Aug 2024 19:34:48 -0300 Message-ID: <20240823223448.692285-2-vinicius.peixoto@canonical.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240823223448.692285-1-vinicius.peixoto@canonical.com> References: <20240823223448.692285-1-vinicius.peixoto@canonical.com> MIME-Version: 1.0 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: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" While loading a zone's info during creation of a block group, we can race with a device replace operation and then trigger a use-after-free on the device that was just replaced (source device of the replace operation). This happens because at btrfs_load_zone_info() we extract a device from the chunk map into a local variable and then use the device while not under the protection of the device replace rwsem. So if there's a device replace operation happening when we extract the device and that device is the source of the replace operation, we will trigger a use-after-free if before we finish using the device the replace operation finishes and frees the device. Fix this by enlarging the critical section under the protection of the device replace rwsem so that all uses of the device are done inside the critical section. CC: stable@vger.kernel.org # 6.1.x: 15c12fcc50a1: btrfs: zoned: introduce a zone_info struct in btrfs_load_block_group_zone_info CC: stable@vger.kernel.org # 6.1.x: 09a46725cc84: btrfs: zoned: factor out per-zone logic from btrfs_load_block_group_zone_info CC: stable@vger.kernel.org # 6.1.x: 9e0e3e74dc69: btrfs: zoned: factor out single bg handling from btrfs_load_block_group_zone_info CC: stable@vger.kernel.org # 6.1.x: 87463f7e0250: btrfs: zoned: factor out DUP bg handling from btrfs_load_block_group_zone_info CC: stable@vger.kernel.org # 6.1.x Reviewed-by: Johannes Thumshirn Signed-off-by: Filipe Manana Reviewed-by: David Sterba Signed-off-by: David Sterba (backported from commit 0090d6e1b210551e63cf43958dc7a1ec942cdde9) [vpeixoto: upstream commit 09a46725cc84 ("btrfs: zoned: factor out per-zone logic from btrfs_load_block_group_zone_info") is missing and extracts some logic from btrfs_load_block_group_zone_info into its own separate function, btrfs_load_zone_info. Since what the fix commit does is essentially enlarging the critical section where we hold a r/w semaphore in order to avoid a UAF, and the logic is basically the same before and after the missing upstream refactor, I adapted it to the old context manually.] CVE-2024-39496 Signed-off-by: Vinicius Peixoto --- fs/btrfs/zoned.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c index 8c858f31bdbc0..1c07fbd01bced 100644 --- a/fs/btrfs/zoned.c +++ b/fs/btrfs/zoned.c @@ -1156,10 +1156,12 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new) struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; int dev_replace_is_ongoing = 0; + down_read(&dev_replace->rwsem); device = map->stripes[i].dev; physical = map->stripes[i].physical; if (device->bdev == NULL) { + up_read(&dev_replace->rwsem); alloc_offsets[i] = WP_MISSING_DEV; continue; } @@ -1171,6 +1173,7 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new) num_conventional++; if (!is_sequential) { + up_read(&dev_replace->rwsem); alloc_offsets[i] = WP_CONVENTIONAL; continue; } @@ -1181,11 +1184,9 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new) */ btrfs_dev_clear_zone_empty(device, physical); - down_read(&dev_replace->rwsem); dev_replace_is_ongoing = btrfs_dev_replace_is_ongoing(dev_replace); if (dev_replace_is_ongoing && dev_replace->tgtdev != NULL) btrfs_dev_clear_zone_empty(dev_replace->tgtdev, physical); - up_read(&dev_replace->rwsem); /* * The group is mapped to a sequential zone. Get the zone write @@ -1196,6 +1197,7 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new) ret = btrfs_get_dev_zone(device, physical, &zone); memalloc_nofs_restore(nofs_flag); if (ret == -EIO || ret == -EOPNOTSUPP) { + up_read(&dev_replace->rwsem); ret = 0; alloc_offsets[i] = WP_MISSING_DEV; continue; @@ -1208,6 +1210,7 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new) "zoned: unexpected conventional zone %llu on device %s (devid %llu)", zone.start << SECTOR_SHIFT, rcu_str_deref(device->name), device->devid); + up_read(&dev_replace->rwsem); ret = -EIO; goto out; } @@ -1233,6 +1236,8 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new) ((zone.wp - zone.start) << SECTOR_SHIFT); break; } + + up_read(&dev_replace->rwsem); } if (num_sequential > 0)