as_user_ptr() is intended to be used where an arbitrary integer e.g. an error code is stored in a __user ptr.
The current implementation can be somewhat confusing in that it looks like it can be used as direct replacement for u64_to_user_ptr e.g. in PCuABI, where u64 addresses in the kernel-user interface are being replaced with capability containing types such as __kernel_uintptr_t.
Currently, passing a valid capability e.g. a __kernel_uintptr_t, __uintcap_t or user_uintptr_t etc to as_user_ptr() will result in a cast to (void __user *) and a valid capability/pointer that can be dereferenced. This is contrary to the code comment and intended usage for as_user_ptr().
Add a cast to (u64) before the cast to (void __user *)(user_uintptr_t) to make clearer the intended usage. This also always results in a null capability that cannot be dereferenced.
Signed-off-by: Zachary Leaf zachary.leaf@arm.com ---
rendered version: https://git.morello-project.org/zdleaf/linux/-/blob/docs/as_user_ptr_v3/Docu...
Documentation/core-api/user_ptr.rst | 16 +++++++++++++--- include/linux/user_ptr.h | 6 +++--- 2 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/Documentation/core-api/user_ptr.rst b/Documentation/core-api/user_ptr.rst index 21e02d4bd11b..197bb198ede7 100644 --- a/Documentation/core-api/user_ptr.rst +++ b/Documentation/core-api/user_ptr.rst @@ -31,7 +31,8 @@ errors are likely to occur in PCuABI if it is omitted. In certain situations, it is more convenient to represent user pointers as integers. The type ``user_uintptr_t`` must be used for that purpose. It is **the only integer type** that may be directly cast to and from a -user pointer, for instance ``user_uintptr_t u = (user_uintptr_t)uptr``. +user pointer, for instance ``user_uintptr_t uint = (user_uintptr_t)uptr`` +or ``void __user *uptr = (void __user *)uint``.
Note that ``(u)intptr_t`` is the recommended type to represent kernel pointers, but it cannot represent user pointers. @@ -106,6 +107,13 @@ Each function covers a particular category of input integer: - Integer of any type: ``as_user_ptr()`` - ``u64`` (deprecated): ``u64_to_user_ptr()``
+Note: ``as_user_ptr()`` nullifies any capability and is not a +replacement for most uses of ``u64_to_user_ptr()``. To convert an +integer representation of a user pointer i.e. ``user_uintptr_t`` back to +pointer type, a simple cast such as ``(void __user *)`` is sufficient. +See `Representing user pointers`_ and notes for ``as_user_ptr()`` and +``u64_to_user_ptr()`` below. + These functions are available in ``<linux/user_ptr.h>``, except ``compat_ptr()`` (``<linux/compat.h>``).
@@ -142,8 +150,10 @@ derived from in the PCuABI case. | | | ``compat_*`` struct | | | +------------------------------+--------------------+------------------------+-----------------------------------+------------------------------------------------------+ | ``as_user_ptr()`` | Arbitrary integer | Error code | Null capability | This is a pure representation change, as suggested | -| | | | | by the ``as_`` prefix. The resulting pointer cannot | -| | | | | be dereferenced. | +| | | | | by the ``as_`` prefix. Returns up to 64 bits of an | +| | | | | arbitrary integer represented as a user pointer. The | +| | | | | result is not a valid pointer and cannot be | +| | | | | dereferenced. | +------------------------------+--------------------+------------------------+-----------------------------------+------------------------------------------------------+ | ``u64_to_user_ptr()`` | ``u64`` integer | [Deprecated] | Null capability | Legacy function, new callers should not be added. | | | | | | Existing callers should move to either | diff --git a/include/linux/user_ptr.h b/include/linux/user_ptr.h index 0942b58cfb6a..516024f3fead 100644 --- a/include/linux/user_ptr.h +++ b/include/linux/user_ptr.h @@ -12,10 +12,10 @@ * as_user_ptr - convert an arbitrary integer value to a user pointer * @x: the integer value to convert * - * Returns @x represented as a user pointer. The result is not a valid pointer - * and shall not be dereferenced. + * Returns up to 64 bits of @x represented as a user pointer. The result is + * not a valid pointer and shall not be dereferenced. */ -#define as_user_ptr(x) ((void __user *)(user_uintptr_t)(x)) +#define as_user_ptr(x) ((void __user *)(user_uintptr_t)(u64)(x))
/* Same semantics as as_user_ptr(), but also requires x to be of a given type */ #define as_user_ptr_strict(type, x) ( \ -- 2.34.1
On 19/01/2023 17:37, Zachary Leaf wrote:
as_user_ptr() is intended to be used where an arbitrary integer e.g. an error code is stored in a __user ptr.
The current implementation can be somewhat confusing in that it looks like it can be used as direct replacement for u64_to_user_ptr e.g. in PCuABI, where u64 addresses in the kernel-user interface are being replaced with capability containing types such as __kernel_uintptr_t.
Currently, passing a valid capability e.g. a __kernel_uintptr_t, __uintcap_t or user_uintptr_t etc to as_user_ptr() will result in a cast to (void __user *) and a valid capability/pointer that can be dereferenced. This is contrary to the code comment and intended usage for as_user_ptr().
Add a cast to (u64) before the cast to (void __user *)(user_uintptr_t) to make clearer the intended usage. This also always results in a null capability that cannot be dereferenced.
Signed-off-by: Zachary Leaf zachary.leaf@arm.com
rendered version: https://git.morello-project.org/zdleaf/linux/-/blob/docs/as_user_ptr_v3/Docu...
Documentation/core-api/user_ptr.rst | 16 +++++++++++++--- include/linux/user_ptr.h | 6 +++--- 2 files changed, 16 insertions(+), 6 deletions(-)
Applied on next, thanks!
Kevin
diff --git a/Documentation/core-api/user_ptr.rst b/Documentation/core-api/user_ptr.rst index 21e02d4bd11b..197bb198ede7 100644 --- a/Documentation/core-api/user_ptr.rst +++ b/Documentation/core-api/user_ptr.rst @@ -31,7 +31,8 @@ errors are likely to occur in PCuABI if it is omitted. In certain situations, it is more convenient to represent user pointers as integers. The type ``user_uintptr_t`` must be used for that purpose. It is **the only integer type** that may be directly cast to and from a -user pointer, for instance ``user_uintptr_t u = (user_uintptr_t)uptr``. +user pointer, for instance ``user_uintptr_t uint = (user_uintptr_t)uptr`` +or ``void __user *uptr = (void __user *)uint``.
Note that ``(u)intptr_t`` is the recommended type to represent kernel pointers, but it cannot represent user pointers. @@ -106,6 +107,13 @@ Each function covers a particular category of input integer:
- Integer of any type: ``as_user_ptr()``
- ``u64`` (deprecated): ``u64_to_user_ptr()``
+Note: ``as_user_ptr()`` nullifies any capability and is not a +replacement for most uses of ``u64_to_user_ptr()``. To convert an +integer representation of a user pointer i.e. ``user_uintptr_t`` back to +pointer type, a simple cast such as ``(void __user *)`` is sufficient. +See `Representing user pointers`_ and notes for ``as_user_ptr()`` and +``u64_to_user_ptr()`` below.
These functions are available in ``<linux/user_ptr.h>``, except ``compat_ptr()`` (``<linux/compat.h>``).
@@ -142,8 +150,10 @@ derived from in the PCuABI case. | | | ``compat_*`` struct | | | +------------------------------+--------------------+------------------------+-----------------------------------+------------------------------------------------------+ | ``as_user_ptr()`` | Arbitrary integer | Error code | Null capability | This is a pure representation change, as suggested | -| | | | | by the ``as_`` prefix. The resulting pointer cannot | -| | | | | be dereferenced. | +| | | | | by the ``as_`` prefix. Returns up to 64 bits of an | +| | | | | arbitrary integer represented as a user pointer. The | +| | | | | result is not a valid pointer and cannot be | +| | | | | dereferenced. | +------------------------------+--------------------+------------------------+-----------------------------------+------------------------------------------------------+ | ``u64_to_user_ptr()`` | ``u64`` integer | [Deprecated] | Null capability | Legacy function, new callers should not be added. | | | | | | Existing callers should move to either | diff --git a/include/linux/user_ptr.h b/include/linux/user_ptr.h index 0942b58cfb6a..516024f3fead 100644 --- a/include/linux/user_ptr.h +++ b/include/linux/user_ptr.h @@ -12,10 +12,10 @@
- as_user_ptr - convert an arbitrary integer value to a user pointer
- @x: the integer value to convert
- Returns @x represented as a user pointer. The result is not a valid pointer
- and shall not be dereferenced.
- Returns up to 64 bits of @x represented as a user pointer. The result is
*/
- not a valid pointer and shall not be dereferenced.
-#define as_user_ptr(x) ((void __user *)(user_uintptr_t)(x)) +#define as_user_ptr(x) ((void __user *)(user_uintptr_t)(u64)(x))
/* Same semantics as as_user_ptr(), but also requires x to be of a given type */
#define as_user_ptr_strict(type, x) ( \
2.34.1
linux-morello mailing list -- linux-morello@op-lists.linaro.org To unsubscribe send an email to linux-morello-leave@op-lists.linaro.org
linux-morello@op-lists.linaro.org