From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pj1-f71.google.com (mail-pj1-f71.google.com [209.85.216.71]) (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 268AC48F002 for ; Tue, 8 Sep 2026 22:27:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.71 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788906460; cv=none; b=RfE81uJbMhdSnn48FsdaPSg86ZiOpGJC7FJs/bP/C+FDn0Hnv1UAlyPB3SI1zFhmElWVYxmCAUTC5ZSZV566MNTKmt0WWfxCy7NowbKhIpd5+6qkRMoy6pfhAO98jtxSmWG3hURnMTgmIubkWBQqu1tO5t1dQTCC0ff9Iof5F/s= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788906460; c=relaxed/simple; bh=8r91DRLCl/neE76PnDap4Tdsu/lX3HlhEhY6Vwc0CPI=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=nnjA5tnw0DFJZRlQpRqS3hp8g12rcpXiCCX1KchyCZQ+/npYY72io7Zs2GIbM+i0OyMb5v3jwertsR3+TH3KwrkumVGnXh9E70NrmKRReduG6EeKKsJI/di3s/WO8TR/59BPomMQNWDrXxwDiSmDHddrNnRTG4qmFgaanMU/T5Q= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--morbo.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=JNR4HoeI; arc=none smtp.client-ip=209.85.216.71 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--morbo.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="JNR4HoeI" Received: by mail-pj1-f71.google.com with SMTP id 98e67ed59e1d1-396b9ef3070so7777717a91.3 for ; Tue, 08 Sep 2026 15:27:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1788906458; x=1789511258; darn=vger.kernel.org; h=content-transfer-encoding:content-type:cc:to:from:subject :message-id:references:mime-version:in-reply-to:date:from:to:cc :subject:date:message-id:reply-to:content-type; bh=c9A4iOcSwhHC2tZf3bYzb73lIZurNnt/3XzYiilrGz0=; b=JNR4HoeIHEx51/5Ho15WyHZUeFp6yBxjRhKD/XJ1pf8rCocc/1x92knEiCxF9T3VGv GejNuwqCX87UeI8lO3QHo6aVwibspOV86Bt561FitWkG4YAYgqmXKjw8BqiBmED/dDBI AcqeQiM7+JTF9egfpCMdfOaoe8Y2LC8RWe4OKSkOD52VahOW/QH1ah0fE65dDuHPOko3 ZBQ4Zx2/BvZAmzsc+MbRSnFWq4UBJRiuajIXKAJQmzQ7WfTvvBJVjCZRAYXBof7CgtdM s+wRauoV/Vx9Vkcs62u9BkOP7ySoQLZ584yxH6lMAocQ6E4ov9F6bpXOs/aEw3POkvJY t42g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788906458; x=1789511258; h=content-transfer-encoding:content-type:cc:to:from:subject :message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=c9A4iOcSwhHC2tZf3bYzb73lIZurNnt/3XzYiilrGz0=; b=MWO/XezaVjUKFlpdexKgCjvPsppEjcgjQKB/l7vlZwTlg3bwMT6RUNu71dobMKT3iv xk4GiVOdUa5WoWMQJL+EImV1LCsrpoQ/50aAaH3QfbiovxyMhwMQx0rLpGkuNUuGYqF+ GtacHco2qWdtm0gHcQv7UBkhNY8EnSgQ9NqVJn3CclXrfEwkAyTQvoF6vxcWBNFD8Zya cluVeFVp7acmwj+DNsvozNTDdVYiiR4Qix1uT0Cm7kxhXJeUS8KXv9zrYG6DL0MbyRQv KkAjBH3+H/ZUlCqt08nOVtu+p6Jtf9Jc2rWJFjHvKOamSJwff5BzrSAKuq9+Jrk1BqJ2 NxRw== X-Forwarded-Encrypted: i=1; AKwUvBzCJuiWlsK1zQiwoNQJSxR6kyusuxlkycgEDgeNS5NjMxVnSwY0W0usBRJW4FLfP43lM6hlEqlIselGmx8=@vger.kernel.org X-Gm-Message-State: AFuF++kagRlkUI6F4SwyIQb0zeDtNJRgg0mz5Gm8AJTUU4u4ZH1iFeyc VzXvKj/c7ns3XdWgzptkk+Qdnj9pS8r29zSp5OLfT2YP+DGIoN2mlobEAXRm3PskcTPdayqX9Nd t X-Received: from pjbez18.prod.google.com ([2002:a17:90a:e152:b0:39b:9a3e:dd74]) (user=morbo job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:4fcb:b0:381:a766:efcb with SMTP id 98e67ed59e1d1-39b26100e5dmr44973727a91.4.1788906458271; Tue, 08 Sep 2026 15:27:38 -0700 (PDT) Date: Tue, 8 Sep 2026 22:27:29 +0000 In-Reply-To: <20260823125155.1136740-3-morbo@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260823125155.1136740-3-morbo@google.com> X-Mailer: git-send-email 2.55.0.979.g7e5102b832-goog Message-ID: <20260908222734.3048684-1-morbo@google.com> Subject: [PATCH v5 1/2] userns: Add __counted_by_ptr attribute to struct uid_gid_map From: Bill Wendling To: Christian Brauner Cc: Bill Wendling , "Gustavo A. R. Silva" , Bradley Morgan , "=?UTF-8?q?Thomas=20Wei=C3=9Fschuh?=" , Kees Cook , Aleksa Sarai , Jan Kara , Nathan Chancellor , Miguel Ojeda , Thomas Gleixner , Nicolas Schier , Gary Guo , Alice Ryhl , Douglas Anderson , Anand Moon , Oleg Nesterov , codemender-patching+linux@google.com, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable The compiler attribute __counted_by_ptr associates a pointer field of a struct with a sibling field within the same struct that specifies the element count of the allocated memory. This enables KASAN and fortified bounds-checking to detect out-of-bounds accesses to the pointer field at runtime. We can add the __counted_by_ptr attribute to the 'forward' and 'reverse' pointer fields of 'struct uid_gid_map', which are counted by 'nr_extents'. Since 'nr_extents' is defined in a sibling anonymous struct inside an anonymous union, the nearest common non-anonymous struct level is 'struct uid_gid_map' itself, which is supported by the compiler. However, doing so has runtime implications. In the original implementation of insert_extent(), elements are written to map->forward[map->nr_extents] before map->nr_extents is incremented: if (map->nr_extents < UID_GID_MAP_MAX_BASE_EXTENTS) dest =3D &map->extent[map->nr_extents]; else dest =3D &map->forward[map->nr_extents]; *dest =3D *extent; map->nr_extents++; At the time of writing to 'map->forward[map->nr_extents]', map->nr_extents is still 5, but we are accessing index 5 (which is the 6th element). Under __counted_by_ptr(nr_extents), the compiler and KASAN expect the accessed index to be strictly less than map->nr_extents. Therefore, accessing index 5 when the count is 5 triggers an out-of-bounds panic/trap at runtime. To resolve this, insert_extent() is refactored to increment map->nr_extents first, and then use map->nr_extents - 1 as the index: map->nr_extents++; if (map->nr_extents <=3D UID_GID_MAP_MAX_BASE_EXTENTS) dest =3D &map->extent[map->nr_extents - 1]; else dest =3D &map->forward[map->nr_extents - 1]; *dest =3D *extent; Assisted-by: Gemini:3.1-pro-preview Signed-off-by: Bill Wendling Reviewed-by: Gustavo A. R. Silva Reviewed-by: Bradley Morgan --- v4 - Correct the "Assisted-by" tag. --- Cc: Bradley Morgan Cc: Thomas Wei=C3=9Fschuh Cc: Kees Cook Cc: "Gustavo A. R. Silva" Cc: Christian Brauner Cc: Aleksa Sarai Cc: Jan Kara Cc: Nathan Chancellor Cc: Miguel Ojeda Cc: Thomas Gleixner Cc: Nicolas Schier Cc: Gary Guo Cc: "Thomas Wei=C3=9Fschuh" Cc: Alice Ryhl Cc: Douglas Anderson Cc: Anand Moon Cc: Oleg Nesterov Cc: codemender-patching+linux@google.com Cc: linux-kernel@vger.kernel.org Cc: linux-hardening@vger.kernel.org --- include/linux/user_namespace.h | 4 ++-- kernel/user_namespace.c | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.= h index e38d9e60569f..2962256eddf7 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -29,8 +29,8 @@ struct uid_gid_map { /* 64 bytes -- 1 cache line */ u32 nr_extents; }; struct { - struct uid_gid_extent *forward; - struct uid_gid_extent *reverse; + struct uid_gid_extent *forward __counted_by_ptr(nr_extents); + struct uid_gid_extent *reverse __counted_by_ptr(nr_extents); }; }; }; diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 0bed462e9b2a..786dbf0506ca 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -809,13 +809,17 @@ static int insert_extent(struct uid_gid_map *map, str= uct uid_gid_extent *extent) map->reverse =3D NULL; } =20 - if (map->nr_extents < UID_GID_MAP_MAX_BASE_EXTENTS) - dest =3D &map->extent[map->nr_extents]; + /* + * nr_extents must be updated before the extent and forward arrays are + * accessed, otherwise KSAN will assert an out-of-bounds error. + */ + map->nr_extents++; + if (map->nr_extents <=3D UID_GID_MAP_MAX_BASE_EXTENTS) + dest =3D &map->extent[map->nr_extents - 1]; else - dest =3D &map->forward[map->nr_extents]; + dest =3D &map->forward[map->nr_extents - 1]; =20 *dest =3D *extent; - map->nr_extents++; return 0; } =20 --=20 2.55.0.979.g7e5102b832-goog