Skip to content

Commit 31594c5

Browse files
warthog618gregkh
authored andcommitted
gpiolib: cdev: Disallow reconfiguration without direction (uAPI v1)
[ 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]>
1 parent c3b4257 commit 31594c5

File tree

1 file changed

+10
-6
lines changed

1 file changed

+10
-6
lines changed

drivers/gpio/gpiolib-cdev.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ struct linehandle_state {
132132
GPIOHANDLE_REQUEST_OPEN_DRAIN | \
133133
GPIOHANDLE_REQUEST_OPEN_SOURCE)
134134

135+
#define GPIOHANDLE_REQUEST_DIRECTION_FLAGS \
136+
(GPIOHANDLE_REQUEST_INPUT | \
137+
GPIOHANDLE_REQUEST_OUTPUT)
138+
135139
static int linehandle_validate_flags(u32 flags)
136140
{
137141
/* Return an error if an unknown flag is set */
@@ -212,21 +216,21 @@ static long linehandle_set_config(struct linehandle_state *lh,
212216
if (ret)
213217
return ret;
214218

219+
/* Lines must be reconfigured explicitly as input or output. */
220+
if (!(lflags & GPIOHANDLE_REQUEST_DIRECTION_FLAGS))
221+
return -EINVAL;
222+
215223
for (i = 0; i < lh->num_descs; i++) {
216224
desc = lh->descs[i];
217-
linehandle_flags_to_desc_flags(gcnf.flags, &desc->flags);
225+
linehandle_flags_to_desc_flags(lflags, &desc->flags);
218226

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

226230
ret = gpiod_direction_output(desc, val);
227231
if (ret)
228232
return ret;
229-
} else if (lflags & GPIOHANDLE_REQUEST_INPUT) {
233+
} else {
230234
ret = gpiod_direction_input(desc);
231235
if (ret)
232236
return ret;

0 commit comments

Comments
 (0)