From nobody Mon Jun 8 09:48:26 2026 Received: from mail-pg1-f179.google.com (mail-pg1-f179.google.com [209.85.215.179]) (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 5F49F27A476 for ; Sat, 30 May 2026 14:35:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780151725; cv=none; b=FeE1kWoootmGB6mO5MmGNlGR84t+v2PXG0GdsYk2VJ+iq8W6rzIrcTEBSyyQV2FTAPJeZImGagcmYZOujTOyy4i4kuqpg4z5kDxXZLAp7PZ5bqLE1oHExh2x8+ZpawG5/sau9OAsXjyU8A4jIRhhgdnECFRcAHxYb6YO/eA/7+0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780151725; c=relaxed/simple; bh=1vMLDFW2kS1bQAd09CHs2LUwo+EJDU2ey1BN1xmTXDg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jxKnKIfgZ817v1wDTEqCuIBC666F/YpyQfj2j3UQLI3E89onGX/7OLn40pTO69L4EaL5hZIhLLRCb+A0ZzwFsaP5OU7hD2thKXzr3fS5wOj8e4J3FIERgqPgGfyCHF5zKMQiPEVoiyOGeT+P2CGSIDOjauveG+P4lsIkGp7kLcY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Q4Hnx25d; arc=none smtp.client-ip=209.85.215.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Q4Hnx25d" Received: by mail-pg1-f179.google.com with SMTP id 41be03b00d2f7-c85631bab7cso121595a12.1 for ; Sat, 30 May 2026 07:35:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780151724; x=1780756524; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=RMlzIjbJAEGK5SSnf3zQHzXypQFZNks5QNE1s4jLr2s=; b=Q4Hnx25dI2sUDoeThbyrWAN2mQvsnwVuK7Thkm7lLeMEnLALvVPK2e3zijmkhW5Qnf CYH/tqm2Mjpa0h8RRAVQrEeaTFFd0cn2vKTJ1YsZnjlP2xhJ8DIV63GhBRF8rNOugevj Aka7HSFg/U6nXmQi2lHGxBW4RfAX5cQtbPcIpRacSrUIvDGyhHVhlnlbauwQaZRJKfu8 jRl8q0fs9dewjus+d1WFYscBIC9ONhIBR6cXS+uUd0MS7UslQML3a7GOPwtxJV0+qIKP F9tOuMJg5kXhdipLXaq3Bby8WKVcK+AlpwemOuHZE5qVWkX25TKR0Azcg1cHwI+jZk/f rONA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780151724; x=1780756524; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=RMlzIjbJAEGK5SSnf3zQHzXypQFZNks5QNE1s4jLr2s=; b=P03/y7XDSqq34jqInxgZKVDPstrnP/Hvk0KekjBpqxB6LU67czLhNlVoMenrdqzn2u kp4yxPefXeGa5nxOp15z6oIZuIVQJ73BIyOg+pgt48dZfyMLfVFaUED+GCBJCe4LFLST bXLz4cC//u8KteO7tIgjHoYHWAPq1Z+n1V1Roh48gILObTN6IXvK5DipYCikT5oyfhUx VRu407RvHndtkicrKnIIy1BthJFSXACD1oDEFvpCwAqIRisIRoqaOz7C19N89W/LWZ0d +xxWP372vOWweoQjPStlrnMfuELpgSii6jOK6eTQ09s5C3mMBT5QRgQK+063geju3J9M 74NA== X-Forwarded-Encrypted: i=1; AFNElJ8wofBcfsMJqjXOz55dXgc8KVP3RkYy3fkLCsKI2SzY7Rwv4cXmBugA4gA/8xMLgtR4YMQGe95gtqNtLpc=@vger.kernel.org X-Gm-Message-State: AOJu0YwhTI+tBenVMQhkqW/t7sU6Rcp0cNEsLQsrDMtoFkwiOC8r2C47 4q08R6vX04dEGviYTeXkSW2MA0c3s74bdA/CIvahVAEAY+mSglXkCM1ihfePTA== X-Gm-Gg: Acq92OH7mWT5icCL1fpx5ocdsJ9rblhVUwFVvCtCEuPFbPcwhDKkMXqdL7INlRtH8Tz vOZvJzVOAI4OdkB6xmV+uJtssboxEWXw72LIeWSVZ3k5JgwO7kgoSkfRxVyOA2SjekR3qwIlZhR +DIkYG4607WNTva/WCLD1OkaUiKW55j3zwLn2sJDNMK3Xtng2esTyGaZRuTDMpOn/tQKW0j+D9K jjrpkJcU7NdYa+N/D0oGjUY7bgaWQVfpBA4b8gOqGxcIxSzxuSGWAdlj8GZhAmYgb8ZO6qUIkrf n5EsIhzJTn++jGyD9Bw9xgtDhGs+KF+32fPg3dOkpxyvAtbIl3wuXwlUlXpBg9+BbWT1h550EYE NTdrp+B+oMmEYRhJjKIU7h4H8snjGslsEfKR/fTU+L7wGhVz9UuWKojWsh8i+6AYt3RwzFdEsrV G7rVlkUjkYnGFKgbA6wXiEcta34lU= X-Received: by 2002:a05:6a00:bd01:b0:837:42a6:58a8 with SMTP id d2e1a72fcca58-84225333708mr2001962b3a.2.1780151723402; Sat, 30 May 2026 07:35:23 -0700 (PDT) Received: from ser8.. ([221.156.231.192]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-84214b2acb7sm5832280b3a.13.2026.05.30.07.35.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 30 May 2026 07:35:23 -0700 (PDT) From: DaeMyung Kang To: Namjae Jeon , Hyunchul Lee Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, DaeMyung Kang Subject: [PATCH v4 1/6] ntfs: validate attribute values on lookup Date: Sat, 30 May 2026 23:35:09 +0900 Message-ID: <20260530143514.3083601-2-charsyam@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260530143514.3083601-1-charsyam@gmail.com> References: <20260530143514.3083601-1-charsyam@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" ntfs_attr_find() and ntfs_external_attr_find() check that generic resident attribute values fit in their attribute records and that fixed-size resident values are large enough. For variable-length resident formats, however, the fixed part is not enough: embedded length fields can still point callers past the resident value. A crafted image can set a small resident $FILE_NAME value_length while leaving file_name_length large. Callers then trust file_name_length and read past the resident value when converting or comparing the name. This was reproduced with a crafted image under KASAN as a slab-out-of-bounds read from the kmalloc-1k MFT record copy. The stack included ntfs_lookup(), ntfs_iget(), ntfs_read_locked_inode(), ntfs_attr_name_get(), ntfs_ucstonls(), and utf16s_to_utf8s(). Add a shared attribute value validator and use it before a lookup path can return an attribute, including the AT_UNUSED enumeration case where callers inspect returned attributes directly. The helper validates resident value bounds, minimum resident value sizes, variable-length $FILE_NAME fields, and non-resident mapping-pairs metadata that was previously checked separately in both lookup paths. This also preserves the intended resident @val matching semantics in the external attribute lookup path. The old duplicated validation block overwrote the actual resident value length with the type-specific minimum length before comparing @val, so variable-length resident values could fail to match even when the bytes were identical. Keep the comparison on the actual value length, and make ntfs_attrlist_entry_add() compare resident attributes with lowest_vcn zero instead of reading the non-resident union member after a successful resident match. Reject non-resident $FILE_NAME records too: the format requires $FILE_NAME to be resident and callers treat returned records as resident. Fixes: 6ceb4cc81ef3 ("ntfs: add bound checking to ntfs_attr_find") Signed-off-by: DaeMyung Kang --- fs/ntfs/attrib.c | 160 +++++++++++++++++++++++++++++++++----------------= ---- fs/ntfs/attrlist.c | 11 +++- 2 files changed, 107 insertions(+), 64 deletions(-) diff --git a/fs/ntfs/attrlist.c b/fs/ntfs/attrlist.c index c2594d4c83b0..afb13038ba42 100644 --- a/fs/ntfs/attrlist.c +++ b/fs/ntfs/attrlist.c @@ -118,6 +118,7 @@ int ntfs_attrlist_entry_add(struct ntfs_inode *ni, stru= ct attr_record *attr) int entry_len, entry_offset, err; struct mft_record *ni_mrec; u8 *old_al; + __le64 lowest_vcn; =20 if (!ni || !attr) { ntfs_debug("Invalid arguments.\n"); @@ -158,17 +159,21 @@ int ntfs_attrlist_entry_add(struct ntfs_inode *ni, st= ruct attr_record *attr) ntfs_error(ni->vol->sb, "Failed to get search context"); goto err_out; } + if (attr->non_resident) + lowest_vcn =3D attr->data.non_resident.lowest_vcn; + else + lowest_vcn =3D 0; =20 err =3D ntfs_attr_lookup(attr->type, (attr->name_length) ? (__le16 *) ((u8 *)attr + le16_to_cpu(attr->name_offset)) : AT_UNNAMED, attr->name_length, CASE_SENSITIVE, - (attr->non_resident) ? le64_to_cpu(attr->data.non_resident.lowest_vcn) : - 0, (attr->non_resident) ? NULL : ((u8 *)attr + + le64_to_cpu(lowest_vcn), + (attr->non_resident) ? NULL : ((u8 *)attr + le16_to_cpu(attr->data.resident.value_offset)), (attr->non_resident) ? 0 : le32_to_cpu(attr->data.resident.value_length), ctx); if (!err) { /* Found some extent, check it to be before new extent. */ - if (ctx->al_entry->lowest_vcn =3D=3D attr->data.non_resident.lowest_vcn)= { + if (ctx->al_entry->lowest_vcn =3D=3D lowest_vcn) { err =3D -EEXIST; ntfs_debug("Such attribute already present in the attribute list.\n"); ntfs_attr_put_search_ctx(ctx); diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 421c6cdcbb53..98e0b8ea2edd 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -595,6 +595,97 @@ static u32 ntfs_resident_attr_min_value_length(const _= _le32 type) } } =20 +static bool ntfs_file_name_attr_value_is_valid(const u8 *value, const u32 = value_length) +{ + const struct file_name_attr *fn; + u32 file_name_size; + + fn =3D (const struct file_name_attr *)value; + file_name_size =3D fn->file_name_length * sizeof(__le16); + + return file_name_size <=3D + value_length - offsetof(struct file_name_attr, file_name); +} + +struct ntfs_resident_attr_value { + const u8 *data; + u32 len; +}; + +static bool ntfs_resident_attr_value_get(const struct attr_record *a, + struct ntfs_resident_attr_value *value) +{ + u32 attr_len; + u16 value_offset; + + attr_len =3D le32_to_cpu(a->length); + if (attr_len < offsetof(struct attr_record, data.resident.reserved) + + sizeof(a->data.resident.reserved)) + return false; + + value->len =3D le32_to_cpu(a->data.resident.value_length); + value_offset =3D le16_to_cpu(a->data.resident.value_offset); + + if (value->len > attr_len || value_offset > attr_len - value->len) + return false; + + value->data =3D (const u8 *)a + value_offset; + return true; +} + +static bool ntfs_non_resident_attr_value_is_valid(const struct attr_record= *a) +{ + u32 attr_len; + u32 min_len; + u16 mp_offset; + + attr_len =3D le32_to_cpu(a->length); + min_len =3D offsetof(struct attr_record, data.non_resident.initialized_si= ze) + + sizeof(a->data.non_resident.initialized_size); + if (attr_len < min_len) + return false; + + mp_offset =3D le16_to_cpu(a->data.non_resident.mapping_pairs_offset); + return mp_offset >=3D min_len && mp_offset <=3D attr_len; +} + +static bool ntfs_attr_value_is_valid(struct ntfs_volume *vol, + const struct attr_record *a, + const u64 mft_no) +{ + struct ntfs_resident_attr_value value; + u32 min_len; + + if (a->non_resident) { + if (a->type =3D=3D AT_FILE_NAME) + goto corrupt; + if (!ntfs_non_resident_attr_value_is_valid(a)) + goto corrupt; + return true; + } + + if (!ntfs_resident_attr_value_get(a, &value)) + goto corrupt; + + min_len =3D ntfs_resident_attr_min_value_length(a->type); + if (min_len && value.len < min_len) + goto corrupt; + + switch (a->type) { + case AT_FILE_NAME: + if (!ntfs_file_name_attr_value_is_valid(value.data, value.len)) + goto corrupt; + break; + } + return true; + +corrupt: + ntfs_error(vol->sb, + "Corrupt %#x attribute in MFT record %llu\n", + le32_to_cpu(a->type), mft_no); + return false; +} + /* * ntfs_attr_find - find (next) attribute in mft record * @type: attribute type to find @@ -705,8 +796,11 @@ static int ntfs_attr_find(const __le32 type, const __l= e16 *name, } } =20 - if (type =3D=3D AT_UNUSED) + if (type =3D=3D AT_UNUSED) { + if (!ntfs_attr_value_is_valid(vol, a, ctx->ntfs_ino->mft_no)) + break; return 0; + } if (a->type !=3D type) continue; /* @@ -747,37 +841,8 @@ static int ntfs_attr_find(const __le32 type, const __l= e16 *name, } } =20 - /* Validate attribute's value offset/length */ - if (!a->non_resident) { - u32 min_len; - u32 value_length =3D le32_to_cpu(a->data.resident.value_length); - u16 value_offset =3D le16_to_cpu(a->data.resident.value_offset); - - if (value_length > le32_to_cpu(a->length) || - value_offset > le32_to_cpu(a->length) - value_length) - break; - - min_len =3D ntfs_resident_attr_min_value_length(a->type); - if (min_len && value_length < min_len) { - ntfs_error(vol->sb, - "Too small %#x resident attribute value in MFT record %lld\n", - le32_to_cpu(a->type), (long long)ctx->ntfs_ino->mft_no); - break; - } - } else { - u32 min_len; - u16 mp_offset; - - min_len =3D offsetof(struct attr_record, data.non_resident.initialized_= size) + - sizeof(a->data.non_resident.initialized_size); - if (le32_to_cpu(a->length) < min_len) - break; - - mp_offset =3D le16_to_cpu(a->data.non_resident.mapping_pairs_offset); - if (mp_offset < min_len || - mp_offset > le32_to_cpu(a->length)) - break; - } + if (!ntfs_attr_value_is_valid(vol, a, ctx->ntfs_ino->mft_no)) + break; =20 /* * The names match or @name not present and attribute is @@ -1252,22 +1317,8 @@ static int ntfs_external_attr_find(const __le32 type, =20 ctx->attr =3D a; =20 - if (a->non_resident) { - u32 min_len; - u16 mp_offset; - - min_len =3D offsetof(struct attr_record, - data.non_resident.initialized_size) + - sizeof(a->data.non_resident.initialized_size); - - if (le32_to_cpu(a->length) < min_len) - break; - - mp_offset =3D - le16_to_cpu(a->data.non_resident.mapping_pairs_offset); - if (mp_offset < min_len || mp_offset > attr_len) - break; - } + if (!ntfs_attr_value_is_valid(vol, a, ctx->ntfs_ino->mft_no)) + break; =20 /* * If no @val specified or @val specified and it matches, we @@ -1279,19 +1330,6 @@ static int ntfs_external_attr_find(const __le32 type, u32 value_length =3D le32_to_cpu(a->data.resident.value_length); u16 value_offset =3D le16_to_cpu(a->data.resident.value_offset); =20 - if (attr_len < offsetof(struct attr_record, data.resident.reserved) + - sizeof(a->data.resident.reserved)) - break; - if (value_length > attr_len || value_offset > attr_len - value_length) - break; - - value_length =3D ntfs_resident_attr_min_value_length(a->type); - if (value_length && le32_to_cpu(a->data.resident.value_length) < - value_length) { - pr_err("Too small resident attribute value in MFT record %lld, type %#= x\n", - (long long)ctx->ntfs_ino->mft_no, a->type); - break; - } if (value_length =3D=3D val_len && !memcmp((u8 *)a + value_offset, val, val_len)) { attr_found: --=20 2.43.0 From nobody Mon Jun 8 09:48:26 2026 Received: from mail-pg1-f180.google.com (mail-pg1-f180.google.com [209.85.215.180]) (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 A1E6F2C0299 for ; Sat, 30 May 2026 14:35:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.180 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780151728; cv=none; b=prgej8aZuJV6vys0HPKjEYSDy/Ap61kDPauL1GcW7HYvL2EONB7pcsPG0DQd6kg1wtuvMrrFX9vdxLG7fWbt6ePp7JL5eI+0KATKrPwr+pQQlfngndE7ouvxOUMhqVdU1TYMeDnYS8734cw9mh35Qm94uRytkIU40A4nf11KhH8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780151728; c=relaxed/simple; bh=MSDhO8kmXxGFOzcEOVnsceyiE3UMPChHvO3j6B5hL9w=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=a7dxkGzkzckBnL1QWWAS2BhIrFOlouSDaFXXQ0xiTSfLi/8aRniWiDOwyJG+GWOTQlOzfiqNxWoVLEN6+nQ1v38GH/ctTB6ovdfH/6cYIO6qF92EyxTas2y9yxmgm3Yz1westhrZdYUVdVMoTikIC/6Rm+53B3Upv360iksHmsM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=jUEPKShl; arc=none smtp.client-ip=209.85.215.180 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="jUEPKShl" Received: by mail-pg1-f180.google.com with SMTP id 41be03b00d2f7-c85631bab7cso121596a12.1 for ; Sat, 30 May 2026 07:35:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780151727; x=1780756527; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=hzViUSPWZPFCueI/zqrhP6OZ0oxKngJz6Ipnb5MmOes=; b=jUEPKShlVtxxIOX3XsyUcw9Zb50MqYe8ch5Y2kahN7S7TwSByWFm82NgN5D7c5vDth MeYSiguYyJwCZ3F06QYQZemdcQjx4OyXK6U7Od5p6G6EzJ6f3AForUXw/2bE0QVPfEfW bvqKpMauCThVJpWdPgtkF4NAG6tj8A1StqqRZRe9THauMhid45EYd9r24nhGImXhP4XW 65920tWaO6NPxYXG31Ey4M03h9hu1BBYbrI7dMelsJmTEwL1/PtWwIp+tUdb7OJC6fey Ih9hFnnIWMUI9WvMhZ+YkCDtBH70KnpcwlnFvhSHPX+smkpLoniTnPCNyzMV/TLEN6qE Jy6w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780151727; x=1780756527; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=hzViUSPWZPFCueI/zqrhP6OZ0oxKngJz6Ipnb5MmOes=; b=ft9aNa592eu/3ixfzHMsxGTBm7ZSy8VO8xVaRKg2T2tBK7P1ccYq+cjav3br1htrJc owfa1c5ESR/qDQ1bslqPw5igudsorskZP9Cz58BfiitDatOLe31dKmEv/Wx2YRkVluPa 2YFqK3sRJ3w7y87y/ZzoLNUDet1Pk4WZ9oCvS8eIz5BMQWRYjicDcHQqBDp0Xnar33zT OOtCZPka4CHQ256zhqJLcUb9inTcylWHbc6LHYhvoMi6Va+S0JuVtCqawrzSTV9UMSk2 wNEU/JyzwFLspWl+vPxvKJzUby9f3/npIoxIym0FYoWlmVg/fmxdVtYpjxdnlPEgOt8i U5hA== X-Forwarded-Encrypted: i=1; AFNElJ9cax20seS3DqmIzRl7vN4xjdig5enf/i/BQ0LxPJO8wo38rgqSPeUHFL+7jdwrJu5da74msDvjRKXjk00=@vger.kernel.org X-Gm-Message-State: AOJu0YwYDd9LTdp5B5SalEu4C6R5l1RgwPXYAXz+jWV7V+NRXM5hmhjq Tx2kaonWO7YuZhb45D3JzKbY4nV9Jsoz5um1ln8yvcL/o9G0V546Zuz7A/6LMA== X-Gm-Gg: Acq92OFUw7u/LMtpY1v9lWuckGr/Q4/qr0eSXq3RggGokknPLESbWqGtWwoPCBtT99D //y7tuy9sYHHGqaTVTuoL9pR78Euy/j3ZN/kYzSGMliO2qBuYm91LLbMfKbaIwMvb7iEpJzPoZL hwu5IVLTU3M7faNx1kZaOTmRHjZGh6Zptowt/3JOwgykZ1zqTE83mYK1jlrDhKYAaMrqdklZQJ1 9g35iJxCrKvjnKjZMFmyCzD36gRFZrMlExZkorZBBk5sRkd0dGop6d3XxifnczvDHvAuOweLFPU b2VE5NpP8ECrsatT6OFTUre/KOxl230sC2jKz/wNFHMvD3m5Fkyh1vJLB6Yh7U8+8tN530R9Kqp m4uJ1PM5EEKk7mTAm/eI1s/S07Gx/Tpkj5DwixDqDMRvjifzdpPFgaKUYW0VzOyZpLRWHaU3FDq Y+by5XuAYewbq7SXsHZGTr18Rrc74= X-Received: by 2002:a05:6a00:3c89:b0:841:dc7e:b42e with SMTP id d2e1a72fcca58-842251b90d8mr2102711b3a.0.1780151726961; Sat, 30 May 2026 07:35:26 -0700 (PDT) Received: from ser8.. ([221.156.231.192]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-84214b2acb7sm5832280b3a.13.2026.05.30.07.35.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 30 May 2026 07:35:26 -0700 (PDT) From: DaeMyung Kang To: Namjae Jeon , Hyunchul Lee Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, DaeMyung Kang Subject: [PATCH v4 2/6] ntfs: do not replace volume name after lookup errors Date: Sat, 30 May 2026 23:35:10 +0900 Message-ID: <20260530143514.3083601-3-charsyam@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260530143514.3083601-1-charsyam@gmail.com> References: <20260530143514.3083601-1-charsyam@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" ntfs_write_volume_label() removes an existing $VOLUME_NAME attribute and then adds the replacement. The old code only distinguished lookup success from all other results, so any lookup error was treated like an absent label and the add path still ran. That is unsafe once lookup-time validation rejects corrupt $VOLUME_NAME records with -EIO: the corrupt record would remain in place and a second $VOLUME_NAME record could be appended next to it. Only add the replacement after the old label was removed successfully or after lookup returned -ENOENT. Propagate all other lookup errors, and also stop if removing the old attribute fails. Signed-off-by: DaeMyung Kang --- fs/ntfs/super.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index a2648d1c8fd0..140b8c8a811e 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -452,10 +452,15 @@ int ntfs_write_volume_label(struct ntfs_volume *vol, = char *label) goto out; } =20 - if (!ntfs_attr_lookup(AT_VOLUME_NAME, NULL, 0, 0, 0, NULL, 0, - ctx)) - ntfs_attr_record_rm(ctx); + ret =3D ntfs_attr_lookup(AT_VOLUME_NAME, NULL, 0, 0, 0, NULL, 0, + ctx); + if (!ret) + ret =3D ntfs_attr_record_rm(ctx); + else if (ret =3D=3D -ENOENT) + ret =3D 0; ntfs_attr_put_search_ctx(ctx); + if (ret) + goto out; =20 ret =3D ntfs_resident_attr_record_add(vol_ni, AT_VOLUME_NAME, AT_UNNAMED,= 0, (u8 *)uname, uname_len * sizeof(__le16), 0); --=20 2.43.0 From nobody Mon Jun 8 09:48:26 2026 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 8A37D2D9ECA for ; Sat, 30 May 2026 14:35:30 +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=1780151731; cv=none; b=lL2CeawrIyEwXTYImn9vY11XZYjcu46kK1+7ADJsSQwdjoyp3jbV4WzFVuyi0NLmisBvi87Plrt379+TP6xmPl1zJlAGlyoFW+WyazhbevsEneMp7k5EY/QzB6iwe97EYif7tHuKBDUEq2VvkjnhC8nyJm2guO/zJ4/epoQgzc0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780151731; c=relaxed/simple; bh=9icizL+Sjs2p+zTleA2i7He+9Wrfoo5fQEGr1xgi4KI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=apFXTdYx8QlQRG/eo9e/YHY6oP9ff4GcyX4YYtM3Xjt22ws/whjd2TxtNfSLJ1jWSvLvnAhFbzT5nrLDrh4pdbHvLeQjz7SNIbNx4jN6HLqR6CkQJmaa+kYEoxTRoC7qK/zhe4uOff9Cdvn/zz+eHVNzQsTOSpr+dY8IyEcYJbM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=OGrlrdUg; arc=none smtp.client-ip=209.85.210.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="OGrlrdUg" Received: by mail-pf1-f176.google.com with SMTP id d2e1a72fcca58-842204fcca4so27249b3a.3 for ; Sat, 30 May 2026 07:35:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780151730; x=1780756530; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=yl6ECZG8J6iHdI6eQPCRlThUPWfxjh8VpTkkklcQYXg=; b=OGrlrdUg3OB0d8p2aFaVQb9KkSSIjzBKU0eZV8d9uW25fuVHMmJOa2wUqxi8jMfGVa wCzrm8qxZr30xdY16/BFVCIeCsd/xIqbVE36W5DqMx+0aH0A/SGDgX7E78BhqqmKbabH tUV3ILGw3G0QVEY4yUBKT9O2peUL9F6dCeRwk1iVQkPrN4/YMRL7tSguELVx/UVweh4x iYRXyZNex2NFZUg4g/Vv0d7wPaHlFh9igapvJ7MShKycYR536UxRjtlv0vwMl9QzHcuJ +fIw4knkXBNgKRBeLTH4jy3N/3YXBnMPdxBaAeTnU6Xv2T6qHAZKgPf3+jSQ4kkPCbnW /2wg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780151730; x=1780756530; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=yl6ECZG8J6iHdI6eQPCRlThUPWfxjh8VpTkkklcQYXg=; b=boQ60aN5bnfVOjJhycoCP/PNfRd2CTgophuF5btTJdIhzk5uFD5xA2Y1TUNTTXo/Fl OHFeh9WVwr5lISqesHJUPyrflAzLjQhUDSLGWancCbw/PiXm937fgYUEg2AaZAawRPt8 KYs2DoN2PV072W03NV01pbPeq/51iSuMUGsqZRjteR/uYTW4k7Jh+8rNIoi/7EWhIRZv uT3Lnjjr4syl+dVO3Wfg0xvxilE5mUPuU3Pr1FmlHFvmcvxHwhCFVi+PnUZFCbsWVAau v4exhYegArhQx5DVZvhWZKM3r3ySxFV0zZBPPPiLSmfYNsA2K98oD3MPIgECZWPdnSn5 2rWg== X-Forwarded-Encrypted: i=1; AFNElJ//88GQ2mcdpW/JOWx6wYlEgTwZcp008Lj8hfyGuZobz8kkNTbS89QUra7PF4zc99Lk9vMZFjBbzhb5uCw=@vger.kernel.org X-Gm-Message-State: AOJu0Yza6nXPppQl4DiL93i2jzclqIGj9cIWaj/SGMXvO4pkmdzMaewo NciHMiAhJlLY64zCc3eNeAPuGxKQARdRaNuDxXNmrDsDBcRdIEyhGjT/ X-Gm-Gg: Acq92OFD2L1WiUZ3ih0RaoxuM1D8iWSoEoclHm9rJf3Wd7ANeBEQspwX4RWhCh84NkS zb1/6j1xcpg+0+HQXt88Y6jWkflq6ynnEHcZ3ssTflWAtg2FmztkfoISposeMkJFeuxSGxmrBYr dvrpmQWifZoOBpGX7pBS1mS5ejK0Ffqf2nuZzTQebStcAj6Pth4nF0bJWOihmMaKZ9SgZ4hxsTp Cwd0rdCG//coKD3Tm2OipMw4okKtlhIIwFAr1FahM7WjPx7AifEiL++rTFH4X4Bu0bQihJNyCJ2 i6PxsMxwLdQHOkDZrGo8Bjbk9aRXVwABwJGuWEk1pzNZ2RJOCNiG6XsIzrY3/gwq/XJTM0SZZ9O hfHd+7k+TF5hFlDyzZJfkXNCuApnphT1sDm1EO+mK9XRtFH1aoI1WlzACKNiYFXjRCQUXGXgBx7 ytlgX1q0kQ9H8BvLbYDHHUsa0H1j4= X-Received: by 2002:a05:6a00:124b:b0:82f:6a82:4231 with SMTP id d2e1a72fcca58-8422533341amr1692669b3a.1.1780151729690; Sat, 30 May 2026 07:35:29 -0700 (PDT) Received: from ser8.. ([221.156.231.192]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-84214b2acb7sm5832280b3a.13.2026.05.30.07.35.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 30 May 2026 07:35:29 -0700 (PDT) From: DaeMyung Kang To: Namjae Jeon , Hyunchul Lee Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, DaeMyung Kang Subject: [PATCH v4 3/6] ntfs: reinit search context before volume information lookup Date: Sat, 30 May 2026 23:35:11 +0900 Message-ID: <20260530143514.3083601-4-charsyam@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260530143514.3083601-1-charsyam@gmail.com> References: <20260530143514.3083601-1-charsyam@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" On mount the volume inode is searched for $VOLUME_NAME and then, reusing the same search context, for $VOLUME_INFORMATION. The $VOLUME_NAME lookup is optional and its result is otherwise ignored. Once lookup-time validation can reject a corrupt $VOLUME_NAME with -EIO, the search context is left in an undefined state: ntfs_attr_find() documents that on an actual error @ctx->attr is undefined. Continuing the $VOLUME_INFORMATION search from that context is not contractually valid. Reinitialize the search context before the $VOLUME_INFORMATION lookup so it always starts from a well-defined state regardless of the $VOLUME_NAME lookup outcome. Signed-off-by: DaeMyung Kang --- fs/ntfs/super.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 140b8c8a811e..79b530280d87 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -1537,6 +1537,7 @@ static bool load_system_files(struct ntfs_volume *vol) vol->volume_label =3D NULL; } =20 + ntfs_attr_reinit_search_ctx(ctx); if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, NULL, 0, 0, 0, NULL, 0, ctx) || ctx->attr->non_resident || ctx->attr->flags) { ntfs_attr_put_search_ctx(ctx); --=20 2.43.0 From nobody Mon Jun 8 09:48:26 2026 Received: from mail-pj1-f42.google.com (mail-pj1-f42.google.com [209.85.216.42]) (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 4188824EA90 for ; Sat, 30 May 2026 14:35:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780151734; cv=none; b=Ep+x7RSk1w+jG26iKeAbGBkmcFKoya7Tbe36HhUh/8CtjkDVzNiwvMzdf9z+72OQCzHQ2hiyjKHLgNkXAUXjxpGiYYKfMGijRDCoQEpJ12OPIYv077L3+vLLQ0geFyhCuwLb1pByn67gAheCLvpe5WCLjKR5w5gw5EczchFId/0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780151734; c=relaxed/simple; bh=ijOuRHPAqJHZAughCM9VYDQ6TyLb0FcaeFQA6fy4rEs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NCfI25TgGgfCvQXpZfkUQeu9TbgsfEhSVykghjCpwWrklvKYIL0hqWkGuTJ421jn8VQTDBh4m4upolJILX4f5Qc86HRlP0WIeIyABmHuNafn1Fm0EXswmkHHGIMkIPtXa30XFBrtEe4QjlVioXWUXE/NYd7OiiWZcgo3/7rq1ho= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=BgFF979y; arc=none smtp.client-ip=209.85.216.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="BgFF979y" Received: by mail-pj1-f42.google.com with SMTP id 98e67ed59e1d1-36bb43a58c7so236183a91.1 for ; Sat, 30 May 2026 07:35:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780151733; x=1780756533; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=zDfvTLy1+sJMtcgOCTiZxQEYHCAfpO8m5RiCueB0hpU=; b=BgFF979yQqBJ2IfV0n0QAe7fhjE9Hrw5cv2O1+1m+WbH9dBl0iOPjfIX3bfb3EGtjI Jdmdl9txzNo+H+vDgIQW0RRgXX0rrCeTZ2IQ/7/EVyKnF6XT1rGxtfBBg4S89hfpcBq6 RLjH8oy/Lx7mciOvIzMYCpqUjb+T0lk4IAn8FJ1K+n+KOIJ6oOONbv/WdKCpAS78gL08 sIJPFA/gtjFL81ToJlGL6kXp1Hy7A5Qu6E8OSEuetgZaJynhU0YBaX+1Sg43u7spbdGF fR0l3FQQakdU1853IopmL2ErQ3g5UwPLyCAvRm53nftwZ1jkhCh1vIcopRS4G6UgvuP7 dq+w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780151733; x=1780756533; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=zDfvTLy1+sJMtcgOCTiZxQEYHCAfpO8m5RiCueB0hpU=; b=mgOpEtHajSoFqWESv2ualIOaBU5C04NQYtEscud5JyWU9+6fTfnLp9x6OkqwE6s9vH JGetzP/gDFUHr92+CaDpSKHcWMbE9p6kH7w0Zci7T+3m279meoFYH2KnIiz9x6DRuF0L owvqEVZjqoBekEzQpH48zghWOLPFd7VR53iXUdJjvE9aRlKGDNQsJe5+FmhhRXGqoowD QccdNoZy89ncdDGvIt/glb0BRlqK0ZmckCvVnrXdxMNzuHFC8RxFz/inJJ7KDVemWxML AfanerTI9+9fCBy/87gKQ3wJ6Mt200IYyBWXYUM8a/QqPcpJXxqNyOgZPCghFbIDl4OF FFaw== X-Forwarded-Encrypted: i=1; AFNElJ/0wxAsESvLBol6W8DGa7lVpgtd9kRxEWAgaaopSJRS+M7jEbB7i61SzR7aiyrBsGrINJFOr+hzLHZ55jg=@vger.kernel.org X-Gm-Message-State: AOJu0YwddC9GYATfeoTiVx6JsRe3ArirCHVtgBdyzZwp8bsPxAUOM72q msPxZKOr/MXU9t6doyI/mHHCs+JpksrE+2xATcAOwaI8ThbGjoTCo8vX X-Gm-Gg: Acq92OGp7dlYiyLcYieR7X/Y4yqSh4jsazRX9QVMSSnlmwIum4ddeHowpo6AfWHo/mZ PLMHkhPrK+E/GmKKEDh1kp3TJq8ZLL7hWkclv06pCJhCUo/EwOeI53rPOF0OyiEHn8p8GJiaKgm jOkkEli34IQ57RSRvTPucHgIxIXmy2W11tELZFGq/NpeK98GogKGv17TEwBsoVzHy2JVDiLdbpz iBNrLIA4PQWwqF9AMzgoexCHM0at2GsB6Ydab1h9xN3KA93l1oOITB385jRKF+Mi1FJu6PPWT4W S1Lr3s7tRITntA2y2o8oRaCFUrXCQUAowL9Mj4vm7Lpi/IekEbHpHaXI8q3Sn2yp846M1kYiY0C 6AnyAcxipBbRt1oSOiTkYcqUuqS07d1NB6+NBBmvdo1e5pfGl/8oUd/aw5cV4NduaIWFAobJI7f l343PTkRZ+ZC/bdA6nFL6EsjCT950= X-Received: by 2002:a05:6a21:9189:b0:39f:a451:4a6a with SMTP id adf61e73a8af0-3b427e9c7c1mr2162463637.5.1780151732474; Sat, 30 May 2026 07:35:32 -0700 (PDT) Received: from ser8.. ([221.156.231.192]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-84214b2acb7sm5832280b3a.13.2026.05.30.07.35.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 30 May 2026 07:35:32 -0700 (PDT) From: DaeMyung Kang To: Namjae Jeon , Hyunchul Lee Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, DaeMyung Kang Subject: [PATCH v4 4/6] ntfs: validate resident volume name values on lookup Date: Sat, 30 May 2026 23:35:12 +0900 Message-ID: <20260530143514.3083601-5-charsyam@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260530143514.3083601-1-charsyam@gmail.com> References: <20260530143514.3083601-1-charsyam@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The shared lookup-time attribute validator now has a safe caller path for $VOLUME_NAME corruption: ntfs_write_volume_label() no longer treats lookup errors as an absent label, and the mount path reinitializes its search context before continuing to $VOLUME_INFORMATION. Add $VOLUME_NAME-specific resident value validation. A volume name is stored as a UTF-16LE string, so reject odd byte lengths, and reject values longer than the NTFS volume label limit. Empty labels remain valid. Also reject non-resident $VOLUME_NAME records. $VOLUME_NAME is required to be resident, like $FILE_NAME; a crafted non-resident record would otherwise pass lookup and ntfs_write_volume_label() would remove it as if it were a normal resident attribute. Signed-off-by: DaeMyung Kang --- fs/ntfs/attrib.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 98e0b8ea2edd..7e293b85ad19 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -607,6 +607,14 @@ static bool ntfs_file_name_attr_value_is_valid(const u= 8 *value, const u32 value_ value_length - offsetof(struct file_name_attr, file_name); } =20 +static bool ntfs_volume_name_attr_value_is_valid(const u32 value_length) +{ + if (value_length & 1) + return false; + + return value_length <=3D NTFS_MAX_LABEL_LEN * sizeof(__le16); +} + struct ntfs_resident_attr_value { const u8 *data; u32 len; @@ -657,7 +665,7 @@ static bool ntfs_attr_value_is_valid(struct ntfs_volume= *vol, u32 min_len; =20 if (a->non_resident) { - if (a->type =3D=3D AT_FILE_NAME) + if (a->type =3D=3D AT_FILE_NAME || a->type =3D=3D AT_VOLUME_NAME) goto corrupt; if (!ntfs_non_resident_attr_value_is_valid(a)) goto corrupt; @@ -676,6 +684,10 @@ static bool ntfs_attr_value_is_valid(struct ntfs_volum= e *vol, if (!ntfs_file_name_attr_value_is_valid(value.data, value.len)) goto corrupt; break; + case AT_VOLUME_NAME: + if (!ntfs_volume_name_attr_value_is_valid(value.len)) + goto corrupt; + break; } return true; =20 --=20 2.43.0 From nobody Mon Jun 8 09:48:26 2026 Received: from mail-pj1-f48.google.com (mail-pj1-f48.google.com [209.85.216.48]) (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 AB10C30DEAC for ; Sat, 30 May 2026 14:35:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780151737; cv=none; b=TXRDPr2fBMzQLjORwlzTI2Zq7NWQLCWouuf4Sqm2DvASntONl+O7XOl7PKu7NXJ04mlFvtWAZ2vhBW6fxQEZE0LttNhwtx74+SqLhx1/iebd90FHHRL5Uj6jDesXcvZfGNYin+c6GAIZWRNlMJJVxOneDgFvltWRz2Y5qQAoogI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780151737; c=relaxed/simple; bh=sVgzmvJrwwfRTA5jIT18ZQAVVs4t/EJoipsudjW5zlc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=OoFMRgGYz8O8LFy21jeXqb0aea12mfG35Fervlmyf3fYq86zFQqyHKCifyVimRXjTFQ56tLtGzCq6DIiw/IgA/efbEMpWZjEXjV5gDlk4AMC9me2Wc++qYIQzHqh/kYpFLrrsltfTGlhHK45NVmxm3mmJpWAuGGqBj1PW1yGnqs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=pPNePyYG; arc=none smtp.client-ip=209.85.216.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="pPNePyYG" Received: by mail-pj1-f48.google.com with SMTP id 98e67ed59e1d1-36ba9f46338so270345a91.0 for ; Sat, 30 May 2026 07:35:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780151735; x=1780756535; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=P0z7rLBKen5DM92a4OaucYeckexSO2wBy9x5XZ4xp3g=; b=pPNePyYG6N/9VS/yimSWKEuw6neIwiXrtXdYdB8DOSQNWqbzl1ayH2qeBE/jVnlpot pH78ObKsTiT1SDZ1dM7yJrWz/nV+YLNXw1c2qYFnUecp3H+pgEEnOPMTI5AUyNtjsNyg 9JTbBPrcBZIH0jTMSYN7Gmy+Y9DieB+lwpytQ1SKf/zXqWEk2r756bMArSxIgbsdpKos voQz03DSD8RQII33t+pOSdOKaR9Of1MLDwEqplFapccn0sisyjUyTqGrz3O2GDtSsEBQ YgKOpJ3DOF7+T6wi6dtpfjGVopriKncJcfOBaNOpCzEcQzvVpQtu5Rm/T9PnNWcOh8yx p1bg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780151735; x=1780756535; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=P0z7rLBKen5DM92a4OaucYeckexSO2wBy9x5XZ4xp3g=; b=BJkVxlnrZjUA2m/vsVuoR/V9jV77yie27EZqc2KmS7GndI9Fp/BdUutKfwoWUakS20 QK5IUTkyfwglcobsn2LHsdTKXxiSISf7K8sDVaKrmDCErUmDQevbNmE+/SB/iCXaYrCY TSFejOA1Coa0WM8ZvTkTHfnbnj579oCfGJf6ZjhvMXwC9w8QYDI1141d5id7Ik91nTdC TkNT+SX4E3sCPSBXCApZ/3NtBE9VR7scnGfHTAZU8E015JwYUR+wj490l5FvJgtqwGZe lqBjQ2zlEkHnAOHtaFZmBEU8vSvxs1Q8HA3FtNdmd1ZpMJs1o9SxVPSzIKpJky3b+kCY Uajg== X-Forwarded-Encrypted: i=1; AFNElJ9QQZyCdhY318Caf9Rd7NRdomexlrdBCJ4KMSwGlZRN4JqGtqlwwAEUFJILotiOw8EwIg+Q45qhgEEJFkw=@vger.kernel.org X-Gm-Message-State: AOJu0Yy/z/aBYQdEmFCZiDcEFv9XRFRgTtmnCCOnOt+9MWIQK03tuCZq 5dkXieTyvZUuBVFtW5Lw3lQAnsjVQO+7tkzpn/TTStp4plCVd1jkx28DNh9O7g== X-Gm-Gg: Acq92OGgjETfIgs5rCN2VcAiuOr68ICIQNRxanE1S2fR1FRwsWgjvQsVhGO8oGujcEJ wElVi2g43fLHPfjjC+HwrFx5qOMJJg1hZiGvaYXb6+jsCFlZAYhdlYfFrc+A5HRKMlZ94m2m31a M3k+5HyIVFAWEd/zgT++0PvVNFDK1UcwkUAnvd7AzXNwrPWMpQqOmlAgdK3WXNEdOUhJy0c1YPS DHjxd6KjvTf0GU8+LikLWJGYSiBJ4Cm7//CFVkC32ui7LWAgQCt6q9a1tZcXQE69WfAP1a9V960 cRyoqWV3N54w094g71qpKD0CZAVnkyxwdo0rBj8LyrzjB6c7CQ7oDAYJkrR5u8pMSXBYTBNxMff rvSlPVGLciWxALsL63ZR+M7D9PYKrEMBR0ctTG7gfWfrsq8V+m8eOwPNt+mg2KxF27OeMWS8Svv qXiRv5fR9IAmzCIJdPIKPDw0ewMvc= X-Received: by 2002:a05:6a00:124b:b0:835:41f3:f434 with SMTP id d2e1a72fcca58-84225333915mr1897126b3a.1.1780151734907; Sat, 30 May 2026 07:35:34 -0700 (PDT) Received: from ser8.. ([221.156.231.192]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-84214b2acb7sm5832280b3a.13.2026.05.30.07.35.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 30 May 2026 07:35:34 -0700 (PDT) From: DaeMyung Kang To: Namjae Jeon , Hyunchul Lee Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, DaeMyung Kang Subject: [PATCH v4 5/6] ntfs: update index root allocated size before shrink Date: Sat, 30 May 2026 23:35:13 +0900 Message-ID: <20260530143514.3083601-6-charsyam@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260530143514.3083601-1-charsyam@gmail.com> References: <20260530143514.3083601-1-charsyam@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" ntfs_ir_truncate() currently shrinks the resident $INDEX_ROOT value first and only updates index.allocated_size after re-looking up the attribute. During that relookup, the resident value_length can already be smaller while index.allocated_size still contains the old larger size. That leaves a transiently inconsistent $INDEX_ROOT layout and prevents lookup-time $INDEX_ROOT validation from being enabled: validation can correctly reject allocated_size extending past the newly shrunk resident value. When shrinking, lower index.allocated_size before shrinking value_length. If the truncate fails, restore the old allocated_size. Keep the existing grow ordering because the old allocated_size remains within the enlarged resident value until it is updated after the relookup. The shrink path is safe because the new value_length still covers struct index_root, so the index.allocated_size field remains present while it is updated first. Signed-off-by: DaeMyung Kang --- fs/ntfs/index.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/fs/ntfs/index.c b/fs/ntfs/index.c index 146e011c1a41..068c68a0f9cf 100644 --- a/fs/ntfs/index.c +++ b/fs/ntfs/index.c @@ -1280,9 +1280,16 @@ static int ntfs_ir_reparent(struct ntfs_index_contex= t *icx) static int ntfs_ir_truncate(struct ntfs_index_context *icx, int data_size) { int ret; + u32 old_allocated_size; + bool shrink; =20 ntfs_debug("Entering\n"); =20 + old_allocated_size =3D le32_to_cpu(icx->ir->index.allocated_size); + shrink =3D data_size < old_allocated_size; + if (shrink) + icx->ir->index.allocated_size =3D cpu_to_le32(data_size); + /* * INDEX_ROOT must be resident and its entries can be moved to * struct index_block, so ENOSPC isn't a real error. @@ -1294,9 +1301,14 @@ static int ntfs_ir_truncate(struct ntfs_index_contex= t *icx, int data_size) if (!icx->ir) return -ENOENT; =20 - icx->ir->index.allocated_size =3D cpu_to_le32(data_size); - } else if (ret !=3D -ENOSPC) - ntfs_error(icx->idx_ni->vol->sb, "Failed to truncate INDEX_ROOT"); + if (!shrink) + icx->ir->index.allocated_size =3D cpu_to_le32(data_size); + } else { + if (shrink) + icx->ir->index.allocated_size =3D cpu_to_le32(old_allocated_size); + if (ret !=3D -ENOSPC) + ntfs_error(icx->idx_ni->vol->sb, "Failed to truncate INDEX_ROOT"); + } =20 return ret; } --=20 2.43.0 From nobody Mon Jun 8 09:48:26 2026 Received: from mail-pj1-f50.google.com (mail-pj1-f50.google.com [209.85.216.50]) (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 23AFA3033C6 for ; Sat, 30 May 2026 14:35:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780151744; cv=none; b=Xt27yD8eAOE2k1jP9JODs86Px9+A3b8kCnKxsK8nfiObIw6Af/I/hJhIQWdKByH4MBPWnkiS385/f1xX5haudGB9nqV5KRXcDyAqE81aA5FFvdrThD6HcQ5FgpfkzSgcqJdgdjhjlmhhP2RRhLitqVPolibn7JazZY5XIL88bZ8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780151744; c=relaxed/simple; bh=9SylS9yljNxwfHeZRNXh+k8lgGEzLcUkXrmk6UEWZ6o=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jPVwQGK+CGhyDMdIRSo+EzAEYVJbg+ImKJnY4AAC4qToCdfpfizplvCOURdINJTMy7UA8mzgB+20wDr76LziFPGauhpW8VNHyPbAyGnEhZXTqyN2m3r14lzjx8Y2r9s64lf4o/n7LBH8UCgxhaupIfWQnSPkxpslkP1Uhq6cPcM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=aTWwJA8M; arc=none smtp.client-ip=209.85.216.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="aTWwJA8M" Received: by mail-pj1-f50.google.com with SMTP id 98e67ed59e1d1-36b7e4e3be0so381600a91.0 for ; Sat, 30 May 2026 07:35:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780151737; x=1780756537; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=CQR16zufLVNNshPcvX4mOgsdyLqa+4bs26weMfnyKCA=; b=aTWwJA8MmYUxprXXx/9R9n066pQ3C8R8a/edNCkX3SnY+0HzIKSlIw+PMGQ5Q5p9tO X8nrkgMkfZdUdiVUupXrJLdFO7SCHGAjiXqBxU6MAMb306pf58NRQ+LoGBZYvJuM4F1D 1NNmIL64gaS3/mOfNixMcuZQFRnFV2A1YrZ5xC04eQiZ8J50FPF6n+HnoUTKG+8iUlri rDHGvgP0J9TXdzCyIWvG9DxiabRgEd69g6Skt+nXE6v9F1Id0trlcDHpLlRJmwIKsV7u +mjhSV3tgaNCAHxwbOVYj1Z9SyRVSmS5bOqd3goOxzCj2NTqpARfUyLp+58zsrsszLQj xqww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780151737; x=1780756537; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=CQR16zufLVNNshPcvX4mOgsdyLqa+4bs26weMfnyKCA=; b=K6Yr/5/569/nsggyjFDLOJ5WdzJbAZSCxNR+L2h58Dpico8eih/059NSBB4TTkBrqa hc7r/rbblZZkhT5pMbN8vxC+MWgSmuov1lGiEQfN5PDNHwzcuj41sONMG7yk3alpp7Oe nqzjaqHzsxXQ23kZcnpLbfzILaDVb8MkXF+PrSviVhsK0jfelKd9KqlZrFtyo5aNad7m rC2goxIXfnb4l1WxpYnXh9OkZ00v0eVyzfVs79U/UaVAAnEgo2hAnJKGUtvfxDqxh0RR wyRcBsNOxwOVMKKEnoIdGbBLhJeWlyK9n9CxCTVADfzJZUqott1Sg+DXNJCOhCBM2xTa HLQA== X-Forwarded-Encrypted: i=1; AFNElJ/5hB3kuexwJZMvNC40LAV/QlzSv/kRH9wR1tW3pFvCobgQTFXkpMXNJ1L/2wWwK0u79bk5K9/d5T21xOQ=@vger.kernel.org X-Gm-Message-State: AOJu0YxhvfYynRkZWWcYyWknUKW7a8dImSS9N6hEffsjcbGfLZpSrxkg UPTL/VpNElFP0CGmJW/S2ogZbidJwIYwMnnzOuPDSxLTUcVKBz6z9XQC X-Gm-Gg: Acq92OELU/W636Xc4M8hF7Kc0PKur8+VNBBCL8OQCkymbO8gYGMI7VvigkFeWk/pz0v wl1GZpGWOWjSfVr/NOkBMdAO6Wa/Sj4QgzwNfGrPJn4JmymG0vPU8oTvqdno718SxUp/64pDn6D E8vVcIyLN1DYEdwnDG5O41XUYWGeh1iNoB1ykx8577WMyrLHjPwrx/i1JJG6EvP/e20k/6ItNDM g1j8AR//iWXCBL2rcsK/tVc2wxE0Wb0rx3xfp43B0B9kSRHdFrOJXz/pIygh/y8VnKuSwF0UUDw AAMrxi+C+sJL33QwPiJlEu4h2SYxIwxwXw9QtEMxqsfmcNve++KCZRR4oHYvkFr3B0e+996TMmM YyJunX2NAqJ4uUURBsU9BsXNSW1uERlUunyKDG1VTa5Y4mnkzUeGPI6TUCV8cPc5JY/j9U0kvkm sAue2sB1uS/g/DQKYAsweViBRL10NO836Tbq/QTg== X-Received: by 2002:aa7:9d8d:0:b0:842:2d2c:2b68 with SMTP id d2e1a72fcca58-8422d2c3786mr856020b3a.6.1780151737236; Sat, 30 May 2026 07:35:37 -0700 (PDT) Received: from ser8.. ([221.156.231.192]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-84214b2acb7sm5832280b3a.13.2026.05.30.07.35.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 30 May 2026 07:35:36 -0700 (PDT) From: DaeMyung Kang To: Namjae Jeon , Hyunchul Lee Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, DaeMyung Kang Subject: [PATCH v4 6/6] ntfs: validate resident index root values on lookup Date: Sat, 30 May 2026 23:35:14 +0900 Message-ID: <20260530143514.3083601-7-charsyam@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260530143514.3083601-1-charsyam@gmail.com> References: <20260530143514.3083601-1-charsyam@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Resident $INDEX_ROOT values carry index header fields that callers consume after lookup. Some callers already validate parts of the layout before walking entries, but those checks are scattered and do not cover all root header invariants, such as entries_offset alignment and lower bound, index_length, and allocated_size consistency. Now that ntfs_ir_truncate() updates index.allocated_size before shrinking the resident value, lookup-time validation can cover these header invariants without tripping over the driver shrink path. Add $INDEX_ROOT to the minimum resident value size table and validate the resident index header fields before returning the attribute from lookup. Require 8-byte aligned index header fields, a sane entries_offset, an index_length within allocated_size, allocated_size within the resident value, and enough entry space for at least an index entry header. Signed-off-by: DaeMyung Kang --- fs/ntfs/attrib.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 7e293b85ad19..437bf400a13a 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -588,6 +588,8 @@ static u32 ntfs_resident_attr_min_value_length(const __= le32 type) sizeof(__le16) * 1; case AT_VOLUME_INFORMATION: return sizeof(struct volume_information); + case AT_INDEX_ROOT: + return sizeof(struct index_root); case AT_EA_INFORMATION: return sizeof(struct ea_information); default: @@ -615,6 +617,31 @@ static bool ntfs_volume_name_attr_value_is_valid(const= u32 value_length) return value_length <=3D NTFS_MAX_LABEL_LEN * sizeof(__le16); } =20 +static bool ntfs_index_root_attr_value_is_valid(const u8 *value, const u32= value_length) +{ + const struct index_root *ir; + u32 index_size; + u32 entries_offset; + u32 index_length; + u32 allocated_size; + + ir =3D (const struct index_root *)value; + index_size =3D value_length - offsetof(struct index_root, index); + entries_offset =3D le32_to_cpu(ir->index.entries_offset); + index_length =3D le32_to_cpu(ir->index.index_length); + allocated_size =3D le32_to_cpu(ir->index.allocated_size); + + if ((entries_offset | index_length | allocated_size) & 7 || + entries_offset < sizeof(struct index_header) || + entries_offset > index_length || + index_length > allocated_size || + allocated_size > index_size || + index_length - entries_offset < sizeof(struct index_entry_header)) + return false; + + return true; +} + struct ntfs_resident_attr_value { const u8 *data; u32 len; @@ -688,6 +715,10 @@ static bool ntfs_attr_value_is_valid(struct ntfs_volum= e *vol, if (!ntfs_volume_name_attr_value_is_valid(value.len)) goto corrupt; break; + case AT_INDEX_ROOT: + if (!ntfs_index_root_attr_value_is_valid(value.data, value.len)) + goto corrupt; + break; } return true; =20 --=20 2.43.0