diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 4c62c597c7be..ea810673b74d 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1619,7 +1619,31 @@ sg_remove_device(struct device *cl_dev) kref_put(&sdp->d_ref, sg_device_destroy); } -module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR); +// This range is enforced, as the size of a scatter-gather list element +// is constrained to the interval [PAGE_SIZE, SG_SCATTER_SZ]. +static inline unsigned int check_scatter_elem_sz_range(int n) +{ + unsigned int size = min(n, SG_SCATTER_SZ); + size = max(PAGE_SIZE, size); + return size; +} +// This routine validates the scatter_elem_sz parameter when it is +// modified by a userspace process via its sysfs file entry. +static int scatter_elem_sz_set(const char *val, const struct kernel_param *kp) +{ + int n = 0, ret; + + ret = kstrtoint(val, 10, &n); + if (ret != 0 || check_scatter_elem_sz_range(n) != n) + return -EINVAL; + return param_set_int(val, kp); +} + +static const struct kernel_param_ops scatter_elem_sz_ops = { + .set = scatter_elem_sz_set, + .get = param_get_int, +}; +module_param_cb(scatter_elem_sz, &scatter_elem_sz_ops, &scatter_elem_sz, 0664); module_param_named(def_reserved_size, def_reserved_size, int, S_IRUGO | S_IWUSR); module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR); @@ -1669,10 +1693,15 @@ init_sg(void) { int rc; - if (scatter_elem_sz < PAGE_SIZE) { - scatter_elem_sz = PAGE_SIZE; - scatter_elem_sz_prev = scatter_elem_sz; - } + // This performs validation on the scatter_elem_sz value supplied + // upon module initialization. + unsigned int cond = check_scatter_elem_sz_range(scatter_elem_sz); + + if (cond != scatter_elem_sz) { + scatter_elem_sz = cond; + scatter_elem_sz_prev = scatter_elem_sz; + } + if (def_reserved_size >= 0) sg_big_buff = def_reserved_size; else