cpucontrol: Be more strict with input validation

Avoid truncating 32-bit values.  This would have saved me a bit of time
when I was looking at a cpuid leaf on my system and typed 0x80000001f
instead of 0x8000001f.

Reviewed by:	kib
MFC after:	2 weeks
Differential Revision:	https://reviews.freebsd.org/D54919
This commit is contained in:
Mark Johnston
2026-01-28 16:31:41 +00:00
parent 2ea85a622b
commit 59bbb62b60
+21 -4
View File
@@ -36,7 +36,9 @@
#include <errno.h> #include <errno.h>
#include <dirent.h> #include <dirent.h>
#include <fcntl.h> #include <fcntl.h>
#include <inttypes.h>
#include <paths.h> #include <paths.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -112,6 +114,21 @@ usage(void)
exit(EX_USAGE); exit(EX_USAGE);
} }
static uint32_t
strtouint32(const char *str, char **endptr, int base)
{
uintmax_t val;
errno = 0;
val = strtoumax(str, endptr, base);
if (*str == '\0' || errno == ERANGE || val > UINT32_MAX) {
WARNX(0, "invalid operand: %s", str);
exit(EX_USAGE);
/* NOTREACHED */
}
return ((uint32_t)val);
}
static int static int
do_cpuid(const char *cmdarg, const char *dev) do_cpuid(const char *cmdarg, const char *dev)
{ {
@@ -123,7 +140,7 @@ do_cpuid(const char *cmdarg, const char *dev)
assert(cmdarg != NULL); assert(cmdarg != NULL);
assert(dev != NULL); assert(dev != NULL);
level = strtoul(cmdarg, &endptr, 16); level = strtouint32(cmdarg, &endptr, 16);
if (*cmdarg == '\0' || *endptr != '\0') { if (*cmdarg == '\0' || *endptr != '\0') {
WARNX(0, "incorrect operand: %s", cmdarg); WARNX(0, "incorrect operand: %s", cmdarg);
usage(); usage();
@@ -162,7 +179,7 @@ do_cpuid_count(const char *cmdarg, const char *dev)
assert(cmdarg != NULL); assert(cmdarg != NULL);
assert(dev != NULL); assert(dev != NULL);
level = strtoul(cmdarg, &endptr, 16); level = strtouint32(cmdarg, &endptr, 16);
if (*cmdarg == '\0' || *endptr == '\0') { if (*cmdarg == '\0' || *endptr == '\0') {
WARNX(0, "incorrect or missing operand: %s", cmdarg); WARNX(0, "incorrect or missing operand: %s", cmdarg);
usage(); usage();
@@ -172,7 +189,7 @@ do_cpuid_count(const char *cmdarg, const char *dev)
cmdarg1 = strstr(endptr, ","); cmdarg1 = strstr(endptr, ",");
/* ... and skip past it */ /* ... and skip past it */
cmdarg1 += 1; cmdarg1 += 1;
level_type = strtoul(cmdarg1, &endptr1, 16); level_type = strtouint32(cmdarg1, &endptr1, 16);
if (*cmdarg1 == '\0' || *endptr1 != '\0') { if (*cmdarg1 == '\0' || *endptr1 != '\0') {
WARNX(0, "incorrect or missing operand: %s", cmdarg); WARNX(0, "incorrect or missing operand: %s", cmdarg);
usage(); usage();
@@ -228,7 +245,7 @@ do_msr(const char *cmdarg, const char *dev)
/* /*
* Parse command string. * Parse command string.
*/ */
msr = strtoul(cmdarg, &endptr, 16); msr = strtouint32(cmdarg, &endptr, 16);
switch (*endptr) { switch (*endptr) {
case '\0': case '\0':
op = OP_READ; op = OP_READ;