xref: /netbsd-src/external/bsd/pam-u2f/dist/fuzz/wrap.c (revision 540ca2718c85d7b6631d382e3e93f4dc91e51282)
1 /* Copyright (C) 2021-2022 Yubico AB - See COPYING */
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <assert.h>
5 #include <errno.h>
6 #include <fcntl.h>
7 #include <pwd.h>
8 #include <stdarg.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 
14 #include <openssl/bio.h>
15 #include <openssl/ec.h>
16 #include <fido.h>
17 
18 #include "debug.h"
19 #include "drop_privs.h"
20 #include "fuzz/fuzz.h"
21 
22 extern int prng_up;
23 
24 #ifdef HAVE_PAM_MODUTIL_DROP_PRIV
25 typedef struct pam_modutil_privs fuzz_privs_t;
26 #else
27 typedef struct _ykman_privs fuzz_privs_t;
28 #endif
29 
30 /* In order to be able to fuzz pam-u2f, we need to be able to have a some
31  * predictable data regardless of where its being run. We therefore override
32  * functions which retrieve the local system's users, uid, hostnames,
33  * pam application data, and authenticator data. */
34 static const char *user_ptr = NULL;
35 static struct pam_conv *conv_ptr = NULL;
36 static uint8_t *wiredata_ptr = NULL;
37 static size_t wiredata_len = 0;
38 static int authfile_fd = -1;
39 static char env[] = "value";
40 
41 /* wrap a function, make it fail 0.25% of the time */
42 #define WRAP(type, name, args, retval, param)                                  \
43   extern type __wrap_##name args;                                              \
44   extern type __real_##name args;                                              \
45   type __wrap_##name args {                                                    \
46     if (prng_up && uniform_random(400) < 1) {                                  \
47       return (retval);                                                         \
48     }                                                                          \
49                                                                                \
50     return (__real_##name param);                                              \
51   }
52 
53 void set_wiredata(uint8_t *data, size_t len) {
54   wiredata_ptr = data;
55   wiredata_len = len;
56 }
57 void set_user(const char *user) { user_ptr = user; }
58 void set_conv(struct pam_conv *conv) { conv_ptr = conv; }
59 void set_authfile(int fd) { authfile_fd = fd; }
60 
61 WRAP(int, close, (int fd), -1, (fd))
62 WRAP(void *, strdup, (const char *s), NULL, (s))
63 WRAP(void *, calloc, (size_t nmemb, size_t size), NULL, (nmemb, size))
64 WRAP(void *, malloc, (size_t size), NULL, (size))
65 WRAP(int, gethostname, (char *name, size_t len), -1, (name, len))
66 WRAP(ssize_t, getline, (char **s, size_t *n, FILE *fp), -1, (s, n, fp))
67 WRAP(FILE *, fdopen, (int fd, const char *mode), NULL, (fd, mode))
68 WRAP(int, fstat, (int fd, struct stat *st), -1, (fd, st))
69 WRAP(BIO *, BIO_new, (const BIO_METHOD *type), NULL, (type))
70 WRAP(int, BIO_write, (BIO * b, const void *data, int len), -1, (b, data, len))
71 WRAP(int, BIO_read, (BIO * b, void *data, int len), -1, (b, data, len))
72 WRAP(int, BIO_ctrl, (BIO * b, int cmd, long larg, void *parg), -1,
73      (b, cmd, larg, parg))
74 WRAP(BIO *, BIO_new_mem_buf, (const void *buf, int len), NULL, (buf, len))
75 WRAP(EC_KEY *, EC_KEY_new_by_curve_name, (int nid), NULL, (nid))
76 WRAP(const EC_GROUP *, EC_KEY_get0_group, (const EC_KEY *key), NULL, (key))
77 
78 extern ssize_t __real_read(int fildes, void *buf, size_t nbyte);
79 extern ssize_t __wrap_read(int fildes, void *buf, size_t nbyte);
80 extern ssize_t __wrap_read(int fildes, void *buf, size_t nbyte) {
81   assert(fildes >= 0);
82   assert(buf != NULL);
83   return __real_read(fildes, buf, nbyte);
84 }
85 
86 extern int __wrap_asprintf(char **strp, const char *fmt, ...)
87   ATTRIBUTE_FORMAT(printf, 2, 3);
88 extern int __wrap_asprintf(char **strp, const char *fmt, ...) {
89   va_list ap;
90   int r;
91 
92   if (uniform_random(400) < 1) {
93     *strp = (void *) 0xdeadbeef;
94     return -1;
95   }
96 
97   va_start(ap, fmt);
98   r = vasprintf(strp, fmt, ap);
99   va_end(ap);
100 
101   return r;
102 }
103 
104 extern uid_t __wrap_geteuid(void);
105 extern uid_t __wrap_geteuid(void) {
106   return (uniform_random(10) < 1) ? 0 : 1008;
107 }
108 
109 extern int __real_open(const char *pathname, int flags);
110 extern int __wrap_open(const char *pathname, int flags);
111 extern int __wrap_open(const char *pathname, int flags) {
112   if (prng_up && uniform_random(400) < 1)
113     return -1;
114   /* open write-only files as /dev/null */
115   if ((flags & O_ACCMODE) == O_WRONLY)
116     return __real_open("/dev/null", flags);
117   /* FIXME: special handling for /dev/random */
118   if (strcmp(pathname, "/dev/urandom") == 0)
119     return __real_open(pathname, flags);
120   /* open read-only files using a shared fd for the authfile */
121   if ((flags & O_ACCMODE) == O_RDONLY)
122     return dup(authfile_fd);
123   assert(0); /* unsupported */
124   return -1;
125 }
126 
127 extern int __wrap_getpwuid_r(uid_t, struct passwd *, char *, size_t,
128                              struct passwd **);
129 extern int __wrap_getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
130                              size_t buflen, struct passwd **result) {
131   const char *user = user_ptr;
132   int offset;
133 
134   *result = NULL;
135   if (user == NULL || uniform_random(400) < 1)
136     return EIO;
137   if (uniform_random(400) < 1)
138     return 0; /* No matching record */
139   if (uniform_random(400) < 1)
140     user = "root";
141 
142   pwd->pw_uid = uid;
143   pwd->pw_gid = uid;
144 
145   if ((offset = snprintf(buf, buflen, "/home/")) < 0 ||
146       (size_t) offset >= buflen)
147     return ENOMEM;
148 
149   pwd->pw_dir = buf;
150   buf += offset;
151   buflen -= offset;
152 
153   if ((offset = snprintf(buf, buflen, "%s", user)) < 0 ||
154       (size_t) offset >= buflen)
155     return ENOMEM;
156 
157   if (offset > 1 && uniform_random(400) < 1)
158     buf[offset - 1] = '\0'; /* unexpected username */
159 
160   pwd->pw_name = buf;
161   *result = pwd;
162   return 0;
163 }
164 
165 extern int __wrap_getpwnam_r(const char *, struct passwd *, char *, size_t,
166                              struct passwd **);
167 extern int __wrap_getpwnam_r(const char *name, struct passwd *pwd, char *buf,
168                              size_t buflen, struct passwd **result) {
169   assert(name);
170   return __wrap_getpwuid_r(1008, pwd, buf, buflen, result);
171 }
172 
173 extern int __wrap_pam_get_item(const pam_handle_t *, int, const void **);
174 extern int __wrap_pam_get_item(const pam_handle_t *pamh, int item_type,
175                                const void **item) {
176   assert(pamh == (void *) FUZZ_PAM_HANDLE);
177   assert(item_type == PAM_CONV); /* other types unsupported */
178   assert(item != NULL);
179   *item = conv_ptr;
180 
181   return uniform_random(400) < 1 ? PAM_CONV_ERR : PAM_SUCCESS;
182 }
183 
184 extern int __wrap_pam_get_user(pam_handle_t *, const char **, const char *);
185 extern int __wrap_pam_get_user(pam_handle_t *pamh, const char **user_p,
186                                const char *prompt) {
187   assert(pamh == (void *) FUZZ_PAM_HANDLE);
188   assert(user_p != NULL);
189   assert(prompt == NULL);
190   *user_p = user_ptr;
191 
192   return uniform_random(400) < 1 ? PAM_CONV_ERR : PAM_SUCCESS;
193 }
194 
195 extern int __wrap_pam_modutil_drop_priv(pam_handle_t *, fuzz_privs_t *,
196                                         struct passwd *);
197 extern int __wrap_pam_modutil_drop_priv(pam_handle_t *pamh, fuzz_privs_t *privs,
198                                         struct passwd *pwd) {
199   assert(pamh == (void *) FUZZ_PAM_HANDLE);
200   assert(privs != NULL);
201   assert(pwd != NULL);
202 
203   return uniform_random(400) < 1 ? -1 : 0;
204 }
205 
206 extern int __wrap_pam_modutil_regain_priv(pam_handle_t *, fuzz_privs_t *,
207                                           struct passwd *);
208 extern int __wrap_pam_modutil_regain_priv(pam_handle_t *pamh,
209                                           fuzz_privs_t *privs,
210                                           struct passwd *pwd) {
211   assert(pamh == (void *) FUZZ_PAM_HANDLE);
212   assert(privs != NULL);
213   assert(pwd != NULL);
214 
215   return uniform_random(400) < 1 ? -1 : 0;
216 }
217 
218 extern char *__wrap_secure_getenv(const char *);
219 extern char *__wrap_secure_getenv(const char *name) {
220   (void) name;
221 
222   if (uniform_random(400) < 1)
223     return env;
224   return NULL;
225 }
226 
227 static int buf_read(unsigned char *ptr, size_t len, int ms) {
228   size_t n;
229 
230   (void) ms;
231 
232   if (wiredata_len < len)
233     n = wiredata_len;
234   else
235     n = len;
236 
237   memcpy(ptr, wiredata_ptr, n);
238   wiredata_ptr += n;
239   wiredata_len -= n;
240 
241   return (int) n;
242 }
243 
244 static int buf_write(const unsigned char *ptr, size_t len) {
245   (void) ptr;
246   return (int) len;
247 }
248 
249 static void *dev_open(const char *path) {
250   (void) path;
251   return (void *) FUZZ_DEV_HANDLE;
252 }
253 
254 static void dev_close(void *handle) {
255   assert(handle == (void *) FUZZ_DEV_HANDLE);
256 }
257 
258 static int dev_read(void *handle, unsigned char *ptr, size_t len, int ms) {
259   assert(handle == (void *) FUZZ_DEV_HANDLE);
260   return buf_read(ptr, len, ms);
261 }
262 
263 static int dev_write(void *handle, const unsigned char *ptr, size_t len) {
264   assert(handle == (void *) FUZZ_DEV_HANDLE);
265   return buf_write(ptr, len);
266 }
267 
268 extern int __wrap_fido_dev_open(fido_dev_t *dev, const char *path);
269 extern int __real_fido_dev_open(fido_dev_t *dev, const char *path);
270 int __wrap_fido_dev_open(fido_dev_t *dev, const char *path) {
271   fido_dev_io_t io;
272   int r;
273 
274   (void) path;
275 
276   memset(&io, 0, sizeof(io));
277 
278   io.open = dev_open;
279   io.close = dev_close;
280   io.read = dev_read;
281   io.write = dev_write;
282 
283   if ((r = fido_dev_set_io_functions(dev, &io)) != FIDO_OK)
284     goto err;
285 
286   if ((r = __real_fido_dev_open(dev, "nodev")) != FIDO_OK)
287     goto err;
288 
289 err:
290   return r;
291 }
292 
293 extern int __wrap_fido_dev_info_manifest(fido_dev_info_t *, size_t, size_t *);
294 extern int __wrap_fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen,
295                                          size_t *olen) {
296   (void) devlist;
297   (void) ilen;
298 
299   *olen = (size_t) uniform_random((uint32_t) ilen);
300 
301   return uniform_random(400) < 1 ? FIDO_ERR_INTERNAL : FIDO_OK;
302 }
303