mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
scsi: handle out-of-range SG_SET_TIMEOUT values
SG_SET_TIMEOUT accepts a signed int in USER_HZ units. The sg character device rejects negative values and limits positive values so the converted timeout fits its destination field. The block SCSI and BSG paths instead pass the value to clock_t_to_jiffies(), which accepts an unsigned long, and store the result in an unsigned int. Negative values are converted into large unsigned timeouts. On 64-bit systems, large positive values can also exceed UINT_MAX after conversion and are truncated on assignment. With HZ=1000 and USER_HZ=100, for example, 429496730 clock ticks become 4294967300 jiffies and are stored as 4 jiffies. On 32-bit systems, an overflowing conversion becomes ULONG_MAX, which is an unsafe relative interval for the block timer comparisons. Reject negative values with -EIO, matching drivers/scsi/sg.c. Saturate the converted value at the smaller of the destination field limit and MAX_JIFFY_OFFSET. This preserves successful ioctl behavior while avoiding both narrowing wraparound and an unsafe 32-bit timer interval. The block SCSI behavior predates Git history. BSG has exposed the same behavior since it was introduced. Fixes:1da177e4c3("Linux-2.6.12-rc2") Fixes:3d6392cfbd("bsg: support for full generic block layer SG v3") Cc: stable@vger.kernel.org Reported-by: Bart Van Assche <bvanassche@acm.org> Link: https://lore.kernel.org/r/9321a59c-c560-4742-8b71-5b0ec1f30c2f@acm.org Signed-off-by: Yingjie Wang <x-professor@outlook.com> Link: https://patch.msgid.link/20261022025508.294713-1-x-professor@outlook.com Signed-off-by: Martin K. Petersen (Oracle) <mkp@kernel.org>
This commit is contained in:
parent
5b0d568e18
commit
9a6cb1da4f
|
|
@ -132,7 +132,10 @@ static long bsg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
case SG_SET_TIMEOUT:
|
||||
if (get_user(val, intp))
|
||||
return -EFAULT;
|
||||
bd->timeout = clock_t_to_jiffies(val);
|
||||
if (val < 0)
|
||||
return -EIO;
|
||||
bd->timeout = min(clock_t_to_jiffies(val),
|
||||
min(UINT_MAX, MAX_JIFFY_OFFSET));
|
||||
return 0;
|
||||
case SG_GET_TIMEOUT:
|
||||
return jiffies_to_clock_t(bd->timeout);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/blkdev.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
|
|
@ -196,10 +197,14 @@ static int sg_set_timeout(struct scsi_device *sdev, int __user *p)
|
|||
{
|
||||
int timeout, err = get_user(timeout, p);
|
||||
|
||||
if (!err)
|
||||
sdev->sg_timeout = clock_t_to_jiffies(timeout);
|
||||
if (err)
|
||||
return err;
|
||||
if (timeout < 0)
|
||||
return -EIO;
|
||||
|
||||
return err;
|
||||
sdev->sg_timeout = min(clock_t_to_jiffies(timeout),
|
||||
min(UINT_MAX, MAX_JIFFY_OFFSET));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sg_get_reserved_size(struct scsi_device *sdev, int __user *p)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user