From: Bartosz Golaszewski Date: Fri, 3 Mar 2023 16:23:38 +0000 (+0100) Subject: core: sanitize the output values in gpiod_line_config_set_output_values() X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=20c83a55b40da8a085bc2874724a4270b79cdbe0;p=qemu-gpiodev%2Flibgpiod.git core: sanitize the output values in gpiod_line_config_set_output_values() We check the output values for invalid ones in gpiod_line_settings_set_output_value() but in gpiod_line_config_set_output_values() we just accept all indiscriminately. Factor out the common checking code into a helper function, use it in both functions and add a relevant test case. Signed-off-by: Bartosz Golaszewski --- diff --git a/lib/internal.c b/lib/internal.c index d70e247..9c88e66 100644 --- a/lib/internal.c +++ b/lib/internal.c @@ -105,6 +105,22 @@ int gpiod_poll_fd(int fd, int64_t timeout_ns) return 1; } +int gpiod_set_output_value(enum gpiod_line_value in, enum gpiod_line_value *out) +{ + switch (in) { + case GPIOD_LINE_VALUE_INACTIVE: + case GPIOD_LINE_VALUE_ACTIVE: + *out = in; + break; + default: + *out = GPIOD_LINE_VALUE_INACTIVE; + errno = EINVAL; + return -1; + } + + return 0; +} + void gpiod_line_mask_zero(uint64_t *mask) { *mask = 0ULL; diff --git a/lib/internal.h b/lib/internal.h index 6646647..1988322 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -35,6 +35,8 @@ gpiod_info_event_from_uapi(struct gpio_v2_line_info_changed *uapi_evt); struct gpiod_info_event *gpiod_info_event_read_fd(int fd); int gpiod_poll_fd(int fd, int64_t timeout); +int gpiod_set_output_value(enum gpiod_line_value in, + enum gpiod_line_value *out); void gpiod_line_mask_zero(uint64_t *mask); void gpiod_line_mask_fill(uint64_t *mask); diff --git a/lib/line-config.c b/lib/line-config.c index fef62de..2b2c0ec 100644 --- a/lib/line-config.c +++ b/lib/line-config.c @@ -181,12 +181,23 @@ gpiod_line_config_set_output_values(struct gpiod_line_config *config, const enum gpiod_line_value *values, size_t num_values) { + size_t i; + int ret; + if (num_values > LINES_MAX) { errno = EINVAL; return -1; } - memcpy(config->output_values, values, num_values * sizeof(*values)); + for (i = 0; i < num_values; i++) { + ret = gpiod_set_output_value(values[i], + &config->output_values[i]); + if (ret) { + config->num_output_values = 0; + return ret; + } + } + config->num_output_values = num_values; return 0; diff --git a/lib/line-settings.c b/lib/line-settings.c index 67f3e2d..e54353f 100644 --- a/lib/line-settings.c +++ b/lib/line-settings.c @@ -254,18 +254,7 @@ gpiod_line_settings_set_output_value(struct gpiod_line_settings *settings, { assert(settings); - switch (value) { - case GPIOD_LINE_VALUE_INACTIVE: - case GPIOD_LINE_VALUE_ACTIVE: - settings->output_value = value; - break; - default: - settings->output_value = GPIOD_LINE_VALUE_INACTIVE; - errno = EINVAL; - return -1; - } - - return 0; + return gpiod_set_output_value(value, &settings->output_value); } GPIOD_API enum gpiod_line_value diff --git a/tests/tests-line-config.c b/tests/tests-line-config.c index 446cccb..bbc423a 100644 --- a/tests/tests-line-config.c +++ b/tests/tests-line-config.c @@ -347,3 +347,21 @@ GPIOD_TEST_CASE(read_back_global_output_values) g_assert_cmpint(gpiod_line_settings_get_output_value(retrieved), ==, GPIOD_LINE_VALUE_INACTIVE); } + +GPIOD_TEST_CASE(set_output_values_invalid_value) +{ + static const enum gpiod_line_value values[] = { + GPIOD_LINE_VALUE_ACTIVE, + GPIOD_LINE_VALUE_INACTIVE, + 999, + GPIOD_LINE_VALUE_INACTIVE, + }; + + g_autoptr(struct_gpiod_line_config) config = NULL; + + config = gpiod_test_create_line_config_or_fail(); + + g_assert_cmpint(gpiod_line_config_set_output_values(config, values, 4), + ==, -1); + gpiod_test_expect_errno(EINVAL); +}