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