From: sashiko-bot@kernel.org
To: "Tao Cui" <cui.tao@linux.dev>,
akpm@linux-foundation.org, dgilbert@interlog.com, mkp@kernel.org,
loberman@redhat.com, jmeneghi@redhat.com, kraxel@redhat.com,
vivek.kasireddy@intel.com, mst@redhat.com, jasowangio@gmail.com,
eperezma@redhat.com, stefanha@redhat.com, sgarzare@redhat.com,
rostedt@goodmis.org, vdonnefort@google.com, mhiramat@kernel.org,
jgg@ziepe.ca, kevin.tian@intel.com, axboe@kernel.dk
Cc: linux-mm@kvack.org, James.Bottomley@HansenPartnership.com,
sumit.semwal@linaro.org, christian.koenig@amd.com,
phasta@kernel.org, joro@8bytes.org, will@kernel.org,
linux-scsi@vger.kernel.org, dri-devel@lists.freedesktop.org,
kvm@vger.kernel.org, virtualization@lists.linux.dev,
linux-trace-kernel@vger.kernel.org, bobbyeshleman@meta.com,
mathieu.desnoyers@efficios.com, robin.murphy@arm.com,
mason@kernel.org, aesteve@redhat.com, tjmercier@google.com,
harry@kernel.org, vbabka@suse.cz, cuitao@kylinos.cn,
media-ci@linuxtv.org
Subject: Re: [PATCH 1/7] scsi: sg and st: account the command buffer memory to memcg
Date: Sat, 07 Nov 2026 13:27:23 +0000 [thread overview]
Message-ID: <sashiko-outbox-202918@kernel.org> (raw)
In-Reply-To: <20261106131829.3228926-2-cui.tao@linux.dev>
Thank you for your contribution! Sashiko AI review found 4 potential
issues to consider:
- [High] scsi: sg: GFP_ATOMIC | __GFP_ACCOUNT in sg_build_indirect()
bypasses memcg max
- [Medium] scsi: sg: unrelated and broken blktrace CAP_SYS_ADMIN gate in
sg_ioctl_common()
- [Medium] scsi: st: misattributed GFP_KERNEL_ACCOUNT probe charges in
new_tape_buffer()
- [Low] scsi: sg: commit message cites non-existent history in
sg_build_indirect()
It also noticed 1 related pre-existing issue this patch does not
introduce:
- [High] scsi: sg: shift-out-of-bounds in sg_build_indirect() [1]
--
commit ec96b2b0cdd1df3575b4521cd9f81da9824bc2b2
Author: Tao Cui <cuitao@kylinos.cn>
scsi: sg and st: account the command buffer memory to memcg
This commit adds __GFP_ACCOUNT to buffer and descriptor allocations in the
sg and st drivers to charge them to the calling process's memory cgroup, and
adds a CAP_SYS_ADMIN check for blktrace ioctls in sg_ioctl_common().
> The sg data buffers are unaccounted: the per-fd reserved buffer, the
> scatter-gather page array, and the order-0..N pages behind it, plus the
> per-device tape buffer in st. All of it is user controllable. The
> reserved size is capped only by the device max_sectors, SG_MAX_QUEUE
> (16) commands can be in flight per fd, and the fd count is bounded by
> RLIMIT_NOFILE. Nothing is charged to the memcg of the process driving
> it. The September 2026 fixes in sg_build_indirect reshaped the element
> sizing and left the accounting alone.
[Severity: Low]
Is the commit message accurate about the history of sg_build_indirect() and
the reserved buffer cap?
In git history, sg_build_indirect() has not been modified since
aaff5ebaa269 ("scsi: remove the unchecked_isa_dma flag") in 2021, and its
element sizing has not changed since 10db10d144c0 ("sg: convert the indirect
IO path to use the block layer") in 2008. In addition, the initial per-fd
reserved buffer in sg_add_sfp() is capped by min_t(int, def_reserved_size,
max_sectors_bytes(sdp->device->request_queue)), while only resizing via
SG_SET_RESERVED_SIZE is capped solely by max_sectors_bytes().
> diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
> index 5408f002e6c01..80d919fa5cf91 100644
> --- a/drivers/scsi/sg.c
> +++ b/drivers/scsi/sg.c
> @@ -910,6 +910,19 @@ static int put_compat_request_table(struct compat_sg_req_info __user *o,
> }
> #endif
>
> +/*
> + * The sg passthrough of the blktrace ioctls has the same exposure as the
> + * block device path: holding the node is the only requirement today, and
> + * a created trace outlives the fd. Must match the gate in
> + * blk_trace_ioctl().
> + */
> +static bool sg_is_blktrace_cmd(unsigned int cmd)
> +{
> + return cmd == BLKTRACESETUP || cmd == BLKTRACESETUP2 ||
> + cmd == BLKTRACESTART || cmd == BLKTRACESTOP ||
> + cmd == BLKTRACETEARDOWN;
> +}
> +
> static long
> sg_ioctl_common(struct file *filp, Sg_device *sdp, Sg_fd *sfp,
> unsigned int cmd_in, void __user *p)
> @@ -919,6 +932,9 @@ sg_ioctl_common(struct file *filp, Sg_device *sdp, Sg_fd *sfp,
> Sg_request *srp;
> unsigned long iflags;
>
> + if (sg_is_blktrace_cmd(cmd_in) && !capable(CAP_SYS_ADMIN))
> + return -EPERM;
> +
[Severity: Medium]
Does this capability check belong in a memcg accounting commit, and does it
cause a UAPI regression for unprivileged users with access to /dev/sg*?
Despite the comment, blk_trace_ioctl() in kernel/trace/blktrace.c does not
check capable(CAP_SYS_ADMIN); block devices gate these ioctls only on access
to the device node. Moreover, sg_is_blktrace_cmd() matches BLKTRACESETUP2
even though sg_ioctl_common() only implements BLKTRACESETUP, BLKTRACESTART,
BLKTRACESTOP, and BLKTRACETEARDOWN, so unprivileged callers now get -EPERM
instead of -ENOTTY for BLKTRACESETUP2.
> @@ -1841,7 +1857,7 @@ static int
> sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp, int tablesize)
> {
> int sg_bufflen = tablesize * sizeof(struct page *);
> - gfp_t gfp_flags = GFP_ATOMIC | __GFP_NOWARN;
> + gfp_t gfp_flags = GFP_ATOMIC | __GFP_NOWARN | __GFP_ACCOUNT;
>
> schp->pages = kzalloc(sg_bufflen, gfp_flags);
> if (!schp->pages)
> @@ -1856,7 +1872,8 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
> int ret_sz = 0, i, k, rem_sz, num, mx_sc_elems;
> int sg_tablesize = sfp->parentdp->sg_tablesize;
> int blk_size = buff_size, order;
> - gfp_t gfp_mask = GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN | __GFP_ZERO;
> + gfp_t gfp_mask = GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN |
> + __GFP_ACCOUNT | __GFP_ZERO;
>
> if (blk_size < 0)
> return -EFAULT;
[Severity: High]
This problem wasn't introduced by this patch, but can the ret_sz shift in
sg_build_indirect() trigger a signed shift-out-of-bounds [1]?
drivers/scsi/sg.c:sg_build_indirect() {
...
num = scatter_elem_sz;
...
order = get_order(num);
retry:
ret_sz = 1 << (PAGE_SHIFT + order);
...
}
On 4 KB page architectures, setting the scatter_elem_sz module parameter
near INT_MAX gives order == 19, so 1 << (PAGE_SHIFT + order) evaluates the
signed 32-bit shift 1 << 31, triggering UBSAN or yielding a negative ret_sz
that corrupts the allocation loop.
> @@ -2146,7 +2163,7 @@ sg_add_sfp(Sg_device * sdp)
> unsigned long iflags;
> int bufflen;
>
> - sfp = kzalloc_obj(*sfp, GFP_ATOMIC | __GFP_NOWARN);
> + sfp = kzalloc_obj(*sfp, GFP_ATOMIC | __GFP_NOWARN | __GFP_ACCOUNT);
> if (!sfp)
> return ERR_PTR(-ENOMEM);
[Severity: High]
Does combining GFP_ATOMIC with __GFP_ACCOUNT in sg_build_sgat(),
sg_build_indirect(), and sg_add_sfp() allow processes to bypass their memcg
memory.max limit?
GFP_ATOMIC sets __GFP_HIGH and lacks __GFP_DIRECT_RECLAIM. When a memcg is
at memory.max, try_charge_memcg() skips reclaim because the allocation
cannot block and then force-charges past memory.max because __GFP_HIGH is
set:
mm/memcontrol.c:try_charge_memcg() {
...
nomem:
if (!(gfp_mask & (__GFP_NOFAIL | __GFP_HIGH)))
return -ENOMEM;
force:
page_counter_charge(&memcg->memory, nr_pages);
...
}
All callers of sg_add_sfp(), sg_build_sgat(), and sg_build_indirect()
(sg_open(), SG_SET_RESERVED_SIZE in sg_ioctl_common(), and sg_start_req())
run in sleepable process context holding only mutexes, so using GFP_KERNEL
would allow memcg reclaim and enforce memory.max.
> diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
> index f1c3c49466379..7083d37622c08 100644
> --- a/drivers/scsi/st.c
> +++ b/drivers/scsi/st.c
> @@ -3973,7 +3973,7 @@ static struct st_buffer *new_tape_buffer(int max_sg)
> {
> struct st_buffer *tb;
>
> - tb = kzalloc_obj(struct st_buffer);
> + tb = kzalloc_obj(struct st_buffer, GFP_KERNEL_ACCOUNT);
> if (!tb) {
> printk(KERN_NOTICE "st: Can't allocate new tape buffer.\n");
> return NULL;
> @@ -3982,7 +3982,8 @@ static struct st_buffer *new_tape_buffer(int max_sg)
> tb->use_sg = max_sg;
> tb->buffer_size = 0;
>
> - tb->reserved_pages = kzalloc_objs(struct page *, max_sg);
> + tb->reserved_pages = kzalloc_objs(struct page *, max_sg,
> + GFP_KERNEL_ACCOUNT);
> if (!tb->reserved_pages) {
> kfree(tb);
> return NULL;
[Severity: Medium]
Does using GFP_KERNEL_ACCOUNT in new_tape_buffer() charge the device probe
context instead of the process driving tape I/O?
new_tape_buffer() is only called from st_probe() when a tape device is
attached, and both tb and tb->reserved_pages live until scsi_tape_release(),
so they are never charged to the process performing I/O. Meanwhile, the
per-I/O page array allocated in the driving process's context during direct
I/O in sgl_map_user_pages() (pages = kmalloc_objs(*pages, max_pages))
remains unaccounted.
[1] https://sashiko.dev/#/bug/linux-ccac9556-cc9e-4b08-b44f-5f7ffb342827
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261106131829.3228926-1-cui.tao@linux.dev?part=1
next prev parent reply other threads:[~2026-11-07 13:27 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-06 13:18 [PATCH 0/7] memcg: account the remaining uncharged kernel allocations Tao Cui
2026-11-06 13:18 ` [PATCH 1/7] scsi: sg and st: account the command buffer memory to memcg Tao Cui
2026-11-07 13:27 ` sashiko-bot [this message]
2026-11-09 2:25 ` Tao Cui
2026-11-06 13:18 ` [PATCH 2/7] dma-buf/udmabuf: account the page array metadata " Tao Cui
2026-11-06 13:23 ` Christian König
2026-11-06 17:25 ` T.J. Mercier
2026-11-09 2:32 ` Tao Cui
2026-11-09 10:56 ` Christian König
2026-11-09 13:44 ` Albert Esteve
2026-11-07 13:27 ` sashiko-bot
2026-11-06 13:18 ` [PATCH 3/7] vhost: account the per-device kernel allocations " Tao Cui
2026-11-07 13:27 ` sashiko-bot
2026-11-06 13:18 ` [PATCH 4/7] tracing: account ring buffer pages and trace_array metadata " Tao Cui
2026-11-07 13:27 ` sashiko-bot
2026-11-09 2:35 ` Tao Cui
2026-11-11 16:47 ` Vincent Donnefort
2026-11-11 23:14 ` Steven Rostedt
2026-11-06 13:18 ` [PATCH 5/7] iommufd: account the hw_queue page array " Tao Cui
2026-11-07 13:27 ` sashiko-bot
2026-11-06 13:18 ` [PATCH 6/7] io_uring: account the ring context and SQPOLL thread data " Tao Cui
2026-11-07 13:27 ` sashiko-bot
2026-11-09 2:37 ` Tao Cui
2026-11-06 13:18 ` [PATCH 7/7] io_uring: account the remaining per-object allocations " Tao Cui
2026-11-07 13:27 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-202918@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=James.Bottomley@HansenPartnership.com \
--cc=aesteve@redhat.com \
--cc=akpm@linux-foundation.org \
--cc=axboe@kernel.dk \
--cc=bobbyeshleman@meta.com \
--cc=christian.koenig@amd.com \
--cc=cui.tao@linux.dev \
--cc=cuitao@kylinos.cn \
--cc=dgilbert@interlog.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=eperezma@redhat.com \
--cc=harry@kernel.org \
--cc=jasowangio@gmail.com \
--cc=jgg@ziepe.ca \
--cc=jmeneghi@redhat.com \
--cc=joro@8bytes.org \
--cc=kevin.tian@intel.com \
--cc=kraxel@redhat.com \
--cc=kvm@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-scsi@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=loberman@redhat.com \
--cc=mason@kernel.org \
--cc=mathieu.desnoyers@efficios.com \
--cc=media-ci@linuxtv.org \
--cc=mhiramat@kernel.org \
--cc=mkp@kernel.org \
--cc=mst@redhat.com \
--cc=phasta@kernel.org \
--cc=robin.murphy@arm.com \
--cc=rostedt@goodmis.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=sgarzare@redhat.com \
--cc=stefanha@redhat.com \
--cc=sumit.semwal@linaro.org \
--cc=tjmercier@google.com \
--cc=vbabka@suse.cz \
--cc=vdonnefort@google.com \
--cc=virtualization@lists.linux.dev \
--cc=vivek.kasireddy@intel.com \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.