Skip to content

Commit

Permalink
gpiolib: cdev: Disallow reconfiguration without direction (uAPI v1)
Browse files Browse the repository at this point in the history
[ Upstream commit 9919cce ]

linehandle_set_config() behaves badly when direction is not set.
The configuration validation is borrowed from linehandle_create(), where,
to verify the intent of the user, the direction must be set to in order
to effect a change to the electrical configuration of a line. But, when
applied to reconfiguration, that validation does not allow for the unset
direction case, making it possible to clear flags set previously without
specifying the line direction.

Adding to the inconsistency, those changes are not immediately applied by
linehandle_set_config(), but will take effect when the line value is next
get or set.

For example, by requesting a configuration with no flags set, an output
line with GPIOHANDLE_REQUEST_ACTIVE_LOW and GPIOHANDLE_REQUEST_OPEN_DRAIN
requested could have those flags cleared, inverting the sense of the line
and changing the line drive to push-pull on the next line value set.

Ensure the intent of the user by disallowing configurations which do not
have direction set, returning an error to userspace to indicate that the
configuration is invalid.

And, for clarity, use lflags, a local copy of gcnf.flags, throughout when
dealing with the requested flags, rather than a mixture of both.

Fixes: e588bb1 ("gpio: add new SET_CONFIG ioctl() to gpio chardev")
Signed-off-by: Kent Gibson <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Bartosz Golaszewski <[email protected]>
Signed-off-by: Sasha Levin <[email protected]>
  • Loading branch information
warthog618 authored and gregkh committed Jul 5, 2024
1 parent e44a83b commit 38ce307
Showing 1 changed file with 10 additions and 6 deletions.
16 changes: 10 additions & 6 deletions drivers/gpio/gpiolib-cdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ struct linehandle_state {
GPIOHANDLE_REQUEST_OPEN_DRAIN | \
GPIOHANDLE_REQUEST_OPEN_SOURCE)

#define GPIOHANDLE_REQUEST_DIRECTION_FLAGS \
(GPIOHANDLE_REQUEST_INPUT | \
GPIOHANDLE_REQUEST_OUTPUT)

static int linehandle_validate_flags(u32 flags)
{
/* Return an error if an unknown flag is set */
Expand Down Expand Up @@ -163,21 +167,21 @@ static long linehandle_set_config(struct linehandle_state *lh,
if (ret)
return ret;

/* Lines must be reconfigured explicitly as input or output. */
if (!(lflags & GPIOHANDLE_REQUEST_DIRECTION_FLAGS))
return -EINVAL;

for (i = 0; i < lh->num_descs; i++) {
desc = lh->descs[i];
linehandle_flags_to_desc_flags(gcnf.flags, &desc->flags);
linehandle_flags_to_desc_flags(lflags, &desc->flags);

/*
* Lines have to be requested explicitly for input
* or output, else the line will be treated "as is".
*/
if (lflags & GPIOHANDLE_REQUEST_OUTPUT) {
int val = !!gcnf.default_values[i];

ret = gpiod_direction_output(desc, val);
if (ret)
return ret;
} else if (lflags & GPIOHANDLE_REQUEST_INPUT) {
} else {
ret = gpiod_direction_input(desc);
if (ret)
return ret;
Expand Down

0 comments on commit 38ce307

Please sign in to comment.