On Tue, Jun 23, 2015 at 5:49 AM, Dan Carpenter <dan.carpenter@xxxxxxxxxx> wrote: > Hello Dan Williams, > > The patch 85af0c1db6d8: "libnvdimm: control (ioctl) messages for > nvdimm_bus and nvdimm devices" from Jun 8, 2015, leads to the > following static checker warning: > > drivers/nvdimm/bus.c:484 __nd_ioctl() > warn: should we be adding 'in_size' of the min_t value? > > drivers/nvdimm/bus.c > 466 /* process an input envelope */ > 467 for (i = 0; i < desc->in_num; i++) { > 468 u32 in_size, copy; > 469 > 470 in_size = nd_cmd_in_size(nvdimm, cmd, desc, i, in_env); > 471 if (in_size == UINT_MAX) { > 472 dev_err(dev, "%s:%s unknown input size cmd: %s field: %d\n", > 473 __func__, dimm_name, cmd_name, i); > 474 return -ENXIO; > 475 } > 476 if (!access_ok(VERIFY_READ, p + in_len, in_size)) > 477 return -EFAULT; > 478 if (in_len < sizeof(in_env)) > 479 copy = min_t(u32, sizeof(in_env) - in_len, in_size); > 480 else > 481 copy = 0; > 482 if (copy && copy_from_user(&in_env[in_len], p + in_len, copy)) > 483 return -EFAULT; > 484 in_len += in_size; > > The warning message is saying that probably this should be: > > in_len += copy; > > I think this is true. On most iterations an invalid "in_size" would be > caught perhaps except on the last iteration. It means "in_len" is > something invalid when we use it below. Except that in_size can't be invalid as it's determined from validating the first fields of the input. If we get in_size's that overflow in_env we're also ok because the implementation is prepared to only need the first 16-bytes of input to determine the total size of the incoming command. > > 485 } > 486 > 487 /* process an output envelope */ > 488 for (i = 0; i < desc->out_num; i++) { > 489 u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i, > 490 (u32 *) in_env, (u32 *) out_env); > 491 u32 copy; > 492 > 493 if (out_size == UINT_MAX) { > 494 dev_dbg(dev, "%s:%s unknown output size cmd: %s field: %d\n", > 495 __func__, dimm_name, cmd_name, i); > 496 return -EFAULT; > 497 } > 498 if (!access_ok(VERIFY_WRITE, p + in_len + out_len, out_size)) > > Most of the time an invalid "in_len" doesn't really matter. Maybe it > could be used to trigger an integer overflow? > > 499 return -EFAULT; > 500 if (out_len < sizeof(out_env)) > 501 copy = min_t(u32, sizeof(out_env) - out_len, out_size); > 502 else > 503 copy = 0; > 504 if (copy && copy_from_user(&out_env[out_len], > 505 p + in_len + out_len, copy)) > 506 return -EFAULT; > 507 out_len += out_size; > 508 } > 509 > 510 buf_len = out_len + in_len; > > > So "buflen" is something invalid. Integer overflow as well? > > 511 if (!access_ok(VERIFY_WRITE, p, sizeof(buf_len))) > ^^^^^^^^^^^^^^^ > > This is shoud be: > > if (!access_ok(VERIFY_WRITE, p, buf_len)) > > These days Linus frowns on anyone using __copy_to/from_user unless they > have benchmark data to prove it matters so do we even need this > access_ok() check? I had missed that copy_{from|to}_user() do access_ok() internally. Will drop. -- To unsubscribe from this list: send the line "unsubscribe kernel-janitors" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html