From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 04F11292936 for ; Mon, 16 Mar 2026 18:35:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773686116; cv=none; b=WAZcQMS6YQsxbGpL/JeviXYYXjL+fOnLvBiJNX98PnBcnA1yjoCSjRK9Ao2elClOHPVzumqpEYdZhPpGKqBuNJ0FkZzZuSTrMnIw0GIryVNo3spRA1+aEbZ852sTUYYfLDWzj8i7bfBRIJKcEGpocIR5ja9BscRX3J/txr2eKkM= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773686116; c=relaxed/simple; bh=/D8c/BG9IlNJ+slHzmXUyrJ+OMzmj8E7EqtwgLWNxzk=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=aJ94Era/A9VEXzLo5RHR5MCSIW6Wo4EhIutL9ywhX0NYS0Im0XyZqz1AsvZFzvTjJVsdqEhSJwx3DirzzASq9+tTtkPiOi09+sbcWXsf3tx8HUwvIgEXkSONRoptHO48jBguxgeDCqcHdRZ1JpOaETjk92CkpwTVCEUk+/8otQs= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=mPi+m5F7; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="mPi+m5F7" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8002CC19421; Mon, 16 Mar 2026 18:35:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1773686115; bh=/D8c/BG9IlNJ+slHzmXUyrJ+OMzmj8E7EqtwgLWNxzk=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=mPi+m5F7uSgMn9EL/akU9FQgrbbBzCT7jRonhLSnWlahpj4azKMWgoamO3yide9Fa t4Zgmy+iv8JQMOYyvAb6VedqHEWrxu/JFTBlIcG6pKtTglNGfdDoAGLZtFAoEztuiy cahfhm23P+u01+65idM3rQTlaMEG2guaURpgo0hJsUeJSfYDxeWbpXEGpk5k547pDX rIpO6s8h6Qp4k68Yj77AU30uwrMLJ757LsuFOpg6wt4qzN9fg9Pbd8cbWiVZuZ20kI cfu57Qd+rCa3lxJXkMmkQSIhc83H0pNP0iZFf27TPif9dIwK3ouufN/7Ap/YaVLeDj swPt3peLJRq6Q== Date: Mon, 16 Mar 2026 19:35:12 +0100 From: Alejandro Colomar To: LKML , Kees Cook Cc: corbet@lwn.net, serge@hallyn.com, Martin Uecker Subject: Re: kalloc_objs() may not be as safe as it seems Message-ID: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="mpvesaek3qhuotjx" Content-Disposition: inline In-Reply-To: --mpvesaek3qhuotjx Content-Type: text/plain; protected-headers=v1; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable From: Alejandro Colomar To: LKML , Kees Cook Cc: corbet@lwn.net, serge@hallyn.com, Martin Uecker Subject: Re: kalloc_objs() may not be as safe as it seems Message-ID: References: MIME-Version: 1.0 In-Reply-To: On 2026-03-16T19:33:37+0100, Alejandro Colomar wrote: > Hi Kees, >=20 > I just learnt about kalloc_objs() et al. from > . >=20 > ptr =3D kmalloc_obj(*ptr); > ptr =3D kmalloc_objs(*ptr, n); >=20 > This resembles a lot the macro we have in shadow-utils, malloc_T(), > which would be used as (to resemble the above): >=20 > ptr =3D malloc_T(1, typeof(*ptr)); // But we'd really pass the type > ptr =3D malloc_T(n, typeof(*ptr)); // But we'd really pass the type >=20 > But I've noticed some design mistakes that make it not as safe as it > seems. >=20 > Default arguments > ~~~~~~~~~~~~~~~~~ >=20 > I tend to think it's simpler to have a single API that works for both > 1 element and multiple elements. The special-casing of 1 element seems > unnecessary, and having a literal 1 works just fine. >=20 > I think the combination of having the macros be variadic (for gfp) with > having two very similar APIs that differ in number of arguments, and > all those arguments being integer types, is prone to errors. Consider > the case where one would accidentally write >=20 > ptr =3D kmalloc_obj(*ptr, n); // Bogus > instead of > ptr =3D kmalloc_objs(*ptr, n); >=20 > The compiler wouldn't realize at all. That's a strong argument in > favour of having default arguments be required to be explicit, with an > empty argument: >=20 > ptr =3D kmalloc_obj(*ptr,); > ptr =3D kmalloc_objs(*ptr, n,); >=20 > I know you (and Linus too, FWIW) have previously claimed that it looks > weird to the eye. But I'm pretty sure you could get used to it. That's > certainly going to be safer. >=20 > With mandatory empty arguments, the compiler would easily distinguish > mistakes like the one above. >=20 > Type safety > ~~~~~~~~~~~ >=20 > Apart from the issues with the above, the ability to pass a variable > instead of a type name is also a bad choice. In shadow-utils, we > require a type name, and a variable is rejected. We implement that with > the typeas() macro: >=20 > #define typeas(T) typeof((T){0}) >=20 > This macro works exactly like typeof(), but it requires that the input > is also a type. Passing a variable is a syntax error. We implement > malloc_T() with it: >=20 > // malloc_T - malloc type-safe > #define malloc_T_(n, T) \ > ({ \ > (typeas(T) *){reallocarray(n, sizeof(T))}; \ I meant the following: (typeas(T) *){reallocarray(NULL, n, sizeof(T))}; I had the issue while pasting and adapting for simplicity. The original code is correct, of course. > }) >=20 > which is used as (taking some arbitrary examples from shadow-utils): >=20 > lp =3D xmalloc_T(1, struct link_name); > targs =3D xmalloc_T(n_args + 3, char *); >=20 > Some reasons for passing a type name instead of a variable are: >=20 > - It allows grepping for all allocations of a given type. > - It adds readability. It's similar to declaring variables with some > explicit type, vs. using 'auto' (__auto_type) everywhere. >=20 > But there's also a safety aspect. Consider we want to allocate an array > of 42 ints. And consider the programmer accidentally swaps arguments. >=20 > int *p =3D malloc_T(int, 42); // syntax error > int *p =3D malloc_T(42, int); > vs > int *p =3D kmalloc_objs(*p, 42); > int *p =3D kmalloc_objs(42, *p); // Bogus >=20 > The latter is dereferencing an uninitialized pointer. If for some > reason the pointer had a value before this call, you'd be allocating as > many elements as *p says, which would be bogus, and since typeof(42) is > the same as typeof(*p), the return type would be valid, so this would > still compile. >=20 >=20 > Have a lovely night! > Alex >=20 > --=20 > --=20 --mpvesaek3qhuotjx Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEES7Jt9u9GbmlWADAi64mZXMKQwqkFAmm4TWAACgkQ64mZXMKQ wqlyAQ/+JwR+HHhWI3sgm2nFIvk4wUMfaGCFwcIlzVGnm/jXVtPDvBZUiUZoXfqp avrba9pdY895jenxBWFB8Jzsg7Ih5U/fiIKmPn/EmGjAQ1DG55r33WM/KSz+Kh+N Rry9luMxYnC4jLkI3K8bF1Ft4dD1nBI1dvFKVLPHVSVyali5uRoltUiA/dMjhsNR OL68ad2oFsCdvpjQwAl3EPkdX2zjU/3pe4axPXxsdk1TpSpve9yrZWUag5tdA8y4 vWFhmGSlPQZJOOo5fiOH8Mhl8vQGdWRdHnIlGrY8EDEaOGZcnaRBDqFfF2/LoVam JlQxXFZ3WYUWO0uvG381cWaSf2WH30x8r8of56vs//F64QBqZJEUoijP2F4G81T0 hufNTfJvfpGrt+ftVj1+UL/3DMdW3J9PtMjJttDuM9QVJBDxpqK19sQSt813m6IQ N19aWS5bRLpx+qQUsFfY8xqxBnm4aCm91SlGOuuC+ztzN14M3Uwt+imWTRHwsflr sQ5tKWOUxOLzD2wWdtiuisupxZkvT1sL2H2Zhimv+ErqaJAo+xT7l4lY3FCAoR6B 0C6FsfE4U3vgGILaJWW/HImixFbJMFYuQLjRT7kubj2JRU3x74NTIOU7xJDJVIGt iLc5j/HK0Kp4rJamDu40UxXWmUAmhMmza6h0pRQqcym1r74PzM0= =Gkgl -----END PGP SIGNATURE----- --mpvesaek3qhuotjx--