mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 02:24:24 +02:00
selftests/powerpc: Parse long/unsigned long value safely
Often a file is expected to hold an integral value. Existing functions will use a C stdlib function like atoi or strtol to parse the file. These operations are error prone, with complicated error conditions (atoi returns 0 if not a number, and is undefined behaviour if not in range. strtol returns 0 if not a number, and LONG_MIN/MAX if not in range + sets errno to ERANGE). Signed-off-by: Benjamin Gray <bgray@linux.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20230203003947.38033-4-bgray@linux.ibm.com
This commit is contained in:
parent
121d340be9
commit
d1bc05b7bf
|
|
@ -33,6 +33,13 @@ void *get_auxv_entry(int type);
|
|||
|
||||
int pick_online_cpu(void);
|
||||
|
||||
int parse_intmax(const char *buffer, size_t count, intmax_t *result, int base);
|
||||
int parse_uintmax(const char *buffer, size_t count, uintmax_t *result, int base);
|
||||
int parse_int(const char *buffer, size_t count, int *result, int base);
|
||||
int parse_uint(const char *buffer, size_t count, unsigned int *result, int base);
|
||||
int parse_long(const char *buffer, size_t count, long *result, int base);
|
||||
int parse_ulong(const char *buffer, size_t count, unsigned long *result, int base);
|
||||
|
||||
int read_file(const char *path, char *buf, size_t count, size_t *len);
|
||||
int write_file(const char *path, const char *buf, size_t count);
|
||||
int read_debugfs_file(const char *debugfs_file, char *buf, size_t count);
|
||||
|
|
|
|||
|
|
@ -192,7 +192,6 @@ bool require_paranoia_below(int level)
|
|||
{
|
||||
int err;
|
||||
long current;
|
||||
char *end;
|
||||
char buf[16] = {0};
|
||||
|
||||
err = read_file(PARANOID_PATH, buf, sizeof(buf) - 1, NULL);
|
||||
|
|
@ -201,9 +200,8 @@ bool require_paranoia_below(int level)
|
|||
return false;
|
||||
}
|
||||
|
||||
current = strtol(buf, &end, 10);
|
||||
|
||||
if (end == buf) {
|
||||
err = parse_long(buf, sizeof(buf), ¤t, 10);
|
||||
if (err) {
|
||||
printf("Couldn't parse " PARANOID_PATH "?\n");
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
#include <elf.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <link.h>
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
|
|
@ -123,6 +125,126 @@ int write_debugfs_file(const char *subpath, const char *buf, size_t count)
|
|||
return write_file(path, buf, count);
|
||||
}
|
||||
|
||||
static int validate_int_parse(const char *buffer, size_t count, char *end)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
/* Require at least one digit */
|
||||
if (end == buffer) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Require all remaining characters be whitespace-ish */
|
||||
for (; end < buffer + count; end++) {
|
||||
if (*end == '\0')
|
||||
break;
|
||||
|
||||
if (*end != ' ' && *end != '\n') {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
errno = -err;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int parse_bounded_int(const char *buffer, size_t count, intmax_t *result,
|
||||
int base, intmax_t min, intmax_t max)
|
||||
{
|
||||
int err;
|
||||
char *end;
|
||||
|
||||
errno = 0;
|
||||
*result = strtoimax(buffer, &end, base);
|
||||
|
||||
if (errno)
|
||||
return -errno;
|
||||
|
||||
err = validate_int_parse(buffer, count, end);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (*result < min || *result > max)
|
||||
err = -EOVERFLOW;
|
||||
|
||||
out:
|
||||
errno = -err;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int parse_bounded_uint(const char *buffer, size_t count, uintmax_t *result,
|
||||
int base, uintmax_t max)
|
||||
{
|
||||
int err = 0;
|
||||
char *end;
|
||||
|
||||
errno = 0;
|
||||
*result = strtoumax(buffer, &end, base);
|
||||
|
||||
if (errno)
|
||||
return -errno;
|
||||
|
||||
err = validate_int_parse(buffer, count, end);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (*result > max)
|
||||
err = -EOVERFLOW;
|
||||
|
||||
out:
|
||||
errno = -err;
|
||||
return err;
|
||||
}
|
||||
|
||||
int parse_intmax(const char *buffer, size_t count, intmax_t *result, int base)
|
||||
{
|
||||
return parse_bounded_int(buffer, count, result, base, INTMAX_MIN, INTMAX_MAX);
|
||||
}
|
||||
|
||||
int parse_uintmax(const char *buffer, size_t count, uintmax_t *result, int base)
|
||||
{
|
||||
return parse_bounded_uint(buffer, count, result, base, UINTMAX_MAX);
|
||||
}
|
||||
|
||||
int parse_int(const char *buffer, size_t count, int *result, int base)
|
||||
{
|
||||
intmax_t parsed;
|
||||
int err = parse_bounded_int(buffer, count, &parsed, base, INT_MIN, INT_MAX);
|
||||
|
||||
*result = parsed;
|
||||
return err;
|
||||
}
|
||||
|
||||
int parse_uint(const char *buffer, size_t count, unsigned int *result, int base)
|
||||
{
|
||||
uintmax_t parsed;
|
||||
int err = parse_bounded_uint(buffer, count, &parsed, base, UINT_MAX);
|
||||
|
||||
*result = parsed;
|
||||
return err;
|
||||
}
|
||||
|
||||
int parse_long(const char *buffer, size_t count, long *result, int base)
|
||||
{
|
||||
intmax_t parsed;
|
||||
int err = parse_bounded_int(buffer, count, &parsed, base, LONG_MIN, LONG_MAX);
|
||||
|
||||
*result = parsed;
|
||||
return err;
|
||||
}
|
||||
|
||||
int parse_ulong(const char *buffer, size_t count, unsigned long *result, int base)
|
||||
{
|
||||
uintmax_t parsed;
|
||||
int err = parse_bounded_uint(buffer, count, &parsed, base, ULONG_MAX);
|
||||
|
||||
*result = parsed;
|
||||
return err;
|
||||
}
|
||||
|
||||
void *find_auxv_entry(int type, char *auxv)
|
||||
{
|
||||
ElfW(auxv_t) *p;
|
||||
|
|
@ -224,9 +346,7 @@ int read_debugfs_int(const char *debugfs_file, int *result)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
*result = atoi(value);
|
||||
|
||||
return 0;
|
||||
return parse_int(value, sizeof(value), result, 10);
|
||||
}
|
||||
|
||||
int write_debugfs_int(const char *debugfs_file, int result)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user