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: 13+ 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-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-06 13:18 ` [PATCH 3/7] vhost: account the per-device kernel allocations " Tao Cui
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-06 13:18 ` [PATCH 5/7] iommufd: account the hw_queue page array " Tao Cui
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-06 13:18 ` [PATCH 7/7] io_uring: account the remaining per-object allocations " Tao Cui
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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox