core: sanitize the output values in gpiod_line_config_set_output_values()
authorBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Fri, 3 Mar 2023 16:23:38 +0000 (17:23 +0100)
committerBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Fri, 3 Mar 2023 16:23:38 +0000 (17:23 +0100)
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 <bartosz.golaszewski@linaro.org>
lib/internal.c
lib/internal.h
lib/line-config.c
lib/line-settings.c
tests/tests-line-config.c

index d70e247cd93d89fe6b1b6102d61349e085f4f3a5..9c88e66f40ce40dce295453b0fc00b0351d80674 100644 (file)
@@ -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;
index 6646647bf82721e36d24ab6a82f3d360fd5e4024..19883227d1a60af9bdc92fafbc654960df8013b4 100644 (file)
@@ -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);
index fef62deec109d5f78cba13f6e569b28e20966586..2b2c0ec67b48d33ea0381d4170146d95525f7921 100644 (file)
@@ -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;
index 67f3e2dd6848cb44caa9479f23586a2acea04f0e..e54353f5c6cdc93f08da5f062489158d3b078ad1 100644 (file)
@@ -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
index 446cccb6ca509d22a96434fcf0f113a403d3aba5..bbc423a8347e9f29ba48ea13e5eda8ffc7d08059 100644 (file)
@@ -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);
+}