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>
This commit is contained in:
Chris Wilson
2014-07-17 16:14:16 +01:00
parent bcd09ff6eb
commit 3140d72826

View File

@@ -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;