xref: /netbsd-src/external/bsd/pam-u2f/dist/fuzz/wrap.c (revision 540ca2718c85d7b6631d382e3e93f4dc91e51282)
1*540ca271Schristos /* Copyright (C) 2021-2022 Yubico AB - See COPYING */
23ff1169cSchristos #include <sys/types.h>
33ff1169cSchristos #include <sys/stat.h>
4*540ca271Schristos #include <assert.h>
5*540ca271Schristos #include <errno.h>
6*540ca271Schristos #include <fcntl.h>
7*540ca271Schristos #include <pwd.h>
8*540ca271Schristos #include <stdarg.h>
9*540ca271Schristos #include <stdio.h>
10*540ca271Schristos #include <stdlib.h>
11*540ca271Schristos #include <string.h>
123ff1169cSchristos #include <unistd.h>
133ff1169cSchristos 
143ff1169cSchristos #include <openssl/bio.h>
153ff1169cSchristos #include <openssl/ec.h>
163ff1169cSchristos #include <fido.h>
173ff1169cSchristos 
18*540ca271Schristos #include "debug.h"
193ff1169cSchristos #include "drop_privs.h"
203ff1169cSchristos #include "fuzz/fuzz.h"
213ff1169cSchristos 
22*540ca271Schristos extern int prng_up;
23*540ca271Schristos 
243ff1169cSchristos #ifdef HAVE_PAM_MODUTIL_DROP_PRIV
253ff1169cSchristos typedef struct pam_modutil_privs fuzz_privs_t;
263ff1169cSchristos #else
273ff1169cSchristos typedef struct _ykman_privs fuzz_privs_t;
283ff1169cSchristos #endif
293ff1169cSchristos 
303ff1169cSchristos /* In order to be able to fuzz pam-u2f, we need to be able to have a some
313ff1169cSchristos  * predictable data regardless of where its being run. We therefore override
323ff1169cSchristos  * functions which retrieve the local system's users, uid, hostnames,
333ff1169cSchristos  * pam application data, and authenticator data. */
343ff1169cSchristos static const char *user_ptr = NULL;
353ff1169cSchristos static struct pam_conv *conv_ptr = NULL;
363ff1169cSchristos static uint8_t *wiredata_ptr = NULL;
373ff1169cSchristos static size_t wiredata_len = 0;
383ff1169cSchristos static int authfile_fd = -1;
393ff1169cSchristos static char env[] = "value";
403ff1169cSchristos 
413ff1169cSchristos /* wrap a function, make it fail 0.25% of the time */
423ff1169cSchristos #define WRAP(type, name, args, retval, param)                                  \
433ff1169cSchristos   extern type __wrap_##name args;                                              \
443ff1169cSchristos   extern type __real_##name args;                                              \
453ff1169cSchristos   type __wrap_##name args {                                                    \
46*540ca271Schristos     if (prng_up && uniform_random(400) < 1) {                                  \
473ff1169cSchristos       return (retval);                                                         \
483ff1169cSchristos     }                                                                          \
493ff1169cSchristos                                                                                \
503ff1169cSchristos     return (__real_##name param);                                              \
513ff1169cSchristos   }
523ff1169cSchristos 
533ff1169cSchristos void set_wiredata(uint8_t *data, size_t len) {
543ff1169cSchristos   wiredata_ptr = data;
553ff1169cSchristos   wiredata_len = len;
563ff1169cSchristos }
573ff1169cSchristos void set_user(const char *user) { user_ptr = user; }
583ff1169cSchristos void set_conv(struct pam_conv *conv) { conv_ptr = conv; }
593ff1169cSchristos void set_authfile(int fd) { authfile_fd = fd; }
603ff1169cSchristos 
613ff1169cSchristos WRAP(int, close, (int fd), -1, (fd))
623ff1169cSchristos WRAP(void *, strdup, (const char *s), NULL, (s))
633ff1169cSchristos WRAP(void *, calloc, (size_t nmemb, size_t size), NULL, (nmemb, size))
643ff1169cSchristos WRAP(void *, malloc, (size_t size), NULL, (size))
653ff1169cSchristos WRAP(int, gethostname, (char *name, size_t len), -1, (name, len))
66*540ca271Schristos WRAP(ssize_t, getline, (char **s, size_t *n, FILE *fp), -1, (s, n, fp))
673ff1169cSchristos WRAP(FILE *, fdopen, (int fd, const char *mode), NULL, (fd, mode))
683ff1169cSchristos WRAP(int, fstat, (int fd, struct stat *st), -1, (fd, st))
693ff1169cSchristos WRAP(BIO *, BIO_new, (const BIO_METHOD *type), NULL, (type))
703ff1169cSchristos WRAP(int, BIO_write, (BIO * b, const void *data, int len), -1, (b, data, len))
713ff1169cSchristos WRAP(int, BIO_read, (BIO * b, void *data, int len), -1, (b, data, len))
723ff1169cSchristos WRAP(int, BIO_ctrl, (BIO * b, int cmd, long larg, void *parg), -1,
733ff1169cSchristos      (b, cmd, larg, parg))
743ff1169cSchristos WRAP(BIO *, BIO_new_mem_buf, (const void *buf, int len), NULL, (buf, len))
753ff1169cSchristos WRAP(EC_KEY *, EC_KEY_new_by_curve_name, (int nid), NULL, (nid))
763ff1169cSchristos WRAP(const EC_GROUP *, EC_KEY_get0_group, (const EC_KEY *key), NULL, (key))
773ff1169cSchristos 
78*540ca271Schristos extern ssize_t __real_read(int fildes, void *buf, size_t nbyte);
79*540ca271Schristos extern ssize_t __wrap_read(int fildes, void *buf, size_t nbyte);
80*540ca271Schristos extern ssize_t __wrap_read(int fildes, void *buf, size_t nbyte) {
81*540ca271Schristos   assert(fildes >= 0);
82*540ca271Schristos   assert(buf != NULL);
83*540ca271Schristos   return __real_read(fildes, buf, nbyte);
84*540ca271Schristos }
85*540ca271Schristos 
86*540ca271Schristos extern int __wrap_asprintf(char **strp, const char *fmt, ...)
87*540ca271Schristos   ATTRIBUTE_FORMAT(printf, 2, 3);
88*540ca271Schristos extern int __wrap_asprintf(char **strp, const char *fmt, ...) {
89*540ca271Schristos   va_list ap;
90*540ca271Schristos   int r;
91*540ca271Schristos 
92*540ca271Schristos   if (uniform_random(400) < 1) {
93*540ca271Schristos     *strp = (void *) 0xdeadbeef;
94*540ca271Schristos     return -1;
95*540ca271Schristos   }
96*540ca271Schristos 
97*540ca271Schristos   va_start(ap, fmt);
98*540ca271Schristos   r = vasprintf(strp, fmt, ap);
99*540ca271Schristos   va_end(ap);
100*540ca271Schristos 
101*540ca271Schristos   return r;
102*540ca271Schristos }
103*540ca271Schristos 
1043ff1169cSchristos extern uid_t __wrap_geteuid(void);
1053ff1169cSchristos extern uid_t __wrap_geteuid(void) {
1063ff1169cSchristos   return (uniform_random(10) < 1) ? 0 : 1008;
1073ff1169cSchristos }
1083ff1169cSchristos 
1093ff1169cSchristos extern int __real_open(const char *pathname, int flags);
1103ff1169cSchristos extern int __wrap_open(const char *pathname, int flags);
1113ff1169cSchristos extern int __wrap_open(const char *pathname, int flags) {
112*540ca271Schristos   if (prng_up && uniform_random(400) < 1)
1133ff1169cSchristos     return -1;
1143ff1169cSchristos   /* open write-only files as /dev/null */
1153ff1169cSchristos   if ((flags & O_ACCMODE) == O_WRONLY)
1163ff1169cSchristos     return __real_open("/dev/null", flags);
1173ff1169cSchristos   /* FIXME: special handling for /dev/random */
1183ff1169cSchristos   if (strcmp(pathname, "/dev/urandom") == 0)
1193ff1169cSchristos     return __real_open(pathname, flags);
1203ff1169cSchristos   /* open read-only files using a shared fd for the authfile */
1213ff1169cSchristos   if ((flags & O_ACCMODE) == O_RDONLY)
1223ff1169cSchristos     return dup(authfile_fd);
1233ff1169cSchristos   assert(0); /* unsupported */
1243ff1169cSchristos   return -1;
1253ff1169cSchristos }
1263ff1169cSchristos 
1273ff1169cSchristos extern int __wrap_getpwuid_r(uid_t, struct passwd *, char *, size_t,
1283ff1169cSchristos                              struct passwd **);
1293ff1169cSchristos extern int __wrap_getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
1303ff1169cSchristos                              size_t buflen, struct passwd **result) {
1313ff1169cSchristos   const char *user = user_ptr;
1323ff1169cSchristos   int offset;
1333ff1169cSchristos 
1343ff1169cSchristos   *result = NULL;
1353ff1169cSchristos   if (user == NULL || uniform_random(400) < 1)
1363ff1169cSchristos     return EIO;
1373ff1169cSchristos   if (uniform_random(400) < 1)
1383ff1169cSchristos     return 0; /* No matching record */
1393ff1169cSchristos   if (uniform_random(400) < 1)
1403ff1169cSchristos     user = "root";
1413ff1169cSchristos 
1423ff1169cSchristos   pwd->pw_uid = uid;
1433ff1169cSchristos   pwd->pw_gid = uid;
1443ff1169cSchristos 
1453ff1169cSchristos   if ((offset = snprintf(buf, buflen, "/home/")) < 0 ||
1463ff1169cSchristos       (size_t) offset >= buflen)
1473ff1169cSchristos     return ENOMEM;
1483ff1169cSchristos 
1493ff1169cSchristos   pwd->pw_dir = buf;
1503ff1169cSchristos   buf += offset;
1513ff1169cSchristos   buflen -= offset;
1523ff1169cSchristos 
1533ff1169cSchristos   if ((offset = snprintf(buf, buflen, "%s", user)) < 0 ||
1543ff1169cSchristos       (size_t) offset >= buflen)
1553ff1169cSchristos     return ENOMEM;
1563ff1169cSchristos 
1573ff1169cSchristos   if (offset > 1 && uniform_random(400) < 1)
1583ff1169cSchristos     buf[offset - 1] = '\0'; /* unexpected username */
1593ff1169cSchristos 
1603ff1169cSchristos   pwd->pw_name = buf;
1613ff1169cSchristos   *result = pwd;
1623ff1169cSchristos   return 0;
1633ff1169cSchristos }
1643ff1169cSchristos 
1653ff1169cSchristos extern int __wrap_getpwnam_r(const char *, struct passwd *, char *, size_t,
1663ff1169cSchristos                              struct passwd **);
1673ff1169cSchristos extern int __wrap_getpwnam_r(const char *name, struct passwd *pwd, char *buf,
1683ff1169cSchristos                              size_t buflen, struct passwd **result) {
1693ff1169cSchristos   assert(name);
1703ff1169cSchristos   return __wrap_getpwuid_r(1008, pwd, buf, buflen, result);
1713ff1169cSchristos }
1723ff1169cSchristos 
1733ff1169cSchristos extern int __wrap_pam_get_item(const pam_handle_t *, int, const void **);
1743ff1169cSchristos extern int __wrap_pam_get_item(const pam_handle_t *pamh, int item_type,
1753ff1169cSchristos                                const void **item) {
1763ff1169cSchristos   assert(pamh == (void *) FUZZ_PAM_HANDLE);
1773ff1169cSchristos   assert(item_type == PAM_CONV); /* other types unsupported */
1783ff1169cSchristos   assert(item != NULL);
1793ff1169cSchristos   *item = conv_ptr;
1803ff1169cSchristos 
1813ff1169cSchristos   return uniform_random(400) < 1 ? PAM_CONV_ERR : PAM_SUCCESS;
1823ff1169cSchristos }
1833ff1169cSchristos 
1843ff1169cSchristos extern int __wrap_pam_get_user(pam_handle_t *, const char **, const char *);
1853ff1169cSchristos extern int __wrap_pam_get_user(pam_handle_t *pamh, const char **user_p,
1863ff1169cSchristos                                const char *prompt) {
1873ff1169cSchristos   assert(pamh == (void *) FUZZ_PAM_HANDLE);
1883ff1169cSchristos   assert(user_p != NULL);
1893ff1169cSchristos   assert(prompt == NULL);
1903ff1169cSchristos   *user_p = user_ptr;
1913ff1169cSchristos 
1923ff1169cSchristos   return uniform_random(400) < 1 ? PAM_CONV_ERR : PAM_SUCCESS;
1933ff1169cSchristos }
1943ff1169cSchristos 
1953ff1169cSchristos extern int __wrap_pam_modutil_drop_priv(pam_handle_t *, fuzz_privs_t *,
1963ff1169cSchristos                                         struct passwd *);
1973ff1169cSchristos extern int __wrap_pam_modutil_drop_priv(pam_handle_t *pamh, fuzz_privs_t *privs,
1983ff1169cSchristos                                         struct passwd *pwd) {
1993ff1169cSchristos   assert(pamh == (void *) FUZZ_PAM_HANDLE);
2003ff1169cSchristos   assert(privs != NULL);
2013ff1169cSchristos   assert(pwd != NULL);
2023ff1169cSchristos 
2033ff1169cSchristos   return uniform_random(400) < 1 ? -1 : 0;
2043ff1169cSchristos }
2053ff1169cSchristos 
2063ff1169cSchristos extern int __wrap_pam_modutil_regain_priv(pam_handle_t *, fuzz_privs_t *,
2073ff1169cSchristos                                           struct passwd *);
2083ff1169cSchristos extern int __wrap_pam_modutil_regain_priv(pam_handle_t *pamh,
2093ff1169cSchristos                                           fuzz_privs_t *privs,
2103ff1169cSchristos                                           struct passwd *pwd) {
2113ff1169cSchristos   assert(pamh == (void *) FUZZ_PAM_HANDLE);
2123ff1169cSchristos   assert(privs != NULL);
2133ff1169cSchristos   assert(pwd != NULL);
2143ff1169cSchristos 
2153ff1169cSchristos   return uniform_random(400) < 1 ? -1 : 0;
2163ff1169cSchristos }
2173ff1169cSchristos 
2183ff1169cSchristos extern char *__wrap_secure_getenv(const char *);
2193ff1169cSchristos extern char *__wrap_secure_getenv(const char *name) {
2203ff1169cSchristos   (void) name;
2213ff1169cSchristos 
2223ff1169cSchristos   if (uniform_random(400) < 1)
2233ff1169cSchristos     return env;
2243ff1169cSchristos   return NULL;
2253ff1169cSchristos }
2263ff1169cSchristos 
2273ff1169cSchristos static int buf_read(unsigned char *ptr, size_t len, int ms) {
2283ff1169cSchristos   size_t n;
2293ff1169cSchristos 
2303ff1169cSchristos   (void) ms;
2313ff1169cSchristos 
2323ff1169cSchristos   if (wiredata_len < len)
2333ff1169cSchristos     n = wiredata_len;
2343ff1169cSchristos   else
2353ff1169cSchristos     n = len;
2363ff1169cSchristos 
2373ff1169cSchristos   memcpy(ptr, wiredata_ptr, n);
2383ff1169cSchristos   wiredata_ptr += n;
2393ff1169cSchristos   wiredata_len -= n;
2403ff1169cSchristos 
2413ff1169cSchristos   return (int) n;
2423ff1169cSchristos }
2433ff1169cSchristos 
2443ff1169cSchristos static int buf_write(const unsigned char *ptr, size_t len) {
2453ff1169cSchristos   (void) ptr;
2463ff1169cSchristos   return (int) len;
2473ff1169cSchristos }
2483ff1169cSchristos 
2493ff1169cSchristos static void *dev_open(const char *path) {
2503ff1169cSchristos   (void) path;
2513ff1169cSchristos   return (void *) FUZZ_DEV_HANDLE;
2523ff1169cSchristos }
2533ff1169cSchristos 
2543ff1169cSchristos static void dev_close(void *handle) {
2553ff1169cSchristos   assert(handle == (void *) FUZZ_DEV_HANDLE);
2563ff1169cSchristos }
2573ff1169cSchristos 
2583ff1169cSchristos static int dev_read(void *handle, unsigned char *ptr, size_t len, int ms) {
2593ff1169cSchristos   assert(handle == (void *) FUZZ_DEV_HANDLE);
2603ff1169cSchristos   return buf_read(ptr, len, ms);
2613ff1169cSchristos }
2623ff1169cSchristos 
2633ff1169cSchristos static int dev_write(void *handle, const unsigned char *ptr, size_t len) {
2643ff1169cSchristos   assert(handle == (void *) FUZZ_DEV_HANDLE);
2653ff1169cSchristos   return buf_write(ptr, len);
2663ff1169cSchristos }
2673ff1169cSchristos 
2683ff1169cSchristos extern int __wrap_fido_dev_open(fido_dev_t *dev, const char *path);
2693ff1169cSchristos extern int __real_fido_dev_open(fido_dev_t *dev, const char *path);
2703ff1169cSchristos int __wrap_fido_dev_open(fido_dev_t *dev, const char *path) {
2713ff1169cSchristos   fido_dev_io_t io;
2723ff1169cSchristos   int r;
2733ff1169cSchristos 
2743ff1169cSchristos   (void) path;
2753ff1169cSchristos 
2763ff1169cSchristos   memset(&io, 0, sizeof(io));
2773ff1169cSchristos 
2783ff1169cSchristos   io.open = dev_open;
2793ff1169cSchristos   io.close = dev_close;
2803ff1169cSchristos   io.read = dev_read;
2813ff1169cSchristos   io.write = dev_write;
2823ff1169cSchristos 
2833ff1169cSchristos   if ((r = fido_dev_set_io_functions(dev, &io)) != FIDO_OK)
2843ff1169cSchristos     goto err;
2853ff1169cSchristos 
2863ff1169cSchristos   if ((r = __real_fido_dev_open(dev, "nodev")) != FIDO_OK)
2873ff1169cSchristos     goto err;
2883ff1169cSchristos 
2893ff1169cSchristos err:
2903ff1169cSchristos   return r;
2913ff1169cSchristos }
2923ff1169cSchristos 
2933ff1169cSchristos extern int __wrap_fido_dev_info_manifest(fido_dev_info_t *, size_t, size_t *);
2943ff1169cSchristos extern int __wrap_fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen,
2953ff1169cSchristos                                          size_t *olen) {
2963ff1169cSchristos   (void) devlist;
2973ff1169cSchristos   (void) ilen;
2983ff1169cSchristos 
2993ff1169cSchristos   *olen = (size_t) uniform_random((uint32_t) ilen);
3003ff1169cSchristos 
3013ff1169cSchristos   return uniform_random(400) < 1 ? FIDO_ERR_INTERNAL : FIDO_OK;
3023ff1169cSchristos }
303