Home | History | Annotate | Line # | Download | only in fuzz
preload-snoop.c revision 1.1
      1 /*
      2  * Copyright (c) 2019 Yubico AB. All rights reserved.
      3  * Use of this source code is governed by a BSD-style
      4  * license that can be found in the LICENSE file.
      5  */
      6 
      7 /*
      8  * cc -fPIC -D_GNU_SOURCE -shared -o preload-snoop.so preload-snoop.c
      9  * LD_PRELOAD=$(realpath preload-snoop.so)
     10  */
     11 
     12 #include <sys/types.h>
     13 #include <sys/stat.h>
     14 
     15 #include <dlfcn.h>
     16 #include <err.h>
     17 #include <errno.h>
     18 #include <fcntl.h>
     19 #include <limits.h>
     20 #include <stdarg.h>
     21 #include <stdio.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 #include <unistd.h>
     25 
     26 #define SNOOP_DEV_PREFIX	"/dev/hidraw"
     27 
     28 struct fd_tuple {
     29 	int snoop_in;
     30 	int snoop_out;
     31 	int real_dev;
     32 };
     33 
     34 static struct fd_tuple  *fd_tuple;
     35 static int              (*open_f)(const char *, int, mode_t);
     36 static int              (*close_f)(int);
     37 static ssize_t          (*read_f)(int, void *, size_t);
     38 static ssize_t          (*write_f)(int, const void *, size_t);
     39 
     40 static int
     41 get_fd(const char *hid_path, const char *suffix)
     42 {
     43 	char	*s = NULL;
     44 	char	 path[PATH_MAX];
     45 	int	 fd;
     46 	int	 r;
     47 
     48 	if ((s = strdup(hid_path)) == NULL) {
     49 		warnx("%s: strdup", __func__);
     50 		return (-1);
     51 	}
     52 
     53 	for (size_t i = 0; i < strlen(s); i++)
     54 		if (s[i] == '/')
     55 			s[i] = '_';
     56 
     57 	if ((r = snprintf(path, sizeof(path), "%s-%s", s, suffix)) < 0 ||
     58 	    (size_t)r >= sizeof(path)) {
     59 		warnx("%s: snprintf", __func__);
     60 		free(s);
     61 		return (-1);
     62 	}
     63 
     64 	free(s);
     65 	s = NULL;
     66 
     67 	if ((fd = open_f(path, O_CREAT | O_WRONLY, 0644)) < 0) {
     68 		warn("%s: open", __func__);
     69 		return (-1);
     70 	}
     71 
     72 	return (fd);
     73 }
     74 
     75 int
     76 open(const char *path, int flags, ...)
     77 {
     78 	va_list	ap;
     79 	mode_t	mode;
     80 
     81 	va_start(ap, flags);
     82 	mode = va_arg(ap, mode_t);
     83 	va_end(ap);
     84 
     85 	if (open_f == NULL) {
     86 		open_f = dlsym(RTLD_NEXT, "open");
     87 		if (open_f == NULL) {
     88 			warnx("%s: dlsym", __func__);
     89 			errno = EACCES;
     90 			return (-1);
     91 		}
     92 	}
     93 
     94 	if (strncmp(path, SNOOP_DEV_PREFIX, strlen(SNOOP_DEV_PREFIX)) != 0)
     95 		return (open_f(path, flags, mode));
     96 
     97 	if (fd_tuple != NULL) {
     98 		warnx("%s: fd_tuple != NULL", __func__);
     99 		errno = EACCES;
    100 		return (-1);
    101 	}
    102 
    103 	if ((fd_tuple = calloc(1, sizeof(*fd_tuple))) == NULL) {
    104 		warn("%s: calloc", __func__);
    105 		errno = ENOMEM;
    106 		return (-1);
    107 	}
    108 
    109 	fd_tuple->snoop_in = -1;
    110 	fd_tuple->snoop_out = -1;
    111 	fd_tuple->real_dev = -1;
    112 
    113 	if ((fd_tuple->snoop_in = get_fd(path, "in")) < 0 ||
    114 	    (fd_tuple->snoop_out = get_fd(path, "out")) < 0 ||
    115 	    (fd_tuple->real_dev = open_f(path, flags, mode)) < 0) {
    116 		warn("%s: get_fd/open", __func__);
    117 		goto fail;
    118 	}
    119 
    120 	return (fd_tuple->real_dev);
    121 fail:
    122 	if (fd_tuple->snoop_in != -1)
    123 		close(fd_tuple->snoop_in);
    124 	if (fd_tuple->snoop_out != -1)
    125 		close(fd_tuple->snoop_out);
    126 	if (fd_tuple->real_dev != -1)
    127 		close(fd_tuple->real_dev);
    128 
    129 	free(fd_tuple);
    130 	fd_tuple = NULL;
    131 
    132 	errno = EACCES;
    133 
    134 	return (-1);
    135 }
    136 
    137 int
    138 close(int fd)
    139 {
    140 	if (close_f == NULL) {
    141 		close_f = dlsym(RTLD_NEXT, "close");
    142 		if (close_f == NULL) {
    143 			warnx("%s: dlsym", __func__);
    144 			errno = EBADF;
    145 			return (-1);
    146 		}
    147 	}
    148 
    149 	if (fd_tuple == NULL || fd_tuple->real_dev != fd)
    150 		return (close_f(fd));
    151 
    152 	close_f(fd_tuple->snoop_in);
    153 	close_f(fd_tuple->snoop_out);
    154 	close_f(fd_tuple->real_dev);
    155 
    156 	free(fd_tuple);
    157 	fd_tuple = NULL;
    158 
    159 	return (0);
    160 }
    161 
    162 ssize_t
    163 read(int fd, void *buf, size_t nbytes)
    164 {
    165 	ssize_t n;
    166 
    167 	if (read_f == NULL) {
    168 		read_f = dlsym(RTLD_NEXT, "read");
    169 		if (read_f == NULL) {
    170 			warnx("%s: dlsym", __func__);
    171 			errno = EBADF;
    172 			return (-1);
    173 		}
    174 	}
    175 
    176 	if (write_f == NULL) {
    177 		write_f = dlsym(RTLD_NEXT, "write");
    178 		if (write_f == NULL) {
    179 			warnx("%s: dlsym", __func__);
    180 			errno = EBADF;
    181 			return (-1);
    182 		}
    183 	}
    184 
    185 	if (fd_tuple == NULL || fd_tuple->real_dev != fd)
    186 		return (read_f(fd, buf, nbytes));
    187 
    188 	if ((n = read_f(fd, buf, nbytes)) < 0 ||
    189 	    write_f(fd_tuple->snoop_in, buf, n) != n)
    190 		return (-1);
    191 
    192 	return (n);
    193 }
    194 
    195 ssize_t
    196 write(int fd, const void *buf, size_t nbytes)
    197 {
    198 	ssize_t n;
    199 
    200 	if (write_f == NULL) {
    201 		write_f = dlsym(RTLD_NEXT, "write");
    202 		if (write_f == NULL) {
    203 			warnx("%s: dlsym", __func__);
    204 			errno = EBADF;
    205 			return (-1);
    206 		}
    207 	}
    208 
    209 	if (fd_tuple == NULL || fd_tuple->real_dev != fd)
    210 		return (write_f(fd, buf, nbytes));
    211 
    212 	if ((n = write_f(fd, buf, nbytes)) < 0 ||
    213 	    write_f(fd_tuple->snoop_out, buf, n) != n)
    214 		return (-1);
    215 
    216 	return (n);
    217 }
    218