mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] scsi: st: Prevent timeout arithmetic overflow
@ 2026-10-26 15:16 Yingjie Wang
  0 siblings, 0 replies; only message in thread
From: Yingjie Wang @ 2026-10-26 15:16 UTC (permalink / raw)
  To: linux-scsi
  Cc: loberman, jmeneghi, James.Bottomley, mkp, linux-kernel, linux-api

MT_ST_TIMEOUTS converts the requested timeout from seconds to jiffies in
signed int arithmetic. A sufficiently large value overflows before it is
stored in long_timeout or passed to blk_queue_rq_timeout(). Non-immediate
MTERASE commands also multiply long_timeout by eight, which can overflow
even when the original seconds-to-jiffies conversion fits.

These overflows can turn an administrator's timeout setting into a much
shorter request timeout. MTSETDRVBUFFER requires CAP_SYS_ADMIN, but the
driver should reject settings it cannot represent instead of accepting
a wrapped value.

Check the decoded seconds before multiplication, using the smaller of
INT_MAX and MAX_JIFFY_OFFSET as the jiffies limit. This keeps both the
signed timeout arguments and the relative jiffies interval in range.
For MTERASE, multiply in u64 and clamp to the same limit, so a valid long
timeout remains usable without wrapping when it is extended for erasure.
Zero retains its existing behavior, and timeouts within the limit are
unchanged.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: Yingjie Wang <1075151112@qq.com>
---
Validation of this revision:
- Built drivers/scsi/st.o with x86_64 and i386 defconfig, CHR_DEV_ST=y,
  HZ=1000 and W=1 (GCC 13.3). Both builds needed
  -Wno-error=format-truncation for an existing create_one_cdev() warning,
  also seen when compiling the base st.c with the same headers.
- Host-side checks of the extracted fixed arithmetic covered both timeout
  selectors, zero/default values, range rejection and erase saturation,
  with modeled 32/64-bit limits and seven HZ values from 12 to 12287.
  These are not device runtime tests. This revision has not been
  boot-tested.

 drivers/scsi/st.c | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index e9d41e3cc2dd3..fccb83e75a66c 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -172,6 +172,8 @@ static int debugging = DEBUG;
 
 #define ST_TIMEOUT (900 * HZ)
 #define ST_LONG_TIMEOUT (14000 * HZ)
+/* Fit the signed timeout arguments and the jiffies interval. */
+#define ST_MAX_TIMEOUT min_t(unsigned long, INT_MAX, MAX_JIFFY_OFFSET)
 
 /* Remove mode bits and auto-rewind bit (7) */
 #define TAPE_NR(x) ( ((iminor(x) & ~255) >> (ST_NBR_MODE_BITS + 1)) | \
@@ -2306,6 +2308,7 @@ static void st_log_options(struct scsi_tape * STp, struct st_modedef * STm)
 
 static int st_set_options(struct scsi_tape *STp, long options)
 {
+	unsigned int seconds;
 	int value;
 	long code;
 	struct st_modedef *STm;
@@ -2403,15 +2406,18 @@ static int st_set_options(struct scsi_tape *STp, long options)
 		}
 	} else if (code == MT_ST_TIMEOUTS) {
 		value = (options & ~MT_ST_OPTIONS);
+		seconds = value & ~MT_ST_SET_LONG_TIMEOUT;
+		if (seconds > ST_MAX_TIMEOUT / HZ)
+			return -EINVAL;
 		if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
-			STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
-			DEBC_printk(STp, "Long timeout set to %d seconds.\n",
-				    (value & ~MT_ST_SET_LONG_TIMEOUT));
+			STp->long_timeout = seconds * HZ;
+			DEBC_printk(STp, "Long timeout set to %u seconds.\n",
+				    seconds);
 		} else {
 			blk_queue_rq_timeout(STp->device->request_queue,
-					     value * HZ);
-			DEBC_printk(STp, "Normal timeout set to %d seconds.\n",
-				    value);
+					     seconds * HZ);
+			DEBC_printk(STp, "Normal timeout set to %u seconds.\n",
+				    seconds);
 		}
 	} else if (code == MT_ST_SET_CLN) {
 		value = (options & ~MT_ST_OPTIONS) & 0xff;
@@ -2942,7 +2948,8 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
 			timeout = STp->device->request_queue->rq_timeout;
 		}
 		else
-			timeout = STp->long_timeout * 8;
+			timeout = min_t(u64, (u64)STp->long_timeout * 8,
+					ST_MAX_TIMEOUT);
 
 		DEBC_printk(STp, "Erasing tape.\n");
 		break;

base-commit: 3650bb41391b51d9dcf87b0480ecafeb1526252f


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-10-26 15:16 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-26 15:16 [PATCH] scsi: st: Prevent timeout arithmetic overflow Yingjie Wang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®