* [PATCH] accel/amdxdna: Bound the page count of a user supplied buffer
@ 2026-08-26 19:57 Taimuraz Kaitmazov
2026-08-26 20:09 ` sashiko-bot
2026-08-26 21:20 ` Lizhi Hou
0 siblings, 2 replies; 6+ messages in thread
From: Taimuraz Kaitmazov @ 2026-08-26 19:57 UTC (permalink / raw)
To: Lizhi Hou, Min Ma, Oded Gabbay; +Cc: taimuraz, dri-devel, linux-kernel
amdxdna_get_ubuf() puts a per-entry page count derived from a __u64
va_ent[i].len into a u32, then passes it to pin_user_pages_fast(), whose
nr_pages is an int. An entry of 2^44 bytes truncates npages to zero, so
nothing is pinned, the ret != npages test still passes, and ubuf->pages
keeps whatever kvmalloc_objs() returned while ubuf->nr_pages describes the
untruncated count. amdxdna_ubuf_release() then walks all of it. Reaching
that needs CAP_IPC_LOCK and a multi-gigabyte kvmalloc() to succeed.
Reject a total that does not fit in an int. The lengths are page aligned
and summed with check_add_overflow(), so the total is at least as large as
any one entry and bounds the pin call, the offset accumulator and
sg_alloc_table_from_pages().
Fixes: bd72d4acda10 ("accel/amdxdna: Support user space allocated buffer")
Signed-off-by: Taimuraz Kaitmazov <taimuraz@kaitmazov.com>
---
drivers/accel/amdxdna/amdxdna_ubuf.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/accel/amdxdna/amdxdna_ubuf.c b/drivers/accel/amdxdna/amdxdna_ubuf.c
index 0e0cd69cd1fb..da8e32566ae0 100644
--- a/drivers/accel/amdxdna/amdxdna_ubuf.c
+++ b/drivers/accel/amdxdna/amdxdna_ubuf.c
@@ -125,6 +125,12 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev,
}
ubuf->nr_pages = exp_info.size >> PAGE_SHIFT;
+ if (ubuf->nr_pages > INT_MAX) {
+ XDNA_ERR(xdna, "Too many pages %lld", ubuf->nr_pages);
+ ret = -EINVAL;
+ goto free_ent;
+ }
+
lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
new_pinned = atomic64_add_return(ubuf->nr_pages, &ubuf->mm->pinned_vm);
if (new_pinned > lock_limit && !capable(CAP_IPC_LOCK)) {
--
2.55.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH] accel/amdxdna: Bound the page count of a user supplied buffer
2026-08-26 19:57 [PATCH] accel/amdxdna: Bound the page count of a user supplied buffer Taimuraz Kaitmazov
@ 2026-08-26 20:09 ` sashiko-bot
2026-08-26 21:20 ` Lizhi Hou
1 sibling, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-08-26 20:09 UTC (permalink / raw)
To: Taimuraz Kaitmazov; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [Critical] Unhandled zero-size user buffer bypasses constraints and leads to a fatal kernel panic due to ZERO_SIZE_PTR dereference.
--
commit 0ce5a2a6bc3b9a95a5dd641e22f058018b729ead
Author: Taimuraz Kaitmazov <taimuraz@kaitmazov.com>
accel/amdxdna: Bound the page count of a user supplied buffer
amdxdna_get_ubuf() puts a per-entry page count derived from a __u64
va_ent[i].len into a u32, then passes it to pin_user_pages_fast().
This patch rejects a total that does not fit in an int to prevent
truncation and unbound memory operations.
> diff --git a/drivers/accel/amdxdna/amdxdna_ubuf.c b/drivers/accel/amdxdna/amdxdna_ubuf.c
> index 0e0cd69cd1fbf..da8e32566ae0a 100644
> --- a/drivers/accel/amdxdna/amdxdna_ubuf.c
> +++ b/drivers/accel/amdxdna/amdxdna_ubuf.c
> @@ -125,6 +125,12 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev,
> }
>
> ubuf->nr_pages = exp_info.size >> PAGE_SHIFT;
> + if (ubuf->nr_pages > INT_MAX) {
> + XDNA_ERR(xdna, "Too many pages %lld", ubuf->nr_pages);
> + ret = -EINVAL;
> + goto free_ent;
> + }
> +
[Severity: Critical]
This isn't a bug introduced by this patch, but is it possible for
ubuf->nr_pages to be 0 here, leading to a kernel panic later?
If a user calls the AMDXDNA_DRM_CREATE_BO ioctl with a virtual address
table containing at least one entry but with lengths set to 0,
exp_info.size becomes 0 and ubuf->nr_pages becomes 0. This bypasses the
bounds check above.
Then kvmalloc_objs() allocates ubuf->pages with size 0, which returns
ZERO_SIZE_PTR (0x10) instead of NULL. Later, pin_user_pages_fast() handles
npages = 0 by returning 0, allowing the zero-length dma-buf to be
exported.
When the buffer is eventually mapped in amdxdna_ubuf_map() in
amdxdna_ubuf.c:
ret = sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->nr_pages, 0,
ubuf->nr_pages << PAGE_SHIFT, GFP_KERNEL);
sg_alloc_table_from_pages() delegates to sg_alloc_append_table_from_pages(),
which computes chunks = 1 and evaluates pages[0] in its first iteration
since the nested loop bounds check is skipped when n_pages == 0.
Dereferencing ZERO_SIZE_PTR (0x10) will cause a fatal kernel page fault.
Could we add a check for ubuf->nr_pages == 0 here as well?
> lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
> new_pinned = atomic64_add_return(ubuf->nr_pages, &ubuf->mm->pinned_vm);
> if (new_pinned > lock_limit && !capable(CAP_IPC_LOCK)) {
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260826195736.358579-1-taimuraz@kaitmazov.com?part=1
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] accel/amdxdna: Bound the page count of a user supplied buffer
2026-08-26 19:57 [PATCH] accel/amdxdna: Bound the page count of a user supplied buffer Taimuraz Kaitmazov
2026-08-26 20:09 ` sashiko-bot
@ 2026-08-26 21:20 ` Lizhi Hou
2026-08-26 21:28 ` [PATCH v2] " Taimuraz Kaitmazov
1 sibling, 1 reply; 6+ messages in thread
From: Lizhi Hou @ 2026-08-26 21:20 UTC (permalink / raw)
To: Taimuraz Kaitmazov, Min Ma, Oded Gabbay; +Cc: dri-devel, linux-kernel
On 8/26/26 12:57, Taimuraz Kaitmazov wrote:
> amdxdna_get_ubuf() puts a per-entry page count derived from a __u64
> va_ent[i].len into a u32, then passes it to pin_user_pages_fast(), whose
> nr_pages is an int. An entry of 2^44 bytes truncates npages to zero, so
> nothing is pinned, the ret != npages test still passes, and ubuf->pages
> keeps whatever kvmalloc_objs() returned while ubuf->nr_pages describes the
> untruncated count. amdxdna_ubuf_release() then walks all of it. Reaching
> that needs CAP_IPC_LOCK and a multi-gigabyte kvmalloc() to succeed.
>
> Reject a total that does not fit in an int. The lengths are page aligned
> and summed with check_add_overflow(), so the total is at least as large as
> any one entry and bounds the pin call, the offset accumulator and
> sg_alloc_table_from_pages().
>
> Fixes: bd72d4acda10 ("accel/amdxdna: Support user space allocated buffer")
> Signed-off-by: Taimuraz Kaitmazov <taimuraz@kaitmazov.com>
> ---
> drivers/accel/amdxdna/amdxdna_ubuf.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/drivers/accel/amdxdna/amdxdna_ubuf.c b/drivers/accel/amdxdna/amdxdna_ubuf.c
> index 0e0cd69cd1fb..da8e32566ae0 100644
> --- a/drivers/accel/amdxdna/amdxdna_ubuf.c
> +++ b/drivers/accel/amdxdna/amdxdna_ubuf.c
> @@ -125,6 +125,12 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev,
> }
>
> ubuf->nr_pages = exp_info.size >> PAGE_SHIFT;
> + if (ubuf->nr_pages > INT_MAX) {
> + XDNA_ERR(xdna, "Too many pages %lld", ubuf->nr_pages);
XDNA_DBG(.... %llu", )
Could you also add the boundary check sashiko suggested? Maybe something
like:
for (i = 0, exp_info.size = 0; i < num_entries; i++) {
if (!IS_ALIGNED(va_ent[i].vaddr, PAGE_SIZE) ||
- !IS_ALIGNED(va_ent[i].len, PAGE_SIZE)) {
- XDNA_ERR(xdna, "Invalid address or len %llx, %llx",
+ !IS_ALIGNED(va_ent[i].len, PAGE_SIZE) ||
+ !va_ent[i].len) {
+ XDNA_DBG(xdna, "Invalid address or len %llx, %llx",
va_ent[i].vaddr, va_ent[i].len);
Thanks,
Lizhi
> + ret = -EINVAL;
> + goto free_ent;
> + }
> +
> lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
> new_pinned = atomic64_add_return(ubuf->nr_pages, &ubuf->mm->pinned_vm);
> if (new_pinned > lock_limit && !capable(CAP_IPC_LOCK)) {
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2] accel/amdxdna: Bound the page count of a user supplied buffer
2026-08-26 21:20 ` Lizhi Hou
@ 2026-08-26 21:28 ` Taimuraz Kaitmazov
2026-08-26 21:43 ` sashiko-bot
2026-08-26 23:04 ` Lizhi Hou
0 siblings, 2 replies; 6+ messages in thread
From: Taimuraz Kaitmazov @ 2026-08-26 21:28 UTC (permalink / raw)
To: Lizhi Hou, Min Ma, Oded Gabbay; +Cc: taimuraz, dri-devel, linux-kernel
amdxdna_get_ubuf() puts a per-entry page count derived from a __u64
va_ent[i].len into a u32, then passes it to pin_user_pages_fast(), whose
nr_pages is an int. An entry of 2^44 bytes truncates npages to zero, so
nothing is pinned, the ret != npages test still passes, and ubuf->pages
keeps whatever kvmalloc_objs() returned while ubuf->nr_pages describes the
untruncated count. amdxdna_ubuf_release() then walks all of it. Reaching
that needs CAP_IPC_LOCK and a multi-gigabyte kvmalloc() to succeed.
Reject a total that does not fit in an int. The lengths are page aligned
and summed with check_add_overflow(), so the total is at least as large as
any one entry and bounds the pin call, the offset accumulator and
sg_alloc_table_from_pages().
Reject a zero length entry as well: it contributes nothing to the mapping
and a table of them leaves nr_pages at zero.
Fixes: bd72d4acda10 ("accel/amdxdna: Support user space allocated buffer")
Signed-off-by: Taimuraz Kaitmazov <taimuraz@kaitmazov.com>
---
v2:
- XDNA_DBG and %llu, per your comment.
- Reject a zero length entry in the validation loop, and lower that log to
XDNA_DBG too, as you suggested.
drivers/accel/amdxdna/amdxdna_ubuf.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/accel/amdxdna/amdxdna_ubuf.c b/drivers/accel/amdxdna/amdxdna_ubuf.c
index 0e0cd69cd1fb..bf1e4dd7bbc3 100644
--- a/drivers/accel/amdxdna/amdxdna_ubuf.c
+++ b/drivers/accel/amdxdna/amdxdna_ubuf.c
@@ -111,8 +111,9 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev,
for (i = 0, exp_info.size = 0; i < num_entries; i++) {
if (!IS_ALIGNED(va_ent[i].vaddr, PAGE_SIZE) ||
- !IS_ALIGNED(va_ent[i].len, PAGE_SIZE)) {
- XDNA_ERR(xdna, "Invalid address or len %llx, %llx",
+ !IS_ALIGNED(va_ent[i].len, PAGE_SIZE) ||
+ !va_ent[i].len) {
+ XDNA_DBG(xdna, "Invalid address or len %llx, %llx",
va_ent[i].vaddr, va_ent[i].len);
ret = -EINVAL;
goto free_ent;
@@ -125,6 +126,12 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev,
}
ubuf->nr_pages = exp_info.size >> PAGE_SHIFT;
+ if (ubuf->nr_pages > INT_MAX) {
+ XDNA_DBG(xdna, "Too many pages %llu", ubuf->nr_pages);
+ ret = -EINVAL;
+ goto free_ent;
+ }
+
lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
new_pinned = atomic64_add_return(ubuf->nr_pages, &ubuf->mm->pinned_vm);
if (new_pinned > lock_limit && !capable(CAP_IPC_LOCK)) {
--
2.55.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2] accel/amdxdna: Bound the page count of a user supplied buffer
2026-08-26 21:28 ` [PATCH v2] " Taimuraz Kaitmazov
@ 2026-08-26 21:43 ` sashiko-bot
2026-08-26 23:04 ` Lizhi Hou
1 sibling, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-08-26 21:43 UTC (permalink / raw)
To: Taimuraz Kaitmazov; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Unrestricted userspace-controlled allocation size for `va_ent` can trigger the OOM killer.
--
commit 9b9a5c5cd1330d0aae0aea71c45dc018b59ee7e1
Author: Taimuraz Kaitmazov <taimuraz@kaitmazov.com>
accel/amdxdna: Bound the page count of a user supplied buffer
This patch fixes an issue where amdxdna_get_ubuf() could truncate a per-entry
page count derived from a 64-bit length into a 32-bit integer. It adds
validation to ensure the total page count fits within an integer, preventing
invalid memory accesses. It also explicitly rejects zero-length buffer
entries.
> diff --git a/drivers/accel/amdxdna/amdxdna_ubuf.c b/drivers/accel/amdxdna/amdxdna_ubuf.c
> index 0e0cd69cd1fbf..bf1e4dd7bbc30 100644
> --- a/drivers/accel/amdxdna/amdxdna_ubuf.c
> +++ b/drivers/accel/amdxdna/amdxdna_ubuf.c
> @@ -111,8 +111,9 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev,
>
> for (i = 0, exp_info.size = 0; i < num_entries; i++) {
[Severity: High]
This is a pre-existing issue, but is it possible for num_entries to be a
massive value here?
Looking at amdxdna_gem_create_ubuf_object() in
drivers/accel/amdxdna/amdxdna_gem.c, it appears that va_tbl.num_entries
from userspace is passed directly to amdxdna_get_ubuf() without any bounds
checking.
Earlier in amdxdna_get_ubuf(), we allocate memory based on this value:
va_ent = kvzalloc_objs(*va_ent, num_entries);
If an unprivileged user with a non-zero RLIMIT_MEMLOCK sets num_entries to a
huge value like U32_MAX, can this allocate an unrestricted amount of memory
and trigger the OOM killer before we even reach the bounds checks on nr_pages
added in this patch?
> if (!IS_ALIGNED(va_ent[i].vaddr, PAGE_SIZE) ||
> - !IS_ALIGNED(va_ent[i].len, PAGE_SIZE)) {
> - XDNA_ERR(xdna, "Invalid address or len %llx, %llx",
> + !IS_ALIGNED(va_ent[i].len, PAGE_SIZE) ||
> + !va_ent[i].len) {
> + XDNA_DBG(xdna, "Invalid address or len %llx, %llx",
> va_ent[i].vaddr, va_ent[i].len);
> ret = -EINVAL;
> goto free_ent;
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260826212825.408846-1-taimuraz@kaitmazov.com?part=1
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] accel/amdxdna: Bound the page count of a user supplied buffer
2026-08-26 21:28 ` [PATCH v2] " Taimuraz Kaitmazov
2026-08-26 21:43 ` sashiko-bot
@ 2026-08-26 23:04 ` Lizhi Hou
1 sibling, 0 replies; 6+ messages in thread
From: Lizhi Hou @ 2026-08-26 23:04 UTC (permalink / raw)
To: Taimuraz Kaitmazov, Min Ma, Oded Gabbay; +Cc: dri-devel, linux-kernel
On 8/26/26 14:28, Taimuraz Kaitmazov wrote:
> amdxdna_get_ubuf() puts a per-entry page count derived from a __u64
> va_ent[i].len into a u32, then passes it to pin_user_pages_fast(), whose
> nr_pages is an int. An entry of 2^44 bytes truncates npages to zero, so
> nothing is pinned, the ret != npages test still passes, and ubuf->pages
> keeps whatever kvmalloc_objs() returned while ubuf->nr_pages describes the
> untruncated count. amdxdna_ubuf_release() then walks all of it. Reaching
> that needs CAP_IPC_LOCK and a multi-gigabyte kvmalloc() to succeed.
>
> Reject a total that does not fit in an int. The lengths are page aligned
> and summed with check_add_overflow(), so the total is at least as large as
> any one entry and bounds the pin call, the offset accumulator and
> sg_alloc_table_from_pages().
>
> Reject a zero length entry as well: it contributes nothing to the mapping
> and a table of them leaves nr_pages at zero.
>
> Fixes: bd72d4acda10 ("accel/amdxdna: Support user space allocated buffer")
> Signed-off-by: Taimuraz Kaitmazov <taimuraz@kaitmazov.com>
> ---
> v2:
> - XDNA_DBG and %llu, per your comment.
> - Reject a zero length entry in the validation loop, and lower that log to
> XDNA_DBG too, as you suggested.
>
> drivers/accel/amdxdna/amdxdna_ubuf.c | 11 +++++++++--
> 1 file changed, 9 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/accel/amdxdna/amdxdna_ubuf.c b/drivers/accel/amdxdna/amdxdna_ubuf.c
> index 0e0cd69cd1fb..bf1e4dd7bbc3 100644
> --- a/drivers/accel/amdxdna/amdxdna_ubuf.c
> +++ b/drivers/accel/amdxdna/amdxdna_ubuf.c
> @@ -111,8 +111,9 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev,
>
> for (i = 0, exp_info.size = 0; i < num_entries; i++) {
> if (!IS_ALIGNED(va_ent[i].vaddr, PAGE_SIZE) ||
> - !IS_ALIGNED(va_ent[i].len, PAGE_SIZE)) {
> - XDNA_ERR(xdna, "Invalid address or len %llx, %llx",
> + !IS_ALIGNED(va_ent[i].len, PAGE_SIZE) ||
> + !va_ent[i].len) {
> + XDNA_DBG(xdna, "Invalid address or len %llx, %llx",
> va_ent[i].vaddr, va_ent[i].len);
> ret = -EINVAL;
> goto free_ent;
> @@ -125,6 +126,12 @@ struct dma_buf *amdxdna_get_ubuf(struct drm_device *dev,
> }
>
> ubuf->nr_pages = exp_info.size >> PAGE_SHIFT;
> + if (ubuf->nr_pages > INT_MAX) {
> + XDNA_DBG(xdna, "Too many pages %llu", ubuf->nr_pages);
> + ret = -EINVAL;
> + goto free_ent;
> + }
> +
Reviewed-by: Lizhi Hou <lizhi.hou@amd.com>
> lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
> new_pinned = atomic64_add_return(ubuf->nr_pages, &ubuf->mm->pinned_vm);
> if (new_pinned > lock_limit && !capable(CAP_IPC_LOCK)) {
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-08-26 23:04 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-26 19:57 [PATCH] accel/amdxdna: Bound the page count of a user supplied buffer Taimuraz Kaitmazov
2026-08-26 20:09 ` sashiko-bot
2026-08-26 21:20 ` Lizhi Hou
2026-08-26 21:28 ` [PATCH v2] " Taimuraz Kaitmazov
2026-08-26 21:43 ` sashiko-bot
2026-08-26 23:04 ` Lizhi Hou
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).