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