// We wrap all important calls to glibc to insure that pointers are checked and unprotected before being used // internally in glibc or passed to system calls. // // For each pointer argument, we need to check, unprotect, call the glibc function and reprotect. // If a glibc function calls another nested glibc function, there is no need to do further // processing, because the arguments should have already been checked and unprotected. #define _GNU_SOURCE #include <malloc.h> #include <string.h> #include <wchar.h> #include <signal.h> #include <stdlib.h> #include <pthread.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <sys/wait.h> #include <sys/user.h> #include <errno.h> #include <sched.h> #include <limits.h> #include <sys/mman.h> #include <execinfo.h> #include <unistd.h> #include <fcntl.h> #include <linux/openat2.h> #include <stdarg.h> #include <dlfcn.h> #include <sys/vfs.h> #include <dirent.h> #include <libintl.h> #include <locale.h> #include <sys/param.h> #include "dw-log.h" #include "dw-protect.h" #include "dw-wrap-glibc.h" // Intercept common glibc functions to check access and remove the protection from pointers. // This is essential for system calls because otherwise they will fail. // It is also useful for utility functions, as it can simplify the access check // (a single one instead of multiple ones) and avoid some functions that may perform // tricky pointer arithmetic (e.g. memcpy / memmove) // // Only a minimal set of wrappers was implemented, it is far from being complete. // Moreover, some of the wrappers are incomplete. For instance, for the execvpe and // similar functions, the argv and envp arrays are unprotected, but not the pointers // contained within. This would require allocating a new array where to copy the unprotected // pointers. // Check that we can get the desired symbol void *dlsym_check(void *restrict handle, const char *restrict symbol) { void *ret = dlsym(handle, symbol); if(ret == NULL) dw_log(WARNING, WRAP, "Symbol %s not found\n", symbol); return ret; } // Size of argv arguments in execve and similar functions static size_t arglen(char *const argv[]) { size_t i = 0; for(; argv[i] != NULL; i++); return sizeof(char *) * (i + 1); } // Have our own strlen, not called with tainted pointers, that will // not be instrumented by libpatch. size_t dw_strlen(const char* s) { const char* cursor; for (cursor = s; *cursor != 0; cursor++); return (size_t)(cursor - s); } // Declare all the pointers to the original libc functions static char* (*libc_strchr)(const char *s, int c); static char* (*libc_strrchr)(const char *s, int c); static int (*libc_strcmp)(const char *s1, const char *s2); static int (*libc_strncmp)(const char *s1, const char *s2, size_t n); static int (*libc_fputs)(const char *restrict s, FILE *restrict stream); static int (*libc_puts)(const char *s); static size_t (*libc_strlen)(const char *s); static int (*libc_open)(const char *pathname, int flags, ...); static int (*libc_openat)(int dirfd, const char *pathname, int flags, ...); static int (*libc_creat)(const char *pathname, mode_t mode); static int (*libc_access)(const char *pathname, int mode); static char* (*libc_getcwd)(char *buf, size_t size); static ssize_t (*libc_getrandom)(void *buf, size_t buflen, unsigned int flags); static int (*libc_stat)(const char *restrict pathname, struct stat *restrict statbuf); static int (*libc_fstat)(int fd, struct stat *statbuf); static int (*libc_lstat)(const char *restrict pathname, struct stat *restrict statbuf); static int (*libc_fstatat)(int dirfd, const char *restrict pathname, struct stat *restrict statbuf, int flags); static size_t (*libc_fread)(void *ptr, size_t size, size_t nmemb, FILE *stream); static size_t (*libc_fwrite)(const void *ptr, size_t size, size_t nmemb, FILE *stream); static ssize_t (*libc_pread)(int fd, void *buf, size_t count, off_t offset); static ssize_t (*libc_pwrite)(int fd, const void *buf, size_t count, off_t offset); static ssize_t (*libc_read)(int fd, void *buf, size_t count); extern ssize_t __read(int fd, void *buf, size_t count); static ssize_t (*libc_write)(int fd, const void *buf, size_t count); extern ssize_t libc_real_write(int fd, const void *buf, size_t count); static int (*libc_statfs)(const char *path, struct statfs *buf); static int (*libc_fstatfs)(int fd, struct statfs *buf); static ssize_t (*libc_getdents64)(int fd, void *dirp, size_t count); static DIR* (*libc_opendir)(const char *name); static int (*libc_bcmp)(const void *s1, const void *s2, size_t n); static void (*libc_bcopy)(const void *src, void *dest, size_t n); static void (*libc_bzero)(void *s, size_t n); static void* (*libc_memccpy)(void *dest, const void *src, int c, size_t n); static void* (*libc_memchr)(const void *s, int c, size_t n); static int (*libc_memcmp)(const void *s1, const void *s2, size_t n); static void* (*libc_memcpy)(void *dest, const void *src, size_t n); static void* (*libc_memcpy_chk)(void *dest, const void *src, size_t len, size_t destlen); static void* (*libc_memfrob)(void *s, size_t n); static void* (*libc_memmem)(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen); static void* (*libc_memmove)(void *dest, const void *src, size_t n); static void* (*libc_mempcpy)(void *restrict dest, const void *restrict src, size_t n); static void* (*libc_memset)(void *s, int c, size_t n); static char* (*libc_strcpy)(char *restrict dest, const char *src); static char* (*libc_strcat)(char *restrict dest, const char *src); static char* (*libc_strncpy)(char *restrict dest, const char *restrict src, size_t n); static wchar_t* (*libc_wmemmove)(wchar_t *dest, const wchar_t *src, size_t n); static wchar_t* (*libc_wmempcpy)(wchar_t *restrict dest, const wchar_t *restrict src, size_t n); static wchar_t* (*libc_wmemcpy)(wchar_t *restrict dest, const wchar_t *restrict src, size_t n); static char* (*libc_gettext)(const char * msgid); static char* (*libc_dgettext)(const char * domainname, const char * msgid); extern char* __dgettext(const char * domainname, const char * msgid); extern char* __dcgettext(const char * domainname, const char * msgid, int category); static char* (*libc_ngettext)(const char *msgid, const char *msgid_plural, unsigned long int n); static char* (*libc_dcngettext)(const char *domainname, const char *msgid, const char *msgid_plural, unsigned long int n, int category); static char* (*libc_setlocale)(int category, const char *locale); static char* (*libc_textdomain)(const char * domainname); static int (*libc_execve)(const char *pathname, char *const argv[], char *const envp[]); static int (*libc_execv)(const char *pathname, char *const argv[]); static int (*libc_execvp)(const char *file, char *const argv[]); static int (*libc_execvpe)(const char *file, char *const argv[], char *const envp[]); // Get the address for all the wrapped libc functions. Some of these functions may get called // very early. Therefore we do check for initialization right before use with the iss() macro. int dw_init_stubs = 0; // size_t (*dw_strlen)(const char *s); void dw_init_syscall_stubs() { libc_strlen = dw_strlen; libc_strchr = dlsym_check(RTLD_NEXT, "strchr"); libc_strrchr = dlsym_check(RTLD_NEXT, "strrchr"); libc_strcmp = dlsym_check(RTLD_NEXT, "strcmp"); libc_strncmp = dlsym_check(RTLD_NEXT, "strncmp"); libc_fputs = dlsym_check(RTLD_NEXT, "fputs"); libc_puts = dlsym_check(RTLD_NEXT, "puts"); libc_open = dlsym_check(RTLD_NEXT, "open"); libc_openat = dlsym_check(RTLD_NEXT, "openat"); libc_creat = dlsym_check(RTLD_NEXT, "creat"); libc_access = dlsym_check(RTLD_NEXT, "access"); libc_getcwd = dlsym_check(RTLD_NEXT, "getcwd"); libc_getrandom = dlsym_check(RTLD_NEXT, "getrandom"); libc_stat = dlsym_check(RTLD_NEXT, "stat"); libc_fstat = dlsym_check(RTLD_NEXT, "fstat"); libc_lstat = dlsym_check(RTLD_NEXT, "lstat"); libc_fstatat = dlsym_check(RTLD_NEXT, "fstatat"); libc_fread = dlsym_check(RTLD_NEXT, "fread"); libc_fwrite = dlsym_check(RTLD_NEXT, "fwrite"); libc_pread = dlsym_check(RTLD_NEXT, "pread"); libc_pwrite = dlsym_check(RTLD_NEXT, "pwrite"); libc_read = __read; // dlsym_check(RTLD_NEXT, "read"); libc_write = dlsym_check(RTLD_NEXT, "write"); libc_statfs = dlsym_check(RTLD_NEXT, "statfs"); libc_fstatfs = dlsym_check(RTLD_NEXT, "fstatfs"); libc_getdents64 = dlsym_check(RTLD_NEXT, "getdents64"); libc_bcmp = dlsym_check(RTLD_NEXT, "bcmp"); libc_bcopy = dlsym_check(RTLD_NEXT, "bcopy"); libc_bzero = dlsym_check(RTLD_NEXT, "bzero"); libc_memccpy = dlsym_check(RTLD_NEXT, "memccpy"); libc_memchr = dlsym_check(RTLD_NEXT, "memchr"); libc_memcmp = dlsym_check(RTLD_NEXT, "memcmp"); libc_memcpy = dlsym_check(RTLD_NEXT, "memcpy"); libc_memcpy_chk = dlsym_check(RTLD_NEXT, "__memcpy_chk"); libc_memfrob = dlsym_check(RTLD_NEXT, "memfrob"); libc_memmem = dlsym_check(RTLD_NEXT, "memmem"); libc_memmove = dlsym_check(RTLD_NEXT, "memmove"); libc_mempcpy = dlsym_check(RTLD_NEXT, "mempcpy"); libc_memset = dlsym_check(RTLD_NEXT, "memset"); libc_strcpy = dlsym_check(RTLD_NEXT, "strcpy"); libc_strcat = dlsym_check(RTLD_NEXT, "strcat"); libc_strncpy = dlsym_check(RTLD_NEXT, "strncpy"); libc_wmemmove = dlsym_check(RTLD_NEXT, "wmemmove"); libc_wmempcpy = dlsym_check(RTLD_NEXT, "wmempcpy"); libc_wmemcpy = dlsym_check(RTLD_NEXT, "wmemcpy"); libc_gettext = dlsym_check(RTLD_NEXT, "gettext"); libc_dgettext = __dgettext; // dlsym_check(RTLD_NEXT, "dgettext "); libc_ngettext = dlsym_check(RTLD_NEXT, "ngettext"); libc_dcngettext = dlsym_check(RTLD_NEXT, "dcngettext"); libc_setlocale = dlsym_check(RTLD_NEXT, "setlocale"); libc_opendir = dlsym_check(RTLD_NEXT, "opendir"); libc_textdomain = dlsym_check(RTLD_NEXT, "textdomain"); libc_execve = dlsym_check(RTLD_NEXT, "execve"); libc_execv = dlsym_check(RTLD_NEXT, "execv"); libc_execvp = dlsym_check(RTLD_NEXT, "execvp"); libc_execvpe = dlsym_check(RTLD_NEXT, "execvpe"); dw_init_stubs = 1; } // Make it shorter, every function calls those #define sin() dw_sin() #define sout() dw_sout() // For each tainted pointer passed to a wrapper, we could eventually check if it is accessed properly, // given the semantics of the function called and the bounds of the pointed object. // The replacements for libc functions for now simply remove the taint before calling // the replaced functions. In some cases, the taint must be reapplied. For instance, // the memccpy function copies a string to a certain character then returns a pointer to // that character. This pointer may be derived from a tainted pointer and the taint must be // carried to it from the dest pointer. size_t strlen(const char *s) { sin(); size_t ret = libc_strlen(dw_unprotect((void *)s)); dw_reprotect((void *)s); sout(); return ret; } #include "dw-printf.h" static inline void fputc_wrapper(char c, void* extra_arg) { FILE *fp = (FILE *)extra_arg; fputc(c, fp); } static inline void dputc_wrapper(char c, void* extra_arg) { int fd = (int)((uintptr_t)extra_arg); libc_write(fd, &c, 1); } int __fprintf_chk(FILE *stream, int flag, const char *format, ...) { va_list arg; va_start(arg, format); const int ret = vfctprintf(fputc_wrapper, (void *)stream, format, arg); va_end(arg); return ret; } int fprintf(FILE *stream, const char *format, ...) { va_list arg; va_start(arg, format); const int ret = vfctprintf(fputc_wrapper, (void *)stream, format, arg); va_end(arg); return ret; } int dprintf(int fd, const char *format, ...) { va_list arg; va_start(arg, format); const int ret = vfctprintf(dputc_wrapper, (void *)((uintptr_t)fd), format, arg); va_end(arg); return ret; } int __sprintf_chk(char *s, int flag, size_t os, const char *fmt, ...) { va_list arg; va_start(arg, fmt); const int ret = vsnprintf(s, os, fmt, arg); va_end(arg); return ret; } int __snprintf_chk(char *s, size_t maxlen, int flag, size_t os, const char *fmt, ...) { va_list arg; va_start(arg, fmt); const int ret = vsnprintf(s, os, fmt, arg); va_end(arg); return ret; } int vfprintf(FILE *restrict stream, const char *restrict format, va_list arg) { return vfctprintf(fputc_wrapper, (void *)stream, format, arg); } int vdprintf(int fd, const char *restrict format, va_list arg) { return vfctprintf(dputc_wrapper, (void *)((uintptr_t)fd), format, arg); } char *strchr(const char *s, int c) { sin(); char *ns = dw_unprotect((void *)s); dw_check_access((void *)s, libc_strlen(ns) + 1); char *ret = libc_strchr(ns, c); dw_reprotect((void *)s); sout(); if(ret == NULL) return ret; return (void *)dw_retaint(ret, s); } char *strrchr(const char *s, int c) { sin(); char *ns = dw_unprotect((void *)s); dw_check_access((void *)s, libc_strlen(ns) + 1); char *ret = libc_strrchr(ns, c); dw_reprotect((void *)s); sout(); if(ret == NULL) return ret; return (void *)dw_retaint(ret, s); } int strcmp(const char *s1, const char *s2) { sin(); char *ns1 = dw_unprotect((void *)s1); dw_check_access((void *)s1, libc_strlen(ns1) + 1); char *ns2 = dw_unprotect((void *)s2); dw_check_access((void *)s2, libc_strlen(ns2) + 1); int ret = libc_strcmp(ns1, ns2); dw_reprotect((void *)s1); dw_reprotect((void *)s2); sout(); return ret; } int strncmp(const char *s1, const char *s2, size_t n) { sin(); char *ns1 = dw_unprotect((void *)s1); dw_check_access((void *)s1, MIN(n, libc_strlen(ns1) + 1)); char *ns2 = dw_unprotect((void *)s2); dw_check_access((void *)s2, MIN(n, libc_strlen(ns2) + 1)); int ret = libc_strncmp(ns1, ns2, n); dw_reprotect((void *)s1); dw_reprotect((void *)s2); sout(); return ret; } int fputs(const char *restrict s, FILE *restrict stream) { sin(); char *ns = dw_unprotect((void *)s); dw_check_access((void *)s, libc_strlen(ns) + 1); int ret = libc_fputs(ns, stream); dw_reprotect((void *)s); sout(); return ret; } int puts(const char *s) { sin(); char *ns = dw_unprotect((void *)s); dw_check_access((void *)s, libc_strlen(ns) + 1); int ret = libc_puts(ns); dw_reprotect((void *)s); sout(); return ret; } // Open can take 2 or 3 arguments, we handle it just like glibc does it internally. int open(const char *pathname, int flags, ...) { sin(); mode_t mode = 0; if(__OPEN_NEEDS_MODE(flags)) { va_list arg; va_start(arg, flags); mode = va_arg(arg, mode_t); va_end(arg); } char *npathname = dw_unprotect((void *)pathname); dw_check_access((void *)pathname, libc_strlen(npathname) + 1); int ret = libc_open(npathname, flags, mode); dw_reprotect((void *)pathname); sout(); return ret; } int openat(int dirfd, const char *pathname, int flags, ...) { sin(); mode_t mode = 0; if(__OPEN_NEEDS_MODE(flags)) { va_list arg; va_start(arg, flags); mode = va_arg(arg, mode_t); va_end(arg); } char *npathname = dw_unprotect((void *)pathname); dw_check_access((void *)pathname, libc_strlen(npathname) + 1); int ret = libc_openat(dirfd, npathname, flags, mode); dw_reprotect((void *)pathname); sout(); return ret; } int creat(const char *pathname, mode_t mode) { sin(); char *npathname = dw_unprotect((void *)pathname); dw_check_access((void *)pathname, libc_strlen(npathname) + 1); int ret = libc_creat(npathname, mode); dw_reprotect((void *)pathname); sout(); return ret; } int access(const char *pathname, int mode) { sin(); char *npathname = dw_unprotect((void *)pathname); dw_check_access((void *)pathname, libc_strlen(npathname) + 1); int ret = libc_access(npathname, mode); dw_reprotect((void *)pathname); sout(); return ret; } char *getcwd(char *buf, size_t size) { sin(); dw_check_access((void *)buf, size); char *ret = libc_getcwd(dw_unprotect((void *)buf), size); dw_reprotect((void *)buf); sout(); if(ret == dw_untaint(buf)) return buf; return ret; } ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) { sin(); dw_check_access((void *)buf, buflen); ssize_t ret = libc_getrandom(dw_unprotect(buf), buflen, flags); dw_reprotect(buf); sout(); return ret; } int stat(const char *restrict pathname, struct stat *restrict statbuf) { sin(); char *npathname = dw_unprotect((void *)pathname); dw_check_access((void *)pathname, libc_strlen(npathname) + 1); dw_check_access((void *)statbuf, sizeof(struct stat)); int ret = libc_stat(npathname, (struct stat *)dw_unprotect((void *)statbuf)); dw_reprotect((void *)pathname); dw_reprotect((void *)statbuf); sout(); return ret; } int fstat(int fd, struct stat *statbuf) { sin(); dw_check_access((void *)statbuf, sizeof(struct stat)); int ret = libc_fstat(fd, (struct stat *)dw_unprotect(statbuf)); dw_reprotect(statbuf); sout(); return ret; } int lstat(const char *restrict pathname, struct stat *restrict statbuf) { sin(); char *npathname = dw_unprotect((void *)pathname); dw_check_access((void *)pathname, libc_strlen(npathname) + 1); dw_check_access((void *)statbuf, sizeof(struct stat)); int ret = libc_lstat(npathname, (struct stat *)dw_unprotect((void *)statbuf)); dw_reprotect((void *)pathname); dw_reprotect((void *)statbuf); sout(); return ret; } int fstatat(int dirfd, const char *restrict pathname, struct stat *restrict statbuf, int flags) { sin(); char *npathname = dw_unprotect((void *)pathname); dw_check_access((void *)pathname, libc_strlen(npathname) + 1); dw_check_access((void *)statbuf, sizeof(struct stat)); int ret = libc_fstatat(dirfd, npathname, (struct stat *)dw_unprotect((void *)statbuf), flags); dw_reprotect((void *)pathname); dw_reprotect((void *)statbuf); sout(); return ret; } size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { sin(); dw_check_access(ptr, size * nmemb); ssize_t ret = libc_fread(dw_unprotect(ptr), size, nmemb, stream); dw_reprotect(ptr); sout(); return ret; } size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { sin(); dw_check_access(ptr, size * nmemb); ssize_t ret = libc_fwrite((const void *)dw_unprotect(ptr), size, nmemb, stream); dw_reprotect(ptr); sout(); return ret; } ssize_t pread(int fd, void *buf, size_t count, off_t offset) { sin(); dw_check_access(buf, count); ssize_t ret = libc_pread(fd, dw_unprotect(buf), count, offset); dw_reprotect(buf); sout(); return ret; } ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset) { sin(); dw_check_access(buf, count); ssize_t ret = libc_pwrite(fd, (const void *)dw_unprotect(buf), count, offset); dw_reprotect(buf); sout(); return ret; } ssize_t read(int fd, void *buf, size_t count) { sin(); dw_check_access(buf, count); ssize_t ret = libc_read(fd, dw_unprotect(buf), count); dw_reprotect(buf); sout(); return ret; } ssize_t write(int fd, const void *buf, size_t count) { sin(); dw_check_access(buf, count); ssize_t ret = libc_write(fd, (const void *)dw_unprotect(buf), count); dw_reprotect(buf); sout(); return ret; } int statfs(const char *path, struct statfs *buf) { sin(); char *npath = dw_unprotect((void *)path); dw_check_access((void *)path, libc_strlen(npath) + 1); dw_check_access((void *)buf, sizeof(struct statfs)); int ret = libc_statfs(npath, (struct statfs *)dw_unprotect((void *)buf)); dw_reprotect((void *)path); dw_reprotect((void *)buf); sout(); return ret; } int fstatfs(int fd, struct statfs *buf) { sin(); dw_check_access((void *)buf, sizeof(struct statfs)); int ret = libc_fstatfs(fd, (struct statfs *)dw_unprotect((void *)buf)); dw_reprotect((void *)buf); sout(); return ret; } ssize_t getdents64(int fd, void *dirp, size_t count) { sin(); dw_check_access(dirp, count); ssize_t ret = libc_getdents64(fd, dw_unprotect(dirp), count); dw_reprotect(dirp); sout(); return ret; } DIR *opendir(const char *name) { sin(); char *nname = dw_unprotect((void *)name); dw_check_access((void *)name, libc_strlen(nname) + 1); DIR *ret = libc_opendir(nname); dw_reprotect(name); sout(); return ret; } int bcmp(const void *s1, const void *s2, size_t n) { sin(); dw_check_access(s1, n); dw_check_access(s2, n); int ret = libc_bcmp((const void *)dw_unprotect(s1), (const void *)dw_unprotect(s2), n); dw_reprotect(s1); dw_reprotect(s2); sout(); return ret; } void bcopy(const void *src, void *dest, size_t n) { sin(); dw_check_access(src, n); dw_check_access(dest, n); libc_bcopy((const void *)dw_unprotect(src), (void *)dw_unprotect(dest), n); dw_reprotect(src); dw_reprotect(dest); sout(); } void bzero(void *s, size_t n) { sin(); dw_check_access(s, n); libc_bzero((void *)dw_unprotect(s), n); dw_reprotect(s); sout(); } void *memccpy(void *dest, const void *src, int c, size_t n) { sin(); dw_check_access(dest, n); dw_check_access(src, n); void *ret = libc_memccpy((void *)dw_unprotect(dest), (const void *)dw_unprotect(src), c, n); dw_reprotect(dest); dw_reprotect(src); sout(); if(ret == NULL) return ret; return (void *)dw_retaint(ret, dest); } void *memchr(const void *s, int c, size_t n) { sin(); dw_check_access(s, n); void *ret = libc_memchr((const void *)dw_unprotect(s), c, n); dw_reprotect(s); sout(); if(ret == NULL) return ret; return (void *)dw_retaint(ret, s); } int memcmp(const void *s1, const void *s2, size_t n) { sin(); dw_check_access(s1, n); dw_check_access(s2, n); int ret = libc_memcmp((const void *)dw_unprotect(s1), (const void *)dw_unprotect(s2), n); dw_reprotect(s1); dw_reprotect(s2); sout(); return ret; } void *memcpy(void *dest, const void *src, size_t n) { sin(); dw_check_access(dest, n); dw_check_access(src, n); libc_memcpy((void *)dw_unprotect(dest), (const void *)dw_unprotect(src), n); dw_reprotect(dest); dw_reprotect(src); sout(); return dest; } void *__memcpy_chk(void *dest, const void *src, size_t len, size_t destlen) { sin(); dw_check_access(dest, destlen); dw_check_access(src, len); libc_memcpy_chk((void *)dw_unprotect(dest), (const void *)dw_unprotect(src), len, destlen); dw_reprotect(dest); dw_reprotect(src); sout(); return dest; } // void *memfrob(void *s, size_t n) { sin(); return libc_memfrob(void *s, size_t n); } void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { sin(); dw_check_access(haystack, haystacklen); dw_check_access(needle, needlelen); void *ret = libc_memmem((const void *)dw_unprotect(haystack), haystacklen, (const void *)dw_unprotect(needle), needlelen); dw_reprotect(haystack); dw_reprotect(needle); sout(); if(ret == NULL) return ret; return (void *)dw_retaint(ret, haystack); } void *memmove(void *dest, const void *src, size_t n) { sin(); dw_check_access(dest, n); dw_check_access(src, n); libc_memmove((void *)dw_unprotect(dest), (void *)dw_unprotect(src), n); dw_reprotect(dest); dw_reprotect(src); sout(); return dest; } void *mempcpy(void *restrict dest, const void *restrict src, size_t n) { sin(); dw_check_access(dest, n); dw_check_access(src, n); libc_mempcpy((void *)dw_unprotect(dest), (void *)dw_unprotect(src), n); dw_reprotect(dest); dw_reprotect(src); sout(); return dest; } void *memset(void *s, int c, size_t n) { sin(); dw_check_access(s, n); libc_memset((void *)dw_unprotect(s), c, n); dw_reprotect(s); sout(); return s; } char *strcpy(char *restrict dest, const char *src) { sin(); char *ndest = dw_unprotect((void *)dest); char *nsrc = dw_unprotect((void *)src); size_t len = libc_strlen(nsrc) + 1; dw_check_access(dest, len); dw_check_access(src, len); libc_strcpy(ndest, nsrc); dw_reprotect(dest); dw_reprotect(src); sout(); return dest;} char *strcat(char *restrict dest, const char *src) { sin(); char *ndest = dw_unprotect((void *)dest); char *nsrc = dw_unprotect((void *)src); size_t dst_len = libc_strlen(ndest); size_t src_len = libc_strlen(nsrc); dw_check_access(dest, dst_len + src_len + 1); dw_check_access(src, src_len + 1); libc_strcat(ndest, nsrc); dw_reprotect(dest); dw_reprotect(src); sout(); return dest;} char *strncpy(char *restrict dest, const char *restrict src, size_t n) { sin(); char *nsrc = dw_unprotect((void *)src); size_t len = libc_strlen(nsrc) + 1; dw_check_access(dest, n); dw_check_access(src, len < n ? len : n); libc_strncpy(dw_unprotect(dest), nsrc, n); dw_reprotect(dest); dw_reprotect(src); sout(); return dest; } wchar_t *wmemmove(wchar_t *dest, const wchar_t *src, size_t n) { sin(); dw_check_access(dest, n * sizeof(wchar_t)); dw_check_access(src, n * sizeof(wchar_t)); libc_wmemmove((wchar_t *)dw_unprotect(dest), (wchar_t *)dw_unprotect(src), n); dw_reprotect(dest); dw_reprotect(src); sout(); return dest; } wchar_t *wmempcpy(wchar_t *restrict dest, const wchar_t *restrict src, size_t n) { sin(); dw_check_access(dest, n * sizeof(wchar_t)); dw_check_access(src, n * sizeof(wchar_t)); wchar_t *ret = libc_wmempcpy((wchar_t *)dw_unprotect(dest), (wchar_t *)dw_unprotect(src), n); dw_reprotect(dest); dw_reprotect(src); sout(); return (wchar_t *)dw_retaint(ret, dest); } wchar_t *wmemcpy(wchar_t *restrict dest, const wchar_t *restrict src, size_t n) { sin(); dw_check_access(dest, n * sizeof(wchar_t)); dw_check_access(src, n * sizeof(wchar_t)); libc_wmemcpy((wchar_t *)dw_unprotect(dest), (wchar_t *)dw_unprotect(src), n); dw_reprotect(dest); dw_reprotect(src); sout(); return dest; } char *gettext (const char * msgid) { sin(); char *nmsgid = dw_unprotect((void *)msgid); dw_check_access((void *)msgid, libc_strlen(nmsgid) + 1); char *ret = libc_gettext(nmsgid); dw_reprotect(msgid); sout(); if(ret == nmsgid) return (char *)msgid; else return ret; } char *dgettext (const char * domainname, const char * msgid) { sin(); char *ndomainname = dw_unprotect((void *)domainname); char *nmsgid = dw_unprotect((void *)msgid); dw_check_access((void *)domainname, libc_strlen(ndomainname) + 1); dw_check_access((void *)msgid, libc_strlen(nmsgid) + 1); char *ret = libc_dgettext(ndomainname, nmsgid); dw_reprotect(domainname); dw_reprotect(msgid); sout(); if(ret == nmsgid) return (char *)msgid; else return ret; } char *dcgettext (const char * domainname, const char * msgid, int category) { sin(); char *ndomainname = dw_unprotect((void *)domainname); char *nmsgid = dw_unprotect((void *)msgid); dw_check_access((void *)domainname, libc_strlen(ndomainname) + 1); dw_check_access((void *)msgid, libc_strlen(nmsgid) + 1); char *ret = __dcgettext (ndomainname, nmsgid, category); dw_reprotect(domainname); dw_reprotect(msgid); sout(); if(ret == nmsgid) return (char *)msgid; else return ret; } char *ngettext(const char *msgid, const char *msgid_plural, unsigned long int n) { sin(); char *nmsgid = dw_unprotect((void *)msgid); char *nmsgid_plural = dw_unprotect((void *)msgid_plural); dw_check_access((void *)msgid, libc_strlen(nmsgid) + 1); dw_check_access((void *)msgid_plural, libc_strlen(nmsgid_plural) + 1); char *ret = libc_ngettext(nmsgid, nmsgid_plural, n); dw_reprotect(msgid); dw_reprotect(msgid_plural); sout(); if(ret == nmsgid) return (char *)msgid; else if(ret == nmsgid_plural) return (char *)msgid_plural; else return ret; } char *dcngettext(const char *domainname, const char *msgid, const char *msgid_plural, unsigned long int n, int category) { sin(); char *ndomainname = dw_unprotect((void *)domainname); char *nmsgid = dw_unprotect((void *)msgid); char *nmsgid_plural = dw_unprotect((void *)msgid_plural); dw_check_access((void *)domainname, libc_strlen(ndomainname) + 1); dw_check_access((void *)msgid, libc_strlen(nmsgid) + 1); dw_check_access((void *)msgid_plural, libc_strlen(nmsgid_plural) + 1); char *ret = libc_dcngettext(ndomainname, nmsgid, nmsgid_plural, n, category); dw_reprotect(domainname); dw_reprotect(msgid); dw_reprotect(msgid_plural); sout(); if(ret == nmsgid) return (char *)msgid; else if(ret == nmsgid_plural) return (char *)msgid_plural; else return ret; } char *setlocale(int category, const char *locale) { sin(); char *nlocale = dw_unprotect((void *)locale); dw_check_access((void *)locale, libc_strlen(nlocale) + 1); char *ret = libc_setlocale(category, nlocale); dw_reprotect(locale); sout(); return ret; } char *textdomain(const char * domainname) { sin(); char *ndomainname = dw_unprotect((void *)domainname); dw_check_access((void *)domainname, libc_strlen(ndomainname) + 1); char *ret = libc_textdomain(ndomainname); dw_reprotect(domainname); sout(); return ret; } int execve(const char *pathname, char *const argv[], char *const envp[]) { sin(); char *npathname = dw_unprotect((void *)pathname); dw_check_access((void *)pathname, libc_strlen(npathname) + 1); dw_check_access((void *)argv, arglen(argv)); dw_check_access((void *)envp, arglen(envp)); int ret = libc_execve(npathname, dw_unprotect(argv), dw_unprotect(envp)); dw_reprotect(pathname); dw_reprotect(argv); dw_reprotect(envp); sout(); return ret; } int execv(const char *pathname, char *const argv[]) { sin(); char *npathname = dw_unprotect((void *)pathname); dw_check_access((void *)pathname, libc_strlen(npathname) + 1); dw_check_access((void *)argv, arglen(argv)); int ret = libc_execv(npathname, dw_unprotect(argv)); dw_reprotect(pathname); dw_reprotect(argv); sout(); return ret; } int execvp(const char *file, char *const argv[]) { sin(); char *nfile = dw_unprotect((void *)file); dw_check_access((void *)file, libc_strlen(nfile) + 1); dw_check_access((void *)argv, arglen(argv)); int ret = libc_execvp(nfile, dw_unprotect(argv)); dw_reprotect(file); dw_reprotect(argv); sout(); return ret; } int execvpe(const char *file, char *const argv[], char *const envp[]) { sin(); char *nfile = dw_unprotect((void *)file); dw_check_access((void *)file, libc_strlen(nfile) + 1); dw_check_access((void *)argv, arglen(argv)); dw_check_access((void *)envp, arglen(envp)); int ret = libc_execvpe(nfile, dw_unprotect(argv), dw_unprotect(envp)); dw_reprotect(file); dw_reprotect(argv); dw_reprotect(envp); sout(); return ret; }