diff options
author | Corubba Smith <corubba@gmx.de> | 2025-03-12 15:55:16 +0100 |
---|---|---|
committer | Florian Westphal <fw@strlen.de> | 2025-03-12 16:22:34 +0100 |
commit | a6229ae0bbeb8fcb7f9ee5d1dddaae98c0c71176 (patch) | |
tree | 970bc9a2610b3a9091e8d127fbee16d05bc526c5 | |
parent | 0ac16e540283e2fa6c89292a416448c944bd3483 (diff) |
ulogd: improve integer option parsing
The `value` union member in `struct config_entry` is declared as `int`
since basically the beginning in e07722e46001 ("config stuff added").
The parsing was switched from the original `atoi()` in 015849995f7f
("Fix hexadecimal parsing in config file") to `strtoul()`.
Switch the function for parsing to the signed `strtol()` variant since
the result will be stored in a signed int, and it makes sense to support
negative numbers. Detect when `strtol()` does not properly consume the
whole argument and return a new format error. Also check the numerical
value to make sure the signed int does not overflow, in which case
a new range error is returned.
Unfortunately there is no `strtoi()` which would do the proper range
check itself, so the intermediate `long` and range-check for `int` is
required. I also considered changing the `value` union member from
`int` to `long`, which would make it possible to use the parsed value
as-is. But since this is part of the api towards plugins (including
third party) such a potentially breaking change felt unwarranted. This
also means that still only 16bit integer values are *guaranteed* to
work, although most platforms use bigger widths for int.
Signed-off-by: Corubba Smith <corubba@gmx.de>
Signed-off-by: Florian Westphal <fw@strlen.de>
-rw-r--r-- | include/ulogd/conffile.h | 2 | ||||
-rw-r--r-- | src/conffile.c | 17 | ||||
-rw-r--r-- | src/ulogd.c | 10 |
3 files changed, 28 insertions, 1 deletions
diff --git a/include/ulogd/conffile.h b/include/ulogd/conffile.h index 1f3d563..fb54dea 100644 --- a/include/ulogd/conffile.h +++ b/include/ulogd/conffile.h @@ -19,6 +19,8 @@ enum { ERRUNKN, /* unknown config key */ ERRSECTION, /* section not found */ ERRTOOLONG, /* string too long */ + ERRINTFORMAT, /* integer format is invalid */ + ERRINTRANGE, /* integer value is out of range */ }; /* maximum line length of config file entries */ diff --git a/src/conffile.c b/src/conffile.c index cc5552c..955956a 100644 --- a/src/conffile.c +++ b/src/conffile.c @@ -17,6 +17,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <limits.h> #include <ulogd/ulogd.h> #include <ulogd/common.h> #include <ulogd/conffile.h> @@ -227,7 +228,21 @@ int config_parse_file(const char *section, struct config_keyset *kset) } break; case CONFIG_TYPE_INT: - ce->u.value = strtoul(args, NULL, 0); + errno = 0; + char *endptr = NULL; + long parsed = strtol(args, &endptr, 0); + if (endptr == args || *endptr != '\0') { + config_errce = ce; + err = -ERRINTFORMAT; + goto cpf_error; + } + if (errno == ERANGE || + parsed < INT_MIN || parsed > INT_MAX) { + config_errce = ce; + err = -ERRINTRANGE; + goto cpf_error; + } + ce->u.value = (int)parsed; break; case CONFIG_TYPE_CALLBACK: (ce->u.parser)(args); diff --git a/src/ulogd.c b/src/ulogd.c index 7260aeb..c844767 100644 --- a/src/ulogd.c +++ b/src/ulogd.c @@ -293,6 +293,16 @@ int ulogd_parse_configfile(const char *section, struct config_keyset *ce) else ulogd_log(ULOGD_ERROR, "string value is too long\n"); break; + case -ERRINTFORMAT: + ulogd_log(ULOGD_ERROR, + "integer has invalid format for key \"%s\"\n", + config_errce->key); + break; + case -ERRINTRANGE: + ulogd_log(ULOGD_ERROR, + "integer is out of range for key \"%s\"\n", + config_errce->key); + break; } return ULOGD_IRET_ERR; |