diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2014-07-17 16:14:16 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2014-07-17 16:14:16 +0100 |
commit | 3140d72826b5227f7f7ac9a428faa4bcfd4b377b (patch) | |
tree | 085f8745071adfbd1d4b05fc1a6d7bc22efdf8b9 | |
parent | bcd09ff6eb76bc4df046ece4da29b1455fed8dff (diff) |
backlight: Prevent dereference of potential NULL argv
Adam Sampson spotted that
"It's possible (but not very sensible) to exec a program with an empty
argument list, so argv[0] is not necessarily a valid pointer. For
example:
$ cat exec0.c
int main(int argc, char *argv[]) {
char *empty[1] = { NULL };
execvp(argv[1], empty);
perror("execvp");
return 1;
}
$ ./exec0 /usr/libexec/xf86-video-intel-backlight-helper
Usage: (null) <iface>
"
He sensibly suggested that we hardcode the program name to avoid the
NULL dereference. Being the paranoid type, we should also be careful not
to write to any file descriptors outside of our control (i.e. stderr),
so disable the messages unless we are debugging.
Reported-by: Adam Sampson
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | tools/backlight_helper.c | 56 |
1 files changed, 35 insertions, 21 deletions
diff --git a/tools/backlight_helper.c b/tools/backlight_helper.c index 24958ec6..8b2667dc 100644 --- a/tools/backlight_helper.c +++ b/tools/backlight_helper.c @@ -1,43 +1,57 @@ #include <stdio.h> #include <string.h> +#include <stdarg.h> +#include <stdlib.h> #include <fcntl.h> #include <unistd.h> +#include <errno.h> #include <sys/types.h> #include <sys/stat.h> +#define DBG 0 + +#if defined(__GNUC__) && (__GNUC__ > 3) +__attribute__((format(printf, 1, 2), noreturn)) +#endif +static void die(const char *format, ...) +{ + if (DBG) { + va_list args; + + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + } + + exit(1); +} + int main(int argc, char *argv[]) { struct stat st; char buf[1024]; int len, fd; - if (argc != 2) { - fprintf(stderr, "Usage: %s <iface>\n", argv[0]); - return 1; - } + if (argc != 2) + die("Usage: xf86-video-intel-backlight-helper <iface>\n"); + + if (strchr(argv[1], '/') != NULL) + die("Invalid interface '%s': contains '/'\n", argv[1]); + + if (snprintf(buf, sizeof(buf), + "/sys/class/backlight/%s/brightness", + argv[1]) >= sizeof(buf)) + die("Invalid interface '%s': name too long\n", argv[1]); - if (strchr(argv[1], '/') != NULL) { - fprintf(stderr, "Invalid interface name\n"); - return 1; - } - if (snprintf(buf, sizeof(buf), "/sys/class/backlight/%s/brightness", - argv[1]) >= sizeof(buf)) { - fprintf(stderr, "Interface name is too long\n"); - return 1; - } fd = open(buf, O_RDWR); - if (fd < 0 || fstat(fd, &st) || major(st.st_dev)) { - fprintf(stderr, "Cannot access backlight interface '%s'\n", argv[1]); - return 1; - } + if (fd < 0 || fstat(fd, &st) || major(st.st_dev)) + die("Invalid interface '%s': unknown backlight file\n", argv[1]); while (fgets(buf, sizeof(buf), stdin)) { len = strlen(buf); - if (write(fd, buf, len) != len) { - fprintf(stderr, "Failed to update backlight interface '%s'\n", argv[1]); - return 2; - } + if (write(fd, buf, len) != len) + die("Failed to update backlight interface '%s': errno=%d\n", argv[1], errno); } return 0; |