summaryrefslogtreecommitdiff
path: root/fuzz/preload-snoop.c
diff options
context:
space:
mode:
Diffstat (limited to 'fuzz/preload-snoop.c')
-rw-r--r--fuzz/preload-snoop.c217
1 files changed, 217 insertions, 0 deletions
diff --git a/fuzz/preload-snoop.c b/fuzz/preload-snoop.c
new file mode 100644
index 0000000..373acc5
--- /dev/null
+++ b/fuzz/preload-snoop.c
@@ -0,0 +1,217 @@
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
28struct fd_tuple {
29 int snoop_in;
30 int snoop_out;
31 int real_dev;
32};
33
34static struct fd_tuple *fd_tuple;
35static int (*open_f)(const char *, int, mode_t);
36static int (*close_f)(int);
37static ssize_t (*read_f)(int, void *, size_t);
38static ssize_t (*write_f)(int, const void *, size_t);
39
40static int
41get_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
75int
76open(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);
121fail:
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
137int
138close(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
162ssize_t
163read(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
195ssize_t
196write(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}