From: Tao Cui <[email protected]> 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.
Mark these allocations __GFP_ACCOUNT so the driving process pays for the memory it induces. Signed-off-by: Tao Cui <[email protected]> --- drivers/scsi/sg.c | 23 ++++++++++++++++++++--- drivers/scsi/st.c | 7 ++++--- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 6551f1284d44..9c1414479b21 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -911,6 +911,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) @@ -920,6 +933,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; + SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, "sg_ioctl: cmd=0x%x\n", (int) cmd_in)); read_only = (O_RDWR != (filp->f_flags & O_ACCMODE)); @@ -1829,7 +1845,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) @@ -1844,7 +1860,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; @@ -2134,7 +2151,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); diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index e9d41e3cc2dd..b92633ab2757 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -4074,7 +4074,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; @@ -4083,7 +4083,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; @@ -4109,7 +4110,7 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size) max_segs = STbuffer->use_sg; - priority = GFP_KERNEL | __GFP_NOWARN; + priority = GFP_KERNEL | __GFP_NOWARN | __GFP_ACCOUNT; if (STbuffer->cleared) priority |= __GFP_ZERO; -- 2.43.0
