From 5d9f7e14bf5c68736fd4395caac45416796fed3d Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 18:19:06 -0600 Subject: backtrace: Add semicolons after call to function-like macros This duplicates the semicolon at the end of the macro, but it prevents clang-format from getting confused. This is only temporary until the macro is updated in a later commit. Signed-off-by: Samuel Holland --- libgcompat/backtrace.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/libgcompat/backtrace.c b/libgcompat/backtrace.c index 2ceb334..4ef0f88 100644 --- a/libgcompat/backtrace.c +++ b/libgcompat/backtrace.c @@ -9,16 +9,16 @@ int backtrace(void **addr_buf, int size) { void *curr; - _frame_level(addr_buf, curr, 0, size) - _frame_level(addr_buf, curr, 1, size) - _frame_level(addr_buf, curr, 2, size) - _frame_level(addr_buf, curr, 3, size) - _frame_level(addr_buf, curr, 4, size) - _frame_level(addr_buf, curr, 5, size) - _frame_level(addr_buf, curr, 6, size) - _frame_level(addr_buf, curr, 7, size) - _frame_level(addr_buf, curr, 8, size) - _frame_level(addr_buf, curr, 9, size) + _frame_level(addr_buf, curr, 0, size); + _frame_level(addr_buf, curr, 1, size); + _frame_level(addr_buf, curr, 2, size); + _frame_level(addr_buf, curr, 3, size); + _frame_level(addr_buf, curr, 4, size); + _frame_level(addr_buf, curr, 5, size); + _frame_level(addr_buf, curr, 6, size); + _frame_level(addr_buf, curr, 7, size); + _frame_level(addr_buf, curr, 8, size); + _frame_level(addr_buf, curr, 9, size); return 9; } -- cgit v1.2.3-60-g2f50 From 28748009c0dc553e2fe5e6253e7615cf89d2b7ef Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 18:21:13 -0600 Subject: Add clang-format configuration and Makefile rule The settings here are based on the current code style documentation. Signed-off-by: Samuel Holland --- .clang-format | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Makefile | 5 +++++ 2 files changed, 57 insertions(+) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..05db5a1 --- /dev/null +++ b/.clang-format @@ -0,0 +1,52 @@ +--- +# for clang-format 4.0.0 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: false +AlignOperands: false +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +BinPackArguments: true +BinPackParameters: true +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeBraces: WebKit +BreakBeforeTernaryOperators: true +BreakStringLiterals: true +ColumnLimit: 80 +Cpp11BracedListStyle: false +IncludeCategories: + - Priority: 1 + Regex: '^<' + - Priority: 2 + Regex: '^"' +IndentCaseLabels: false +IndentWidth: 8 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: false +Language: Cpp +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: true +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 8 +UseTab: ForIndentation +... diff --git a/Makefile b/Makefile index c595290..6c532fd 100644 --- a/Makefile +++ b/Makefile @@ -44,6 +44,11 @@ ${LOADER_NAME}: ${LOADER_OBJ} clean: rm -f libgcompat/*.o loader/*.o ${LIBGCOMPAT_NAME} ${LOADER_NAME} +format: + clang-format -i ${LIBGCOMPAT_SRC} ${LOADER_SRC} + install: all install -D -m755 ${LIBGCOMPAT_NAME} ${DESTDIR}/${LIBGCOMPAT_PATH} install -D -m755 ${LOADER_NAME} ${DESTDIR}/${LOADER_PATH} + +.PHONY: all clean format install -- cgit v1.2.3-60-g2f50 From d40369b0e09e4e2228ebff305067ec2d99220848 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 18:28:35 -0600 Subject: global: Format the code consistently * Apply clang-format. * Change all comments to the same style. * Add braces as dictated by the coding style guidelines. Signed-off-by: Samuel Holland --- libgcompat/backtrace.c | 25 ++++++++++++++++--------- libgcompat/dlmopen.c | 15 +++++++-------- libgcompat/dlvsym.c | 11 +++++------ libgcompat/gnulib.c | 2 +- libgcompat/malloc.c | 44 +++++++++++++++++++++++--------------------- libgcompat/math.c | 2 +- libgcompat/pthread.c | 16 ++++++++++------ libgcompat/pwd.c | 30 +++++++++++++++++++----------- libgcompat/resolv.c | 13 ++++++++----- libgcompat/resource.c | 15 +++++++-------- libgcompat/stdio.c | 31 +++++++++++++------------------ libgcompat/stdlib.c | 4 ++-- libgcompat/string.c | 25 ++++++++++++++----------- libgcompat/sysctl.c | 22 ++++++++++------------ libgcompat/ucontext.c | 2 +- libgcompat/version.c | 6 ++++-- loader/loader.c | 7 ++++--- 17 files changed, 145 insertions(+), 125 deletions(-) diff --git a/libgcompat/backtrace.c b/libgcompat/backtrace.c index 4ef0f88..c8ded8b 100644 --- a/libgcompat/backtrace.c +++ b/libgcompat/backtrace.c @@ -2,9 +2,16 @@ #include #include -#define _frame_level(addr_buf, curr, frame, size) \ - if(__builtin_frame_address(frame) != NULL && (curr = __builtin_return_address(frame)) > 0x1000 && frame <= size) addr_buf[frame] = curr; \ - else return size; +#define _frame_level(addr_buf, curr, frame, size) \ + do { \ + if (__builtin_frame_address(frame) != NULL \ + && (curr = __builtin_return_address(frame)) > 0x1000 \ + && frame <= size) { \ + addr_buf[frame] = curr; \ + } else { \ + return size; \ + } \ + } while (0) int backtrace(void **addr_buf, int size) { @@ -22,18 +29,18 @@ int backtrace(void **addr_buf, int size) return 9; } -char **backtrace_symbols(void * const *addr_buf, int size) +char **backtrace_symbols(void *const *addr_buf, int size) { char **result = calloc(sizeof(char *), size); - if(result == NULL) return result; + if (result == NULL) { + return result; + } - for(int next = 0; next < size; next++) - { + for (int next = 0; next < size; next++) { Dl_info info; int err = dladdr(addr_buf[next], &info); - if(err != 0) - { + if (err != 0) { result[next] = "??:0"; } else { result[next] = info.dli_sname; diff --git a/libgcompat/dlmopen.c b/libgcompat/dlmopen.c index fecb29c..4584680 100644 --- a/libgcompat/dlmopen.c +++ b/libgcompat/dlmopen.c @@ -1,15 +1,14 @@ -#include // dlopen -#include // fprintf -#include // getenv +#include /* dlopen */ +#include /* fprintf */ +#include /* getenv */ void *dlmopen(long lmid, const char *pathname, int mode) { - if(getenv("GLIBC_FAKE_DEBUG")) - { - fprintf(stderr, "library %s was requested to load in %ld namespace", - pathname, lmid); + if (getenv("GLIBC_FAKE_DEBUG")) { + fprintf(stderr, + "library %s was requested to load in %ld namespace", + pathname, lmid); } return dlopen(pathname, mode); } - diff --git a/libgcompat/dlvsym.c b/libgcompat/dlvsym.c index 3d744ea..0aba245 100644 --- a/libgcompat/dlvsym.c +++ b/libgcompat/dlvsym.c @@ -1,13 +1,12 @@ -#include // dlsym -#include // fprintf -#include // getenv +#include /* dlsym */ +#include /* fprintf */ +#include /* getenv */ void *dlvsym(void *handle, char *symbol, char *version) { - if(getenv("GLIBC_FAKE_DEBUG")) - { + if (getenv("GLIBC_FAKE_DEBUG")) { fprintf(stderr, "symbol %s with version %s is being redirected", - symbol, version); + symbol, version); } return dlsym(handle, symbol); diff --git a/libgcompat/gnulib.c b/libgcompat/gnulib.c index 08544fc..e0ee953 100644 --- a/libgcompat/gnulib.c +++ b/libgcompat/gnulib.c @@ -4,5 +4,5 @@ unsigned long __fdelt_chk(unsigned long size) { assert(size < FD_SETSIZE); - return size / (sizeof(unsigned long)<<3); + return size / (sizeof(unsigned long) << 3); } diff --git a/libgcompat/malloc.c b/libgcompat/malloc.c index 7478834..db85d8d 100644 --- a/libgcompat/malloc.c +++ b/libgcompat/malloc.c @@ -1,16 +1,16 @@ /* struct mallinfo pulled from mallinfo.3: * * Copyright (c) 2012 by Michael Kerrisk - * + * * Permission is granted to make and distribute verbatim copies of this * manual provided the copyright notice and this permission notice are * preserved on all copies. - * + * * Permission is granted to copy and distribute modified versions of this * manual under the conditions for verbatim copying, provided that the * entire resulting derived work is distributed under the terms of a * permission notice identical to this one. - * + * * Since the Linux kernel and libraries are constantly changing, this * manual page may be incorrect or out-of-date. The author(s) assume no * responsibility for errors or omissions, or for damages resulting from @@ -18,26 +18,26 @@ * have taken the same level of care in the production of this manual, * which is licensed free of charge, as they might when working * professionally. - * + * * Formatted or processed versions of this manual, if unaccompanied by * the source, must acknowledge the copyright and authors of this work. */ -#include /* memset */ -#include /* {m,c,re}alloc, free */ -#include /* memalign */ +#include /* memalign */ +#include /* {m,c,re}alloc, free */ +#include /* memset */ struct mallinfo { - int arena; /* Non-mmapped space allocated (bytes) */ - int ordblks; /* Number of free chunks */ - int smblks; /* Number of free fastbin blocks */ - int hblks; /* Number of mmapped regions */ - int hblkhd; /* Space allocated in mmapped regions (bytes) */ - int usmblks; /* Maximum total allocated space (bytes) */ - int fsmblks; /* Space in freed fastbin blocks (bytes) */ - int uordblks; /* Total allocated space (bytes) */ - int fordblks; /* Total free space (bytes) */ - int keepcost; /* Top-most, releasable space (bytes) */ + int arena; /* Non-mmapped space allocated (bytes) */ + int ordblks; /* Number of free chunks */ + int smblks; /* Number of free fastbin blocks */ + int hblks; /* Number of mmapped regions */ + int hblkhd; /* Space allocated in mmapped regions (bytes) */ + int usmblks; /* Maximum total allocated space (bytes) */ + int fsmblks; /* Space in freed fastbin blocks (bytes) */ + int uordblks; /* Total allocated space (bytes) */ + int fordblks; /* Total free space (bytes) */ + int keepcost; /* Top-most, releasable space (bytes) */ }; struct mallinfo mallinfo(void) @@ -72,8 +72,10 @@ void *__libc_memalign(size_t align, size_t len) return memalign(align, len); } -extern __typeof(__libc_malloc) __malloc __attribute__((weak, alias("__libc_malloc"))); -extern __typeof(__libc_calloc) __calloc __attribute__((weak, alias("__libc_calloc"))); -extern __typeof(__libc_realloc) __realloc __attribute__((weak, alias("__libc_realloc"))); +extern __typeof(__libc_malloc) __malloc + __attribute__((weak, alias("__libc_malloc"))); +extern __typeof(__libc_calloc) __calloc + __attribute__((weak, alias("__libc_calloc"))); +extern __typeof(__libc_realloc) __realloc + __attribute__((weak, alias("__libc_realloc"))); extern __typeof(__libc_free) __free __attribute__((weak, alias("__libc_free"))); - diff --git a/libgcompat/math.c b/libgcompat/math.c index 2c793e4..42ed032 100644 --- a/libgcompat/math.c +++ b/libgcompat/math.c @@ -1,4 +1,4 @@ -#include // isinf, isnan +#include /* isinf, isnan */ int __isinff(float number) { diff --git a/libgcompat/pthread.c b/libgcompat/pthread.c index ddfc570..52daceb 100644 --- a/libgcompat/pthread.c +++ b/libgcompat/pthread.c @@ -1,15 +1,19 @@ #include -int __register_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) { +int __register_atfork(void (*prepare)(void), void (*parent)(void), + void (*child)(void)) +{ return pthread_atfork(prepare, parent, child); } -int register_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) __attribute__ ((weak, alias("__register_atfork"))); +int register_atfork(void (*prepare)(void), void (*parent)(void), + void (*child)(void)) + __attribute__((weak, alias("__register_atfork"))); - -void __pthread_register_cancel(void *buf) { +void __pthread_register_cancel(void *buf) +{ } - -void __pthread_unregister_cancel(void *buf) { +void __pthread_unregister_cancel(void *buf) +{ } diff --git a/libgcompat/pwd.c b/libgcompat/pwd.c index 2e09aea..50d8da0 100644 --- a/libgcompat/pwd.c +++ b/libgcompat/pwd.c @@ -1,23 +1,27 @@ /* some musl versions incorrectly mark fgetpwent() as a GNU extension */ #define _GNU_SOURCE -#include #include #include +#include #include - -int getpwent_r(struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp) { +int getpwent_r(struct passwd *pwbuf, char *buf, size_t buflen, + struct passwd **pwbufp) +{ struct passwd *pwd; - if (pwbufp == NULL || pwbuf == NULL) + if (pwbufp == NULL || pwbuf == NULL) { return ERANGE; + } - if (buflen < 1) + if (buflen < 1) { return ERANGE; + } - if (buf != NULL) + if (buf != NULL) { *buf = '\0'; + } if ((pwd = getpwent()) == NULL) { *pwbufp = NULL; @@ -30,18 +34,22 @@ int getpwent_r(struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **p return 0; } - -int fgetpwent_r(FILE *filp, struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp) { +int fgetpwent_r(FILE *filp, struct passwd *pwbuf, char *buf, size_t buflen, + struct passwd **pwbufp) +{ struct passwd *pwd; - if (pwbufp == NULL || pwbuf == NULL) + if (pwbufp == NULL || pwbuf == NULL) { return ERANGE; + } - if (buflen < 1) + if (buflen < 1) { return ERANGE; + } - if (buf != NULL) + if (buf != NULL) { *buf = '\0'; + } if ((pwd = fgetpwent(filp)) == NULL) { *pwbufp = NULL; diff --git a/libgcompat/resolv.c b/libgcompat/resolv.c index 9ded8c9..3566dcd 100644 --- a/libgcompat/resolv.c +++ b/libgcompat/resolv.c @@ -6,8 +6,8 @@ * Note: res_init() is actually deprecated according to * http://docs.oracle.com/cd/E36784_01/html/E36875/res-nclose-3resolv.html **************************************************************************/ -#include /* memcpy, memset */ -#include /* res_state */ +#include /* res_state */ +#include /* memcpy, memset */ static inline int res_ninit(res_state statp) { @@ -20,13 +20,16 @@ static inline int res_ninit(res_state statp) static inline int res_nclose(res_state statp) { - if (!statp) + if (!statp) { return -1; + } if (statp != &_res) { memset(statp, 0, sizeof(*statp)); } return 0; } -extern __typeof(res_ninit) __res_ninit __attribute__((weak, alias("res_ninit"))); -extern __typeof(res_nclose) __res_nclose __attribute__((weak, alias("res_nclose"))); +extern __typeof(res_ninit) __res_ninit + __attribute__((weak, alias("res_ninit"))); +extern __typeof(res_nclose) __res_nclose + __attribute__((weak, alias("res_nclose"))); diff --git a/libgcompat/resource.c b/libgcompat/resource.c index 029b31e..4a7ab4e 100644 --- a/libgcompat/resource.c +++ b/libgcompat/resource.c @@ -1,8 +1,8 @@ -#include /* setrlimit, struct rlimit */ -#include /* assert */ -#include /* dlsym, RTLD_NEXT */ -#include /* NULL */ -#include /* memcpy */ +#include /* assert */ +#include /* dlsym, RTLD_NEXT */ +#include /* NULL */ +#include /* memcpy */ +#include /* setrlimit, struct rlimit */ /* Sigh. * Valve compiled Steam against the glibc2.2 version of setrlimit. @@ -11,7 +11,7 @@ * So, what you have to do is: if you want to run steam with this gcompat, * ensure you compile *without* defining NO_BROKEN_SHADOW_SETRLIMIT. * If you do *not* want to run steam with this gcompat, define it. - * + * * The only problem with enabling this all the time is that if a binary * really does need a ulimit to be 0 for any reason (such as coredumps), it * very obviously won't work here. @@ -27,8 +27,7 @@ int setrlimit(int resource, const struct rlimit *rlim) memcpy(&my_rlim, rlim, sizeof(struct rlimit)); - if(my_rlim.rlim_cur == 0) - { + if (my_rlim.rlim_cur == 0) { my_rlim.rlim_cur = my_rlim.rlim_max; } diff --git a/libgcompat/stdio.c b/libgcompat/stdio.c index 89bd677..a44d94c 100644 --- a/libgcompat/stdio.c +++ b/libgcompat/stdio.c @@ -15,8 +15,7 @@ int __printf_chk(int flag, const char *format, ...) va_list argp; int result; - if(flag > 0) - { + if (flag > 0) { assert(format != NULL); } @@ -32,8 +31,7 @@ int __fprintf_chk(FILE *stream, int flag, const char *format, ...) va_list argp; int result; - if(flag > 0) - { + if (flag > 0) { assert(stream != NULL); assert(format != NULL); } @@ -59,13 +57,13 @@ int __sprintf_chk(char *str, int flag, size_t strlen, const char *format, ...) return result; } -int __snprintf_chk(char *str, size_t size, int flag, size_t strlen, const char *format, ...) +int __snprintf_chk(char *str, size_t size, int flag, size_t strlen, + const char *format, ...) { va_list argp; int result; - if(flag > 0) - { + if (flag > 0) { assert(format != NULL); } // must always be done per LFS @@ -78,13 +76,13 @@ int __snprintf_chk(char *str, size_t size, int flag, size_t strlen, const char * return result; } -int __swprintf_chk(wchar_t *wcs, size_t maxlen, int flag, size_t wcslen, const wchar_t *format, ...) +int __swprintf_chk(wchar_t *wcs, size_t maxlen, int flag, size_t wcslen, + const wchar_t *format, ...) { va_list argp; int result; - if(flag > 0) - { + if (flag > 0) { assert(format != NULL); } // must always be done per LFS @@ -99,8 +97,7 @@ int __swprintf_chk(wchar_t *wcs, size_t maxlen, int flag, size_t wcslen, const w int __vasprintf_chk(char **strp, int flag, const char *fmt, va_list ap) { - if(flag > 0) - { + if (flag > 0) { assert(strp != NULL); assert(fmt != NULL); } @@ -109,22 +106,20 @@ int __vasprintf_chk(char **strp, int flag, const char *fmt, va_list ap) int __vfprintf_chk(FILE *stream, int flag, const char *format, va_list ap) { - if(flag > 0) - { + if (flag > 0) { assert(stream != NULL); assert(format != NULL); } return vfprintf(stream, format, ap); } -int __vsnprintf_chk(char *str, size_t size, int flag, size_t strlen, const char *format, va_list ap) +int __vsnprintf_chk(char *str, size_t size, int flag, size_t strlen, + const char *format, va_list ap) { - if(flag > 0) - { + if (flag > 0) { assert(format != NULL); } // must always be done per LFS assert(size <= strlen); return vsnprintf(str, size, format, ap); } - diff --git a/libgcompat/stdlib.c b/libgcompat/stdlib.c index 30c904e..6783615 100644 --- a/libgcompat/stdlib.c +++ b/libgcompat/stdlib.c @@ -1,5 +1,5 @@ -#include // assert -#include // strtod +#include /* assert */ +#include /* strtod */ char *__realpath_chk(const char *path, char *resolved_path) { diff --git a/libgcompat/string.c b/libgcompat/string.c index 9045d5d..60f61fc 100644 --- a/libgcompat/string.c +++ b/libgcompat/string.c @@ -1,6 +1,6 @@ -#include /* assert */ -#include /* memcpy, strcpy, strncat, strndup */ -#include /* strto[u?]ll */ +#include /* assert */ +#include /* strto[u?]ll */ +#include /* memcpy, strcpy, strncat, strndup */ /* "Checked" memcpy */ void *__memcpy_chk(void *dest, const void *src, size_t len, size_t destlen) @@ -8,8 +8,7 @@ void *__memcpy_chk(void *dest, const void *src, size_t len, size_t destlen) assert(dest != NULL); assert(src != NULL); assert(len <= destlen); - if(src < dest) - { + if (src < dest) { assert(!(src + len >= dest)); } else { assert(!(dest + len >= src)); @@ -64,12 +63,14 @@ char *__strndup(const char *str, size_t count) void *rawmemchr(const void *s, int c) { const unsigned char *haystack = s; - unsigned char needle = (unsigned char)c; - while(*haystack++ != needle); - return (void *)haystack; + unsigned char needle = (unsigned char) c; + while (*haystack++ != needle) + ; + return (void *) haystack; } -extern __typeof(rawmemchr) __rawmemchr __attribute__((weak, alias("rawmemchr"))); +extern __typeof(rawmemchr) __rawmemchr + __attribute__((weak, alias("rawmemchr"))); /* Another useless __ alias */ char *__strtok_r(char *str, const char *delim, char **saveptr) @@ -85,12 +86,14 @@ char *__strsep_g(char **stringp, const char *delim) } /* Some day, when musl supports LC_NUMERIC, we can probably remove these */ -long long int strtoll_l(const char *nptr, char **endptr, int base, locale_t locale) +long long int strtoll_l(const char *nptr, char **endptr, int base, + locale_t locale) { return strtoll(nptr, endptr, base); } -unsigned long long int strtoull_l(const char *nptr, char **endptr, int base, locale_t locale) +unsigned long long int strtoull_l(const char *nptr, char **endptr, int base, + locale_t locale) { return strtoull(nptr, endptr, base); } diff --git a/libgcompat/sysctl.c b/libgcompat/sysctl.c index a14c2b8..e7218c1 100644 --- a/libgcompat/sysctl.c +++ b/libgcompat/sysctl.c @@ -1,6 +1,5 @@ -#include /* size_t */ #include - +#include /* size_t */ #ifdef SYS__sysctl @@ -13,16 +12,15 @@ struct __sysctl_args { size_t newlen; }; - -int sysctl (int *name, int nlen, void *oldval, size_t *oldlenp, void *newval, size_t newlen) { - struct __sysctl_args args = { - .name = name, - .nlen = nlen, - .oldval = oldval, - .oldlenp = oldlenp, - .newval = newval, - .newlen = newlen - }; +int sysctl(int *name, int nlen, void *oldval, size_t *oldlenp, void *newval, + size_t newlen) +{ + struct __sysctl_args args = { .name = name, + .nlen = nlen, + .oldval = oldval, + .oldlenp = oldlenp, + .newval = newval, + .newlen = newlen }; return syscall(SYS__sysctl, &args); } diff --git a/libgcompat/ucontext.c b/libgcompat/ucontext.c index 2d6006e..4827263 100644 --- a/libgcompat/ucontext.c +++ b/libgcompat/ucontext.c @@ -1,4 +1,4 @@ -#include /* errno, ENOSYS */ +#include /* errno, ENOSYS */ int getcontext(void *ucp) { diff --git a/libgcompat/version.c b/libgcompat/version.c index 63146f8..99c2c8c 100644 --- a/libgcompat/version.c +++ b/libgcompat/version.c @@ -1,9 +1,11 @@ -#include // getenv +#include /* getenv */ const char *gnu_get_libc_version(void) { char *ver = getenv("GLIBC_FAKE_VERSION"); - if(ver == NULL) ver = "2.8"; + if (ver == NULL) { + ver = "2.8"; + } return ver; } diff --git a/loader/loader.c b/loader/loader.c index f2942a4..979937f 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -10,14 +10,14 @@ * from the use of this software. */ +#include #include #include #include #include -#include #ifndef PATH_MAX -#define PATH_MAX 16384 +#define PATH_MAX 16384 #endif #ifndef LINKER @@ -28,7 +28,8 @@ #error LIBGCOMPAT must be defined #endif -int main(int argc, char *argv[], char *envp[]) { +int main(int argc, char *argv[], char *envp[]) +{ size_t i = 0; char target[PATH_MAX]; char **new_argv = calloc(sizeof(char *), argc + 5); -- cgit v1.2.3-60-g2f50 From dfafb0735f09d65a392d03a2d1ad3d0b934981da Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 18:40:59 -0600 Subject: libgcompat: Add and use a macro for defining symbol aliases * Prefer providing the underscore-prefixed symbol as the strong definition. * Do not use a weak alias if the alias is also underscore-prefixed. * Make libgcompat objects depend on the new header. [NOTE: I originally took the weak_alias macro from musl's libc.h, but it's trivial and the same pattern already in use. If desired, I can add the musl copyright notice.] Signed-off-by: Samuel Holland --- Makefile | 4 ++++ libgcompat/alias.h | 9 +++++++++ libgcompat/malloc.c | 14 ++++++-------- libgcompat/math.c | 11 ++++++----- libgcompat/pthread.c | 7 +++---- libgcompat/resolv.c | 13 ++++++------- libgcompat/string.c | 8 ++++---- 7 files changed, 38 insertions(+), 28 deletions(-) create mode 100644 libgcompat/alias.h diff --git a/Makefile b/Makefile index 6c532fd..b941dcf 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,5 @@ +LIBGCOMPAT_INCLUDE = \ + libgcompat/alias.h LIBGCOMPAT_SRC = \ libgcompat/backtrace.c \ libgcompat/dlmopen.c \ @@ -33,6 +35,8 @@ ${LIBGCOMPAT_NAME}: ${LIBGCOMPAT_OBJ} $(CC) -o ${LIBGCOMPAT_NAME} -Wl,-soname,${LIBGCOMPAT_NAME} \ -shared ${LIBGCOMPAT_OBJ} +${LIBGCOMPAT_OBJ}: ${LIBGCOMPAT_INCLUDE} + ${LOADER_NAME}: ${LOADER_OBJ} $(CC) -o ${LOADER_NAME} -fPIE -static ${LOADER_OBJ} diff --git a/libgcompat/alias.h b/libgcompat/alias.h new file mode 100644 index 0000000..3f54672 --- /dev/null +++ b/libgcompat/alias.h @@ -0,0 +1,9 @@ +#ifndef _ALIAS_H_ +#define _ALIAS_H_ + +#define alias(old, new) \ + extern __typeof(old) new __attribute__((__alias__(#old))) +#define weak_alias(old, new) \ + extern __typeof(old) new __attribute__((weak, __alias__(#old))) + +#endif /* _ALIAS_H_ */ diff --git a/libgcompat/malloc.c b/libgcompat/malloc.c index db85d8d..dc9d25e 100644 --- a/libgcompat/malloc.c +++ b/libgcompat/malloc.c @@ -27,6 +27,8 @@ #include /* {m,c,re}alloc, free */ #include /* memset */ +#include "alias.h" /* alias */ + struct mallinfo { int arena; /* Non-mmapped space allocated (bytes) */ int ordblks; /* Number of free chunks */ @@ -51,31 +53,27 @@ void *__libc_malloc(size_t size) { return malloc(size); } +alias(__libc_malloc, __malloc); void __libc_free(void *ptr) { return free(ptr); } +alias(__libc_free, __free); void *__libc_calloc(size_t nmemb, size_t size) { return calloc(nmemb, size); } +alias(__libc_calloc, __calloc); void *__libc_realloc(void *ptr, size_t size) { return realloc(ptr, size); } +alias(__libc_realloc, __realloc); void *__libc_memalign(size_t align, size_t len) { return memalign(align, len); } - -extern __typeof(__libc_malloc) __malloc - __attribute__((weak, alias("__libc_malloc"))); -extern __typeof(__libc_calloc) __calloc - __attribute__((weak, alias("__libc_calloc"))); -extern __typeof(__libc_realloc) __realloc - __attribute__((weak, alias("__libc_realloc"))); -extern __typeof(__libc_free) __free __attribute__((weak, alias("__libc_free"))); diff --git a/libgcompat/math.c b/libgcompat/math.c index 42ed032..2982116 100644 --- a/libgcompat/math.c +++ b/libgcompat/math.c @@ -1,26 +1,27 @@ #include /* isinf, isnan */ +#include "alias.h" /* weak_alias */ + int __isinff(float number) { return isinf(number); } +weak_alias(__isinff, isinff); int __isinf(double number) { return isinf(number); } +weak_alias(__isinf, isinf); int __isnanf(float number) { return isnan(number); } +weak_alias(__isnanf, isnanf); int __isnan(double number) { return isnan(number); } - -extern __typeof(__isnanf) isnanf __attribute__((weak, alias("__isnanf"))); -extern __typeof(__isnan) isnan __attribute__((weak, alias("__isnan"))); -extern __typeof(__isinff) isinff __attribute__((weak, alias("__isinff"))); -extern __typeof(__isinf) isinf __attribute__((weak, alias("__isinf"))); +weak_alias(__isnan, isnan); diff --git a/libgcompat/pthread.c b/libgcompat/pthread.c index 52daceb..9333554 100644 --- a/libgcompat/pthread.c +++ b/libgcompat/pthread.c @@ -1,14 +1,13 @@ #include +#include "alias.h" /* weak_alias */ + int __register_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) { return pthread_atfork(prepare, parent, child); } - -int register_atfork(void (*prepare)(void), void (*parent)(void), - void (*child)(void)) - __attribute__((weak, alias("__register_atfork"))); +weak_alias(__register_atfork, register_atfork); void __pthread_register_cancel(void *buf) { diff --git a/libgcompat/resolv.c b/libgcompat/resolv.c index 3566dcd..7ad984f 100644 --- a/libgcompat/resolv.c +++ b/libgcompat/resolv.c @@ -9,7 +9,9 @@ #include /* res_state */ #include /* memcpy, memset */ -static inline int res_ninit(res_state statp) +#include "alias.h" /* weak_alias */ + +static inline int __res_ninit(res_state statp) { int rc = res_init(); if (statp != &_res) { @@ -17,8 +19,9 @@ static inline int res_ninit(res_state statp) } return rc; } +weak_alias(__res_ninit, res_ninit); -static inline int res_nclose(res_state statp) +static inline int __res_nclose(res_state statp) { if (!statp) { return -1; @@ -28,8 +31,4 @@ static inline int res_nclose(res_state statp) } return 0; } - -extern __typeof(res_ninit) __res_ninit - __attribute__((weak, alias("res_ninit"))); -extern __typeof(res_nclose) __res_nclose - __attribute__((weak, alias("res_nclose"))); +weak_alias(__res_nclose, res_nclose); diff --git a/libgcompat/string.c b/libgcompat/string.c index 60f61fc..7ca0bf6 100644 --- a/libgcompat/string.c +++ b/libgcompat/string.c @@ -2,6 +2,8 @@ #include /* strto[u?]ll */ #include /* memcpy, strcpy, strncat, strndup */ +#include "alias.h" /* weak_alias */ + /* "Checked" memcpy */ void *__memcpy_chk(void *dest, const void *src, size_t len, size_t destlen) { @@ -60,7 +62,7 @@ char *__strndup(const char *str, size_t count) /* The existance of this method, and the fact it is used in real code, gives * me nightmares. */ -void *rawmemchr(const void *s, int c) +void *__rawmemchr(const void *s, int c) { const unsigned char *haystack = s; unsigned char needle = (unsigned char) c; @@ -68,9 +70,7 @@ void *rawmemchr(const void *s, int c) ; return (void *) haystack; } - -extern __typeof(rawmemchr) __rawmemchr - __attribute__((weak, alias("rawmemchr"))); +weak_alias(__rawmemchr, rawmemchr); /* Another useless __ alias */ char *__strtok_r(char *str, const char *delim, char **saveptr) -- cgit v1.2.3-60-g2f50 From 737aaed25c2a29f00e53b5689ca07108e977cd84 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 19:00:49 -0600 Subject: Makefile: Update compilation options * Remove -DPIC as it is unused (and PIC is always enabled). * Export the loader name as a macro (this will be used in the future). * Enable compiler warnings, except the expected ones. Signed-off-by: Samuel Holland --- Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index b941dcf..887a7cf 100644 --- a/Makefile +++ b/Makefile @@ -41,9 +41,10 @@ ${LOADER_NAME}: ${LOADER_OBJ} $(CC) -o ${LOADER_NAME} -fPIE -static ${LOADER_OBJ} .c.o: - $(CC) -std=c99 -D_BSD_SOURCE -fPIC -DPIC -DLINKER=\"${LINKER_PATH}\" \ - -DLIBGCOMPAT=\"${LIBGCOMPAT_PATH}\" ${CFLAGS} ${CPPFLAGS} \ - -c -o $@ $< + $(CC) -c -D_BSD_SOURCE -DLIBGCOMPAT=\"${LIBGCOMPAT_PATH}\" \ + -DLINKER=\"${LINKER_PATH}\" -DLOADER=\"${LOADER_NAME}\" \ + -fPIC -std=c99 -Wall -Wextra -Wno-frame-address \ + -Wno-unused-parameter ${CFLAGS} ${CPPFLAGS} -o $@ $< clean: rm -f libgcompat/*.o loader/*.o ${LIBGCOMPAT_NAME} ${LOADER_NAME} -- cgit v1.2.3-60-g2f50 From 9e0bbd07ef5affa403d476b0bcdabfc5a5684cf9 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 20:30:39 -0600 Subject: loader: Several improvements * Handle programs that have a DT_NEEDED entry for glibc's ld.so. * Handle when LD_PRELOAD is already set. * Use the --argv0 option to properly set argv[0] in the target program. * Ensure the the argument list is terminated with a NULL sentinel. * Document the details of the loader's implementation. [NOTE: Better commit summary?] Signed-off-by: Samuel Holland --- loader/loader.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 75 insertions(+), 18 deletions(-) diff --git a/loader/loader.c b/loader/loader.c index 979937f..53a2c38 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2017 William Pitcock + * Copyright (c) 2018 Samuel Holland * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -10,43 +11,99 @@ * from the use of this software. */ -#include -#include -#include -#include -#include +#include /* PATH_MAX */ +#include /* NULL */ +#include /* fputs, fwrite, stderr */ +#include /* calloc, EXIT_FAILURE, getenv */ +#include /* strcpy, strlcpy */ +#include /* execve, ssize_t */ #ifndef PATH_MAX #define PATH_MAX 16384 #endif +#ifndef LIBGCOMPAT +#error LIBGCOMPAT must be defined +#endif + #ifndef LINKER #error LINKER must be defined #endif -#ifndef LIBGCOMPAT -#error LIBGCOMPAT must be defined +#ifndef LOADER +#error LOADER must be defined #endif +/* + * Given the argv { "foo", "bar", "baz" }, and the environment variable + * "LD_PRELOAD=/another/preload.so", the new argv will be { + * "ld-linux-$ARCH.so.N", + * "--argv0", + * "foo", + * "--preload", + * "/path/to/libgcompat.so /another/preload.so", + * "/path/to/foo", + * "bar", + * "baz" + * }. + * + * NOTE: The new argv needs 6 more entries than the original argc: five for + * arguments added at the beginning, and one for the NULL sentinel at the end + * not included in argc. Because calloc() is used, the sentinel is not + * explicitly set on its own, but *it is still there*! + * + * NOTE: The name given in argv[0] to musl *must* match glibc's ld.so filename. + * Many glibc-linked programs have an explicit dependency on its ld.so, but the + * file placed at that path (this loader) is not a real shared library. If musl + * tries to load this file as a shared library, it will fail. Thankfully, since + * musl treats argv[0] as "its" name when run directly, it considers a library + * by that name to already be loaded, and ignores the problematic dependency. + * + * NOTE: LD_PRELOAD entries are processed in order, and the environment variable + * is ignored if the parameter is given. In case the glibc-linked program needs + * another preloaded library, it should be appended to the argument so it gets + * loaded after libgcompat. Leave the environment variable as is, so if the + * program runs other glibc-linked programs, the same transformation gets + * applied there as well. + * + * NOTE: In order for the program to be able to re-exec itself it needs the + * fully-resolved path from /proc/self/exe ("target" below). This path is given + * to musl on the command line in new_argv[5], but it is not directly available + * to the program. An intercepted readlink("/proc/self/exe") must read it from + * /proc/self/cmdline. Thus, if its position in new_argv changes, that function + * must also be updated to match. + */ int main(int argc, char *argv[], char *envp[]) { - size_t i = 0; + char **new_argv = calloc(argc + 6, sizeof(char *)); + char preload[PATH_MAX]; char target[PATH_MAX]; - char **new_argv = calloc(sizeof(char *), argc + 5); + ssize_t i, j, len; - memset(target, 0, sizeof(target)); - if (readlink("/proc/self/exe", target, sizeof(target)) < 0) { + strcpy(preload, LIBGCOMPAT " "); + if (getenv("LD_PRELOAD") != NULL) { + len = strlcat(preload, getenv("LD_PRELOAD"), sizeof(preload)); + if ((size_t) len >= sizeof(preload)) { + fputs("too many preloaded libraries", stderr); + return EXIT_FAILURE; + } + } + + len = readlink("/proc/self/exe", target, sizeof(target)); + if (len < 0 || len == sizeof(target)) { perror("readlink"); return EXIT_FAILURE; } + target[len] = '\0'; - new_argv[0] = argv[0]; - new_argv[1] = "--preload"; - new_argv[2] = LIBGCOMPAT; - new_argv[3] = target; - - for (i = 1; i < argc; i++) { - new_argv[3 + i] = argv[i]; + new_argv[0] = LOADER; + new_argv[1] = "--argv0"; + new_argv[2] = argv[0]; + new_argv[3] = "--preload"; + new_argv[4] = preload; + new_argv[5] = target; + for (i = 6, j = 1; j < argc; ++i, ++j) { + new_argv[i] = argv[j]; } execve(LINKER, new_argv, envp); -- cgit v1.2.3-60-g2f50 From 51fcab754dabef67a26210a6e1cd752290a10749 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 21:22:23 -0600 Subject: execinfo: Clean up, implement backtrace_symbols_fd Rename the file to match the header it implements functions from. Changes to existing code: * Fix the return value from backtrace (off by one). * Use __builtin_extract_return_addr as recommended in gcc documentation. * Document header usage. * Document where the functions are referenced in the LSB standard. Signed-off-by: Samuel Holland --- Makefile | 2 +- libgcompat/backtrace.c | 51 -------------------------- libgcompat/execinfo.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 52 deletions(-) delete mode 100644 libgcompat/backtrace.c create mode 100644 libgcompat/execinfo.c diff --git a/Makefile b/Makefile index 887a7cf..b6ea4f7 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ LIBGCOMPAT_INCLUDE = \ libgcompat/alias.h LIBGCOMPAT_SRC = \ - libgcompat/backtrace.c \ libgcompat/dlmopen.c \ libgcompat/dlvsym.c \ + libgcompat/execinfo.c \ libgcompat/gnulib.c \ libgcompat/malloc.c \ libgcompat/math.c \ diff --git a/libgcompat/backtrace.c b/libgcompat/backtrace.c deleted file mode 100644 index c8ded8b..0000000 --- a/libgcompat/backtrace.c +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include -#include - -#define _frame_level(addr_buf, curr, frame, size) \ - do { \ - if (__builtin_frame_address(frame) != NULL \ - && (curr = __builtin_return_address(frame)) > 0x1000 \ - && frame <= size) { \ - addr_buf[frame] = curr; \ - } else { \ - return size; \ - } \ - } while (0) - -int backtrace(void **addr_buf, int size) -{ - void *curr; - _frame_level(addr_buf, curr, 0, size); - _frame_level(addr_buf, curr, 1, size); - _frame_level(addr_buf, curr, 2, size); - _frame_level(addr_buf, curr, 3, size); - _frame_level(addr_buf, curr, 4, size); - _frame_level(addr_buf, curr, 5, size); - _frame_level(addr_buf, curr, 6, size); - _frame_level(addr_buf, curr, 7, size); - _frame_level(addr_buf, curr, 8, size); - _frame_level(addr_buf, curr, 9, size); - return 9; -} - -char **backtrace_symbols(void *const *addr_buf, int size) -{ - char **result = calloc(sizeof(char *), size); - if (result == NULL) { - return result; - } - - for (int next = 0; next < size; next++) { - Dl_info info; - int err = dladdr(addr_buf[next], &info); - - if (err != 0) { - result[next] = "??:0"; - } else { - result[next] = info.dli_sname; - } - } - - return result; -} diff --git a/libgcompat/execinfo.c b/libgcompat/execinfo.c new file mode 100644 index 0000000..59441aa --- /dev/null +++ b/libgcompat/execinfo.c @@ -0,0 +1,97 @@ +#include /* dladdr */ +#include /* NULL */ +#include /* uintptr_t */ +#include /* calloc */ +#include /* strlen */ +#include /* write */ + +#define get_frame_level(array, size, n) \ + do { \ + if (n >= size || __builtin_frame_address(n) == NULL) { \ + return n; \ + } \ + void *address = __builtin_return_address(n); \ + array[n] = __builtin_extract_return_addr(address); \ + if ((uintptr_t) array[n] < 0x1000) { \ + return n; \ + } \ + } while (0) + +/** + * Obtain a backtrace for the calling program. + * + * LSB 5.0: LSB-Core-generic/baselib-backtrace-1.html + */ +int backtrace(void **array, int size) +{ + get_frame_level(array, size, 0); + get_frame_level(array, size, 1); + get_frame_level(array, size, 2); + get_frame_level(array, size, 3); + get_frame_level(array, size, 4); + get_frame_level(array, size, 5); + get_frame_level(array, size, 6); + get_frame_level(array, size, 7); + get_frame_level(array, size, 8); + get_frame_level(array, size, 9); + return 10; +} + +/** + * Translate addresses into symbol information. + * + * LSB 5.0: LSB-Core-generic/baselib-backtrace-1.html + */ +const char **backtrace_symbols(void *const *array, int size) +{ + const char **result = calloc(size, sizeof(char *)); + + if (result == NULL) { + return NULL; + } + for (int i = 0; i < size; ++i) { + Dl_info info; + + if (dladdr(array[i], &info) && info.dli_sname != NULL) { + result[i] = info.dli_sname; + } else { + result[i] = "??:0"; + } + } + + return result; +} + +/** + * Write symbol information to a file without allocating memory. + * + * LSB 5.0: LSB-Core-generic/baselib-backtrace-1.html + */ +void backtrace_symbols_fd(void *const *array, int size, int fd) +{ + for (int i = 0; i < size; ++i) { + Dl_info info; + const char *line; + int len; + + if (dladdr(array[i], &info) && info.dli_sname != NULL) { + line = info.dli_sname; + len = strlen(line); + } else { + line = "??:0"; + len = sizeof("??:0") - 1; + } + while (len > 0) { + int written = write(fd, line, len); + + if (written < 1) { + return; + } + line += written; + len -= written; + } + if (write(fd, "\n", 1) != 1) { + return; + } + } +} -- cgit v1.2.3-60-g2f50 From d0fc6cbef513341ff6b3d12c9b9a1e4093c0a112 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 21:33:52 -0600 Subject: dlfcn: Combine functions for the same header into one file Changes to existing code: * Make explicit comparison against NULL. * Adjust debug message for readability. Signed-off-by: Samuel Holland --- Makefile | 3 +-- libgcompat/dlfcn.c | 25 +++++++++++++++++++++++++ libgcompat/dlmopen.c | 14 -------------- libgcompat/dlvsym.c | 13 ------------- 4 files changed, 26 insertions(+), 29 deletions(-) create mode 100644 libgcompat/dlfcn.c delete mode 100644 libgcompat/dlmopen.c delete mode 100644 libgcompat/dlvsym.c diff --git a/Makefile b/Makefile index b6ea4f7..4873403 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,7 @@ LIBGCOMPAT_INCLUDE = \ libgcompat/alias.h LIBGCOMPAT_SRC = \ - libgcompat/dlmopen.c \ - libgcompat/dlvsym.c \ + libgcompat/dlfcn.c \ libgcompat/execinfo.c \ libgcompat/gnulib.c \ libgcompat/malloc.c \ diff --git a/libgcompat/dlfcn.c b/libgcompat/dlfcn.c new file mode 100644 index 0000000..f2eaa45 --- /dev/null +++ b/libgcompat/dlfcn.c @@ -0,0 +1,25 @@ +#include /* dlopen, dlsym */ +#include /* NULL */ +#include /* fprintf */ +#include /* getenv */ + +void *dlmopen(long lmid, const char *pathname, int mode) +{ + if (getenv("GLIBC_FAKE_DEBUG") != NULL) { + fprintf(stderr, + "loading library %s was requested in namespace %ld", + pathname, lmid); + } + + return dlopen(pathname, mode); +} + +void *dlvsym(void *handle, char *symbol, char *version) +{ + if (getenv("GLIBC_FAKE_DEBUG") != NULL) { + fprintf(stderr, "symbol %s with version %s is being redirected", + symbol, version); + } + + return dlsym(handle, symbol); +} diff --git a/libgcompat/dlmopen.c b/libgcompat/dlmopen.c deleted file mode 100644 index 4584680..0000000 --- a/libgcompat/dlmopen.c +++ /dev/null @@ -1,14 +0,0 @@ -#include /* dlopen */ -#include /* fprintf */ -#include /* getenv */ - -void *dlmopen(long lmid, const char *pathname, int mode) -{ - if (getenv("GLIBC_FAKE_DEBUG")) { - fprintf(stderr, - "library %s was requested to load in %ld namespace", - pathname, lmid); - } - - return dlopen(pathname, mode); -} diff --git a/libgcompat/dlvsym.c b/libgcompat/dlvsym.c deleted file mode 100644 index 0aba245..0000000 --- a/libgcompat/dlvsym.c +++ /dev/null @@ -1,13 +0,0 @@ -#include /* dlsym */ -#include /* fprintf */ -#include /* getenv */ - -void *dlvsym(void *handle, char *symbol, char *version) -{ - if (getenv("GLIBC_FAKE_DEBUG")) { - fprintf(stderr, "symbol %s with version %s is being redirected", - symbol, version); - } - - return dlsym(handle, symbol); -} -- cgit v1.2.3-60-g2f50 From 9549bf6ab9feddec4959de21d3e1a1f59adb15a5 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 21:39:28 -0600 Subject: malloc: Sort functions by name Signed-off-by: Samuel Holland --- libgcompat/malloc.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/libgcompat/malloc.c b/libgcompat/malloc.c index dc9d25e..14fbf66 100644 --- a/libgcompat/malloc.c +++ b/libgcompat/malloc.c @@ -1,4 +1,5 @@ -/* struct mallinfo pulled from mallinfo.3: +/* + * struct mallinfo pulled from mallinfo.3: * * Copyright (c) 2012 by Michael Kerrisk * @@ -42,30 +43,29 @@ struct mallinfo { int keepcost; /* Top-most, releasable space (bytes) */ }; -struct mallinfo mallinfo(void) +void *__libc_calloc(size_t nmemb, size_t size) { - struct mallinfo my_info; - memset(&my_info, 0, sizeof(struct mallinfo)); - return my_info; + return calloc(nmemb, size); } +alias(__libc_calloc, __calloc); -void *__libc_malloc(size_t size) +void __libc_free(void *ptr) { - return malloc(size); + free(ptr); } -alias(__libc_malloc, __malloc); +alias(__libc_free, __free); -void __libc_free(void *ptr) +void *__libc_malloc(size_t size) { - return free(ptr); + return malloc(size); } -alias(__libc_free, __free); +alias(__libc_malloc, __malloc); -void *__libc_calloc(size_t nmemb, size_t size) +void *__libc_memalign(size_t align, size_t len) { - return calloc(nmemb, size); + return memalign(align, len); } -alias(__libc_calloc, __calloc); +alias(__libc_memalign, __memalign); void *__libc_realloc(void *ptr, size_t size) { @@ -73,7 +73,9 @@ void *__libc_realloc(void *ptr, size_t size) } alias(__libc_realloc, __realloc); -void *__libc_memalign(size_t align, size_t len) +struct mallinfo mallinfo(void) { - return memalign(align, len); + struct mallinfo info; + memset(&info, 0, sizeof(info)); + return info; } -- cgit v1.2.3-60-g2f50 From ea0bbb48b37dc43c3a1cec4e87ed7049e13b4ff9 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 21:41:21 -0600 Subject: math: Clean up, add additional functions * Add finite() variants, needed by some applications. * Add remaining long double variants of existing functions. * Sort and document existing functions, including where referenced in the LSB standard. Signed-off-by: Samuel Holland --- libgcompat/math.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 11 deletions(-) diff --git a/libgcompat/math.c b/libgcompat/math.c index 2982116..db123f8 100644 --- a/libgcompat/math.c +++ b/libgcompat/math.c @@ -1,27 +1,96 @@ -#include /* isinf, isnan */ +#include /* isfinite, isinf, isnan */ #include "alias.h" /* weak_alias */ -int __isinff(float number) +/** + * Test for finite value. + */ +int __finite(double arg) { - return isinf(number); + return isfinite(arg); } -weak_alias(__isinff, isinff); +weak_alias(__finite, finite); + +/** + * Test for finite value. + */ +int __finitef(float arg) +{ + return isfinite(arg); +} +weak_alias(__finitef, finitef); + +/** + * Test for finite value. + */ +int __finitel(long double arg) +{ + return isfinite(arg); +} +weak_alias(__finitel, finitel); -int __isinf(double number) +/** + * Test for infinity. + * + * LSB 5.0: LSB-Core-generic/baselib---isinf.html + */ +int __isinf(double arg) { - return isinf(number); + return isinf(arg); } weak_alias(__isinf, isinf); -int __isnanf(float number) +/** + * Test for infinity. + * + * LSB 5.0: LSB-Core-generic/baselib---isinff.html + */ +int __isinff(float arg) { - return isnan(number); + return isinf(arg); } -weak_alias(__isnanf, isnanf); +weak_alias(__isinff, isinff); -int __isnan(double number) +/** + * Test for infinity. + * + * LSB 5.0: LSB-Core-generic/baselib---isinfl.html + */ +int __isinfl(long double arg) { - return isnan(number); + return isinf(arg); +} +weak_alias(__isinfl, isinfl); + +/** + * Test for a NaN. + * + * LSB 5.0: LSB-Core-generic/baselib---isnan.html + */ +int __isnan(double arg) +{ + return isnan(arg); } weak_alias(__isnan, isnan); + +/** + * Test for a NaN. + * + * LSB 5.0: LSB-Core-generic/baselib---isnanf.html + */ +int __isnanf(float arg) +{ + return isnan(arg); +} +weak_alias(__isnanf, isnanf); + +/** + * Test for a NaN. + * + * LSB 5.0: LSB-Core-generic/baselib---isnanl.html + */ +int __isnanl(long double arg) +{ + return isnan(arg); +} +weak_alias(__isnanl, isnanl); -- cgit v1.2.3-60-g2f50 From 18ce7cc13e00f98e214c211b55669e8dd4b3268c Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 21:45:46 -0600 Subject: pthread: Clean up, fix prototype * Add the missing parameter to __register_atfork. * Sort and document functions. __pthread_register_cancel and __pthread_unregister_cancel should be implemented at some point, or else pthread_cleanup_pop(true) will not work properly and could cause deadlocks in programs that use it. Signed-off-by: Samuel Holland --- libgcompat/pthread.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/libgcompat/pthread.c b/libgcompat/pthread.c index 9333554..4ebbe6b 100644 --- a/libgcompat/pthread.c +++ b/libgcompat/pthread.c @@ -2,17 +2,28 @@ #include "alias.h" /* weak_alias */ -int __register_atfork(void (*prepare)(void), void (*parent)(void), - void (*child)(void)) +/** + * Underlying function for pthread_cleanup_push. + */ +void __pthread_register_cancel(void *buf) { - return pthread_atfork(prepare, parent, child); } -weak_alias(__register_atfork, register_atfork); -void __pthread_register_cancel(void *buf) +/** + * Underlying function for pthread_cleanup_push. + */ +void __pthread_unregister_cancel(void *buf) { } -void __pthread_unregister_cancel(void *buf) +/** + * Register fork handlers. + * + * LSB 5.0: LSB-Core-generic/baselib---register-atfork.html + */ +int __register_atfork(void (*prepare)(void), void (*parent)(void), + void (*child)(void), void *__dso_handle) { + return pthread_atfork(prepare, parent, child); } +weak_alias(__register_atfork, register_atfork); -- cgit v1.2.3-60-g2f50 From 810f46ab1cc801e54fc3836c22b5f1364cd632e6 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 22:09:08 -0600 Subject: pwd: Fully implement fgetpwent_r/getpwent_r These functions require a deep copy of the structure into the caller-provided buffer. Also make sure to store NULL in result on error. Use the stream to differentiate the two functions and avoid duplication. Signed-off-by: Samuel Holland --- libgcompat/pwd.c | 119 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 74 insertions(+), 45 deletions(-) diff --git a/libgcompat/pwd.c b/libgcompat/pwd.c index 50d8da0..34c5d7b 100644 --- a/libgcompat/pwd.c +++ b/libgcompat/pwd.c @@ -1,63 +1,92 @@ /* some musl versions incorrectly mark fgetpwent() as a GNU extension */ #define _GNU_SOURCE +#include /* assert */ +#include /* ENOENT, ERANGE */ +#include /* pthread_mutex_* */ +#include /* fgetpwent, getpwent, struct passwd */ +#include /* NULL, size_t */ +#include /* FILE */ +#include /* memcpy, stpcpy, strlcpy, strlen */ -#include -#include -#include -#include +static pthread_mutex_t pwent_mutex = PTHREAD_MUTEX_INITIALIZER; -int getpwent_r(struct passwd *pwbuf, char *buf, size_t buflen, - struct passwd **pwbufp) +static int __fgetpwent_r(FILE *stream, struct passwd *pwd, char *buf, + size_t len, struct passwd **result) { - struct passwd *pwd; + struct passwd *pwtmp; + char *cursor = buf, *end = buf + len; - if (pwbufp == NULL || pwbuf == NULL) { - return ERANGE; + *result = NULL; + pthread_mutex_lock(&pwent_mutex); + pwtmp = stream != NULL ? fgetpwent(stream) : getpwent(); + if (pwtmp == NULL) { + pthread_mutex_unlock(&pwent_mutex); + return ENOENT; } - - if (buflen < 1) { - return ERANGE; + memcpy(pwd, pwtmp, sizeof(*pwd)); + if (pwtmp->pw_name != NULL) { + pwd->pw_name = cursor; + cursor += strlcpy(cursor, pwtmp->pw_name, end - cursor) + 1; + if (cursor > end) { + goto err_unlock; + } } - - if (buf != NULL) { - *buf = '\0'; + if (pwtmp->pw_passwd != NULL) { + pwd->pw_passwd = cursor; + cursor += strlcpy(cursor, pwtmp->pw_passwd, end - cursor) + 1; + if (cursor > end) { + goto err_unlock; + } } - - if ((pwd = getpwent()) == NULL) { - *pwbufp = NULL; - return ENOENT; + if (pwtmp->pw_gecos != NULL) { + pwd->pw_gecos = cursor; + cursor += strlcpy(cursor, pwtmp->pw_gecos, end - cursor) + 1; + if (cursor > end) { + goto err_unlock; + } } - - memcpy(pwbuf, pwd, sizeof(*pwd)); - *pwbufp = pwbuf; + if (pwtmp->pw_dir != NULL) { + pwd->pw_dir = cursor; + cursor += strlcpy(cursor, pwtmp->pw_dir, end - cursor) + 1; + if (cursor > end) { + goto err_unlock; + } + } + if (pwtmp->pw_shell != NULL) { + pwd->pw_shell = cursor; + cursor += strlcpy(cursor, pwtmp->pw_shell, end - cursor) + 1; + if (cursor > end) { + goto err_unlock; + } + } + pthread_mutex_unlock(&pwent_mutex); + *result = pwd; return 0; + +err_unlock: + pthread_mutex_unlock(&pwent_mutex); + return ERANGE; } -int fgetpwent_r(FILE *filp, struct passwd *pwbuf, char *buf, size_t buflen, - struct passwd **pwbufp) +/** + * Get passwd file entry. + */ +int fgetpwent_r(FILE *stream, struct passwd *pwd, char *buf, size_t len, + struct passwd **result) { - struct passwd *pwd; - - if (pwbufp == NULL || pwbuf == NULL) { - return ERANGE; - } + assert(stream != NULL); - if (buflen < 1) { - return ERANGE; - } - - if (buf != NULL) { - *buf = '\0'; - } - - if ((pwd = fgetpwent(filp)) == NULL) { - *pwbufp = NULL; - return ENOENT; - } - - memcpy(pwbuf, pwd, sizeof(*pwd)); - *pwbufp = pwbuf; + return fgetpwent_r(stream, pwd, buf, len, result); +} - return 0; +/** + * Get user database entry. + * + * LSB 5.0: LSB-Core-generic/baselib-getpwent-r-1.html + */ +int getpwent_r(struct passwd *pwd, char *buf, size_t len, + struct passwd **result) +{ + return __fgetpwent_r(NULL, pwd, buf, len, result); } -- cgit v1.2.3-60-g2f50 From 28096715d49fe420ed194e8520ec5e81bc2cdc85 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 22:17:13 -0600 Subject: grp: Implement fgetgrent_r/getgrent_r Like fgetpwent_r/getpwent_r, these require a deep copy of the structure into the caller-provided buffer. This is nontrivial for the array of strings member. getgrent_r is required by LSB. [NOTE: I'm not too happy with the macro, but it works. Any suggestions?] Signed-off-by: Samuel Holland --- Makefile | 1 + libgcompat/grp.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 libgcompat/grp.c diff --git a/Makefile b/Makefile index 4873403..14c68f4 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ LIBGCOMPAT_SRC = \ libgcompat/dlfcn.c \ libgcompat/execinfo.c \ libgcompat/gnulib.c \ + libgcompat/grp.c \ libgcompat/malloc.c \ libgcompat/math.c \ libgcompat/pthread.c \ diff --git a/libgcompat/grp.c b/libgcompat/grp.c new file mode 100644 index 0000000..5674fda --- /dev/null +++ b/libgcompat/grp.c @@ -0,0 +1,98 @@ +/* some musl versions incorrectly mark fgetgrent() as a GNU extension */ +#define _GNU_SOURCE +#include /* assert */ +#include /* ENOENT, ERANGE */ +#include /* fgetgrent, getgrent, struct group */ +#include /* pthread_mutex_* */ +#include /* NULL, size_t */ +#include /* ptrdiff_t, uintptr_t */ +#include /* FILE */ +#include /* memcpy, stpcpy, strlcpy, strlen */ + +#define ALIGN_PTR_TO_SIZE_OF(ptr, type) \ + ((type *) ((((uintptr_t)(ptr)) + sizeof(type) - 1) \ + & ~(sizeof(type) - 1))) + +static pthread_mutex_t grent_mutex = PTHREAD_MUTEX_INITIALIZER; + +static int __fgetgrent_r(FILE *stream, struct group *grp, char *buf, size_t len, + struct group **result) +{ + struct group *grtmp; + char *cursor = buf, *end = buf + len; + + *result = NULL; + pthread_mutex_lock(&grent_mutex); + grtmp = stream != NULL ? fgetgrent(stream) : getgrent(); + if (grtmp == NULL) { + pthread_mutex_unlock(&grent_mutex); + return ENOENT; + } + memcpy(grp, grtmp, sizeof(*grp)); + if (grtmp->gr_name != NULL) { + grp->gr_name = cursor; + cursor += strlcpy(cursor, grtmp->gr_name, end - cursor) + 1; + if (cursor > end) { + goto err_unlock; + } + } + if (grtmp->gr_passwd != NULL) { + grp->gr_passwd = cursor; + cursor += strlcpy(cursor, grtmp->gr_passwd, end - cursor) + 1; + if (cursor > end) { + goto err_unlock; + } + } + if (grtmp->gr_mem != NULL) { + char **members = ALIGN_PTR_TO_SIZE_OF(cursor, char *); + ptrdiff_t nameslen = 0; + size_t nmem = 0; + + /* Calculate total size of strings plus their pointers. */ + while (grtmp->gr_mem[nmem++] != NULL) { + nameslen += strlen(grtmp->gr_mem[nmem - 1]) + 1; + } + nameslen += nmem * sizeof(*members); + if (nameslen > end - ((char *) members)) { + goto err_unlock; + } + /* Copy the pointers, including the NULL sentinel. */ + for (size_t i = 0; i < nmem; ++i) { + members[i] = grtmp->gr_mem[i]; + } + /* Copy the strings (the NULL sentinel doesn't point to one). */ + cursor = (char *) &members[nmem]; + for (size_t i = 0; i < nmem - 1; ++i) { + cursor = stpcpy(cursor, members[i]) + 1; + } + } + pthread_mutex_unlock(&grent_mutex); + *result = grp; + + return 0; + +err_unlock: + pthread_mutex_unlock(&grent_mutex); + return ERANGE; +} + +/** + * Get group file entry. + */ +int fgetgrent_r(FILE *stream, struct group *grp, char *buf, size_t len, + struct group **result) +{ + assert(stream != NULL); + + return __fgetgrent_r(stream, grp, buf, len, result); +} + +/** + * Get group database entry. + * + * LSB 5.0: LSB-Core-generic/baselib-getgrent-r-1.html + */ +int getgrent_r(struct group *grp, char *buf, size_t len, struct group **result) +{ + return __fgetgrent_r(NULL, grp, buf, len, result); +} -- cgit v1.2.3-60-g2f50 From d3e8ee9b447b1b60619f8688abe0dd992c383701 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 22:23:43 -0600 Subject: resolv: Clean up, avoid NULL deref * Make comment style consistent with the rest of the project, and remove outdated header name. * Remove "static inline" from functions (this is no longer a header). * Check statp for NULL in res_ninit like in res_nclose. Signed-off-by: Samuel Holland --- libgcompat/resolv.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/libgcompat/resolv.c b/libgcompat/resolv.c index 7ad984f..5943bcc 100644 --- a/libgcompat/resolv.c +++ b/libgcompat/resolv.c @@ -1,34 +1,42 @@ -/* Original author: Khem Raj */ -/*************************************************************************** - * resolv_compat.h +/* + * Original author: Khem Raj * * Mimick GLIBC's res_ninit() and res_nclose() for musl libc * Note: res_init() is actually deprecated according to * http://docs.oracle.com/cd/E36784_01/html/E36875/res-nclose-3resolv.html - **************************************************************************/ + */ + #include /* res_state */ +#include /* NULL */ #include /* memcpy, memset */ #include "alias.h" /* weak_alias */ -static inline int __res_ninit(res_state statp) +int __res_ninit(res_state statp) { - int rc = res_init(); + int rc; + + if (statp == NULL) { + return -1; + } + rc = res_init(); if (statp != &_res) { memcpy(statp, &_res, sizeof(*statp)); } + return rc; } weak_alias(__res_ninit, res_ninit); -static inline int __res_nclose(res_state statp) +int __res_nclose(res_state statp) { - if (!statp) { + if (statp == NULL) { return -1; } if (statp != &_res) { memset(statp, 0, sizeof(*statp)); } + return 0; } weak_alias(__res_nclose, res_nclose); -- cgit v1.2.3-60-g2f50 From c735fc99ec9e96520da0ea938890eed8fe64b50e Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 22:27:11 -0600 Subject: resource: Minor improvements * Make function pointer static. * Only initialize function pointer once. Signed-off-by: Samuel Holland --- libgcompat/resource.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libgcompat/resource.c b/libgcompat/resource.c index 4a7ab4e..836d5e2 100644 --- a/libgcompat/resource.c +++ b/libgcompat/resource.c @@ -17,16 +17,17 @@ * very obviously won't work here. */ #ifndef NO_BROKEN_SHADOW_SETRLIMIT -int (*real_rlimit)(int, const struct rlimit *); +static int (*real_rlimit)(int, const struct rlimit *); int setrlimit(int resource, const struct rlimit *rlim) { struct rlimit my_rlim; - real_rlimit = dlsym(RTLD_NEXT, "setrlimit"); - assert(real_rlimit != NULL); + if (real_rlimit == NULL) { + real_rlimit = dlsym(RTLD_NEXT, "setrlimit"); + assert(real_rlimit); + } memcpy(&my_rlim, rlim, sizeof(struct rlimit)); - if (my_rlim.rlim_cur == 0) { my_rlim.rlim_cur = my_rlim.rlim_max; } -- cgit v1.2.3-60-g2f50 From 101dbb13a1d0270b931291607962e6780ec856a5 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 22:39:41 -0600 Subject: stdio: Clean up, add all of LSB stdio plus more * Add all (non-wchar) stdio functions from LSB, plus those found in use in other applications. Document those functions from LSB as such. * Use a consistent structure and paramater names for all functions. * flag == 0 means FORTIFY_SOURCE=1, so the implemented checks should be unconditional. * Add all possible checks without parsing the format string. * Move functions from wchar.h to their own appropriately-named file. Signed-off-by: Samuel Holland --- Makefile | 3 +- libgcompat/stdio.c | 273 +++++++++++++++++++++++++++++++++++++---------------- libgcompat/wchar.c | 40 ++++++++ 3 files changed, 234 insertions(+), 82 deletions(-) create mode 100644 libgcompat/wchar.c diff --git a/Makefile b/Makefile index 14c68f4..b5fda64 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,8 @@ LIBGCOMPAT_SRC = \ libgcompat/string.c \ libgcompat/sysctl.c \ libgcompat/ucontext.c \ - libgcompat/version.c + libgcompat/version.c \ + libgcompat/wchar.c LIBGCOMPAT_OBJ = ${LIBGCOMPAT_SRC:.c=.o} LIBGCOMPAT_SOVERSION = 0 LIBGCOMPAT_NAME = libgcompat.so.${LIBGCOMPAT_SOVERSION} diff --git a/libgcompat/stdio.c b/libgcompat/stdio.c index a44d94c..0ff5feb 100644 --- a/libgcompat/stdio.c +++ b/libgcompat/stdio.c @@ -1,125 +1,236 @@ -#include -#include -#include -#include - -size_t __fread_chk(void *ptr, size_t size, size_t nmemb, FILE *stream) +#define _GNU_SOURCE /* fgets_unlocked */ +#include /* assert */ +#include /* va_list, va_start, va_end */ +#include /* NULL, size_t */ +#include /* feof, fgets, fread, puts, v*printf */ + +int __vasprintf_chk(char **strp, int flag, const char *format, va_list ap); +int __vfprintf_chk(FILE *stream, int flag, const char *format, va_list ap); +int __vsnprintf_chk(char *s, size_t n, int flag, size_t slen, + const char *format, va_list ap); +int __vsprintf_chk(char *s, int flag, size_t slen, const char *format, + va_list ap); + +/** + * Test end-of-file indicator on a stream. + * + * LSB 5.0: LSB-Core-generic/baselib--io-feof-3.html + */ +int _IO_feof(FILE *stream) { - assert(ptr != NULL); - assert(stream != NULL); - return fread(ptr, size, nmemb, stream); + return feof(stream); } -int __printf_chk(int flag, const char *format, ...) +/** + * Put a string on standard output. + * + * LSB 5.0: LSB-Core-generic/baselib--io-puts-3.html + */ +int _IO_puts(const char *c) { - va_list argp; - int result; + return puts(c); +} - if (flag > 0) { - assert(format != NULL); - } +/** + * Print to allocated string, with stack checking. + */ +int __asprintf_chk(char **strp, int flag, const char *format, ...) +{ + int ret; + va_list ap; - va_start(argp, format); - result = vprintf(format, argp); - va_end(argp); + va_start(ap, format); + ret = __vasprintf_chk(strp, flag, format, ap); + va_end(ap); - return result; + return ret; } -int __fprintf_chk(FILE *stream, int flag, const char *format, ...) +/** + * String input, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---fgets-chk-1.html + */ +char *__fgets_chk(char *s, size_t slen, int n, FILE *stream) { - va_list argp; - int result; + assert(s != NULL); + assert(slen >= (size_t) n); + assert(n > 0); + assert(stream != NULL); - if (flag > 0) { - assert(stream != NULL); - assert(format != NULL); - } + return fgets(s, n, stream); +} - va_start(argp, format); - result = vfprintf(stream, format, argp); - va_end(argp); +/** + * Non-locking string input, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---fgets-unlocked-chk-1.html + */ +char *__fgets_unlocked_chk(char *s, size_t slen, int n, FILE *stream) +{ + assert(s != NULL); + assert(slen >= (size_t) n); + assert(n > 0); + assert(stream != NULL); - return result; + return fgets_unlocked(s, n, stream); } -int __sprintf_chk(char *str, int flag, size_t strlen, const char *format, ...) +/** + * Convert formatted output, with stack checking. + * + * LSB 5.0: LSB-Core-generic/baselib---fprintf-chk-1.html + */ +int __fprintf_chk(FILE *stream, int flag, const char *format, ...) { - va_list argp; - int result; - - assert(strlen > 0); + int ret; + va_list ap; - va_start(argp, format); - result = vsnprintf(str, strlen, format, argp); - va_end(argp); + va_start(ap, format); + ret = __vfprintf_chk(stream, flag, format, ap); + va_end(ap); - return result; + return ret; } -int __snprintf_chk(char *str, size_t size, int flag, size_t strlen, - const char *format, ...) +/** + * Binary input, with stack checking. + */ +size_t __fread_chk(void *buf, size_t buflen, size_t size, size_t nitems, + FILE *stream) { - va_list argp; - int result; + assert(buf != NULL); + assert(size > 0); + assert(buflen / size >= nitems); + assert(stream != NULL); - if (flag > 0) { - assert(format != NULL); - } - // must always be done per LFS - assert(size <= strlen); + return fread(buf, size, nitems, stream); +} - va_start(argp, format); - result = vsnprintf(str, size, format, argp); - va_end(argp); +/** + * Format and print data, with stack checking. + * + * LSB 5.0: LSB-Core-generic/baselib---printf-chk-1.html + */ +int __printf_chk(int flag, const char *format, ...) +{ + int ret; + va_list ap; - return result; + va_start(ap, format); + ret = __vfprintf_chk(stdout, flag, format, ap); + va_end(ap); + + return ret; } -int __swprintf_chk(wchar_t *wcs, size_t maxlen, int flag, size_t wcslen, - const wchar_t *format, ...) +/** + * Convert formatted output, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---snprintf-chk-1.html + */ +int __snprintf_chk(char *s, size_t n, int flag, size_t slen, const char *format, + ...) { - va_list argp; - int result; + int ret; + va_list ap; - if (flag > 0) { - assert(format != NULL); - } - // must always be done per LFS - assert(maxlen <= wcslen); + va_start(ap, format); + ret = __vsnprintf_chk(s, n, flag, slen, format, ap); + va_end(ap); - va_start(argp, format); - result = vswprintf(wcs, maxlen, format, argp); - va_end(argp); + return ret; +} + +/** + * Convert formatted output, with stack checking. + * + * LSB 5.0: LSB-Core-generic/baselib---sprintf-chk-1.html + */ +int __sprintf_chk(char *s, int flag, size_t slen, const char *format, ...) +{ + int ret; + va_list ap; - return result; + va_start(ap, format); + ret = __vsprintf_chk(s, flag, slen, format, ap); + va_end(ap); + + return ret; } -int __vasprintf_chk(char **strp, int flag, const char *fmt, va_list ap) +/** + * Print to allocated string, with stack checking. + */ +int __vasprintf_chk(char **strp, int flag, const char *format, va_list ap) { - if (flag > 0) { - assert(strp != NULL); - assert(fmt != NULL); - } - return vasprintf(strp, fmt, ap); + assert(strp != NULL); + assert(format != NULL); + + return vasprintf(strp, format, ap); } +/** + * Convert formatted output, with stack checking. + * + * LSB 5.0: LSB-Core-generic/baselib---vfprintf-chk-1.html + */ int __vfprintf_chk(FILE *stream, int flag, const char *format, va_list ap) { - if (flag > 0) { - assert(stream != NULL); - assert(format != NULL); - } + assert(stream != NULL); + assert(format != NULL); + return vfprintf(stream, format, ap); } -int __vsnprintf_chk(char *str, size_t size, int flag, size_t strlen, +/** + * Convert formatted output, with stack checking. + * + * LSB 5.0: LSB-Core-generic/baselib---vprintf-chk-1.html + */ +int __vprintf_chk(int flag, const char *format, va_list ap) +{ + return __vfprintf_chk(stdout, flag, format, ap); +} + +/** + * Convert formatted output, with stack checking. + * + * LSB 5.0: LSB-Core-generic/baselib---vsnprintf-chk-1.html + */ +int __vsnprintf_chk(char *s, size_t n, int flag, size_t slen, const char *format, va_list ap) { - if (flag > 0) { - assert(format != NULL); + assert(s != NULL || n == 0); + assert(slen >= n); + assert(format != NULL); + + return vsnprintf(s, n, format, ap); +} + +/** + * Convert formatted output, with stack checking. + * + * LSB 5.0: LSB-Core-generic/baselib---vsprintf-chk-1.html + */ +int __vsprintf_chk(char *s, int flag, size_t slen, const char *format, + va_list ap) +{ + assert(s != NULL); + assert(slen > 0); + assert(format != NULL); + + return vsprintf(s, format, ap); +} + +/** + * Create a name for a temporary file. + */ +char *tmpnam_r(char *s) +{ + if (s == NULL) { + return NULL; } - // must always be done per LFS - assert(size <= strlen); - return vsnprintf(str, size, format, ap); + + return tmpnam(s); } diff --git a/libgcompat/wchar.c b/libgcompat/wchar.c new file mode 100644 index 0000000..1ddaa1f --- /dev/null +++ b/libgcompat/wchar.c @@ -0,0 +1,40 @@ +#include /* assert */ +#include /* va_list, va_start, va_end */ +#include /* size_t */ +#include /* wchar_t, *wprintf */ + +int __vswprintf_chk(wchar_t *s, size_t n, int flag, size_t slen, + const wchar_t *format, va_list ap); + +/** + * Convert formatted wide-character output, with stack checking + * + * LSB 5.0: LSB-Core-generic/baselib---swprintf-chk-1.html + */ +int __swprintf_chk(wchar_t *s, size_t n, int flag, size_t slen, + const wchar_t *format, ...) +{ + int ret; + va_list ap; + + va_start(ap, format); + ret = __vswprintf_chk(s, n, flag, slen, format, ap); + va_end(ap); + + return ret; +} + +/** + * Convert formatted wide-character output, with stack checking + * + * LSB 5.0: LSB-Core-generic/baselib---vswprintf-chk-1.html + */ +int __vswprintf_chk(wchar_t *s, size_t n, int flag, size_t slen, + const wchar_t *format, va_list ap) +{ + assert(s != NULL || n == 0); + assert(slen >= n); + assert(format != NULL); + + return vswprintf(s, n, format, ap); +} -- cgit v1.2.3-60-g2f50 From f87541521e517e8b65a196eada58aceb098ca918 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 22:53:21 -0600 Subject: stdlib: Implement most LSB functions plus more * Fix prototype of __realpath_chk. * Add all strto* functions from LSB, plus the ones thata were previously incorrectly in string.c The main missing LSB functions are the reentrant random functions, which should not be used anyway. Signed-off-by: Samuel Holland --- libgcompat/stdlib.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++--- libgcompat/string.c | 13 ------ 2 files changed, 107 insertions(+), 18 deletions(-) diff --git a/libgcompat/stdlib.c b/libgcompat/stdlib.c index 6783615..c1eaa92 100644 --- a/libgcompat/stdlib.c +++ b/libgcompat/stdlib.c @@ -1,14 +1,116 @@ #include /* assert */ -#include /* strtod */ +#include /* PATH_MAX */ +#include /* locale_t */ +#include /* NULL, size_t */ +#include /* getenv, realpath, strto* */ +#include /* get*id */ -char *__realpath_chk(const char *path, char *resolved_path) +/** + * Resolve a pathname, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---realpath-chk-1.html + */ +char *__realpath_chk(const char *path, char *resolved_path, size_t resolved_len) { assert(path != NULL); + assert(resolved_path != NULL); + assert(resolved_len >= PATH_MAX); + return realpath(path, resolved_path); } -double __strtod_internal(const char *__nptr, char **__endptr, int __group) +/** + * Get an environment variable. + */ +char *__secure_getenv(const char *name) +{ + if (geteuid() != getuid() || getegid() != getgid()) { + return NULL; + } + + return getenv(name); +} + +/** + * Underlying function for strtod. + * + * "__group shall be 0 or the behavior of __strtod_internal() is undefined." + * + * LSB 5.0: LSB-Core-generic/baselib---strtod-internal-1.html + */ +double __strtod_internal(const char *nptr, char **endptr, int group) +{ + assert(group == 0); + + return strtod(nptr, endptr); +} + +/** + * Underlying function for strtof. + * + * "__group shall be 0 or the behavior of __strtof_internal() is undefined." + * + * LSB 5.0: LSB-Core-generic/baselib---strtof-internal.html + */ +float __strtof_internal(const char *nptr, char **endptr, int group) +{ + assert(group == 0); + + return strtof(nptr, endptr); +} + +/** + * Underlying function for strtold. + * + * "__group shall be 0 or the behavior of __strtold_internal() is undefined." + * + * LSB 5.0: LSB-Core-generic/baselib---strtold-internal-1.html + */ +long double __strtold_internal(const char *nptr, char **endptr, int group) +{ + assert(group == 0); + + return strtold(nptr, endptr); +} + +/** + * Convert string value to a long long integer. + * + * Some day, when musl supports LC_NUMERIC, we can probably remove this. + */ +long long int strtoll_l(const char *nptr, char **endptr, int base, + locale_t locale) +{ + return strtoll(nptr, endptr, base); +} + +/** + * Convert string value to a long long integer. + * + * LSB 5.0: LSB-Core-generic/baselib-strtoq-3.html + */ +long long strtoq(const char *nptr, char **endptr, int base) +{ + return strtoll(nptr, endptr, base); +} + +/** + * Convert a string to an unsigned long long. + * + * Some day, when musl supports LC_NUMERIC, we can probably remove this. + */ +unsigned long long int strtoull_l(const char *nptr, char **endptr, int base, + locale_t locale) +{ + return strtoull(nptr, endptr, base); +} + +/** + * Convert a string to an unsigned long long. + * + * LSB 5.0: LSB-Core-generic/baselib-strtouq-3.html + */ +unsigned long long strtouq(const char *nptr, char **endptr, int base) { - assert(__group == 0); - return strtod(__nptr, __endptr); + return strtoull(nptr, endptr, base); } diff --git a/libgcompat/string.c b/libgcompat/string.c index 7ca0bf6..2c05caf 100644 --- a/libgcompat/string.c +++ b/libgcompat/string.c @@ -84,16 +84,3 @@ char *__strsep_g(char **stringp, const char *delim) { return strsep(stringp, delim); } - -/* Some day, when musl supports LC_NUMERIC, we can probably remove these */ -long long int strtoll_l(const char *nptr, char **endptr, int base, - locale_t locale) -{ - return strtoll(nptr, endptr, base); -} - -unsigned long long int strtoull_l(const char *nptr, char **endptr, int base, - locale_t locale) -{ - return strtoull(nptr, endptr, base); -} -- cgit v1.2.3-60-g2f50 From 48030f9988d803da367af5a3b888549851db2f58 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 23:00:13 -0600 Subject: string: Clean up, fix bugs, implement LSB plus more * Add all checked string functions from LSB, plus those found in use in other applications. Document those functions from LSB as such. * Use a consistent structure and paramater names for all functions. * Fix multiple off-by-one errors. * Use a less hacky and more optimized rawmemchr. * Sort functions by name. Signed-off-by: Samuel Holland --- libgcompat/string.c | 237 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 199 insertions(+), 38 deletions(-) diff --git a/libgcompat/string.c b/libgcompat/string.c index 2c05caf..1d387a8 100644 --- a/libgcompat/string.c +++ b/libgcompat/string.c @@ -1,86 +1,247 @@ +#define _GNU_SOURCE /* mempcpy */ #include /* assert */ -#include /* strto[u?]ll */ +#include /* NULL, size_t */ +#include /* SIZE_MAX */ #include /* memcpy, strcpy, strncat, strndup */ #include "alias.h" /* weak_alias */ -/* "Checked" memcpy */ -void *__memcpy_chk(void *dest, const void *src, size_t len, size_t destlen) +/** + * Copy bytes in memory, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---memcpy-chk-1.html + */ +void *__memcpy_chk(void *dest, const void *src, size_t n, size_t destlen) { assert(dest != NULL); assert(src != NULL); - assert(len <= destlen); - if (src < dest) { - assert(!(src + len >= dest)); + assert(destlen >= n); + if (dest < src) { + assert((char *) dest + n <= (char *) src); } else { - assert(!(dest + len >= src)); + assert((char *) src + n <= (char *) dest); } - return memcpy(dest, src, len); + + return memcpy(dest, src, n); } -/* "Checked" strncat */ -char *__strncat_chk(char *dest, const char *src, size_t n, size_t destlen) +/** + * Copy bytes in memory with overlapping areas, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---memmove-chk-1.html + */ +void *__memmove_chk(void *dest, const void *src, size_t n, size_t destlen) { assert(dest != NULL); assert(src != NULL); - assert(n <= destlen); + assert(destlen >= n); - return strncat(dest, src, n); + return memmove(dest, src, n); } -/* "Checked" strcat */ -char *__strcat_chk(char *dest, const char *src, size_t destlen) +/** + * Copy bytes in memory. + * + * LSB 5.0: LSB-Core-generic/baselib---mempcpy.html + */ +void *__mempcpy(void *dest, const void *src, size_t n) { - return strncat(dest, src, destlen - 1); + return mempcpy(dest, src, n); } -/* "Checked" strncpy */ -char *__strncpy_chk(char *dest, const char *src, size_t n, size_t destlen) +/** + * Copy bytes in memory, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---mempcpy-chk-1.html + */ +void *__mempcpy_chk(void *dest, const void *src, size_t n, size_t destlen) { assert(dest != NULL); assert(src != NULL); - assert(strlen(src) < destlen); + assert(destlen >= n); + if (dest < src) { + assert((char *) dest + n <= (char *) src); + } else { + assert((char *) src + n <= (char *) dest); + } - return strncpy(dest, src, n); + return mempcpy(dest, src, n); +} + +/** + * Set bytes in memory, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---memset-chk-1.html + */ +void *__memset_chk(void *s, int c, size_t n, size_t buflen) +{ + assert(s != NULL); + assert(buflen >= n); + + return memset(s, c, n); +} + +/** + * Find byte in memory. + * + * LSB 5.0: LSB-Core-generic/baselib---rawmemchr.html + */ +void *__rawmemchr(const void *s, int c) +{ + return memchr(s, c, SIZE_MAX); +} +weak_alias(__rawmemchr, rawmemchr); + +/** + * Copy a string and return a pointer to the end of the result, with buffer + * overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---stpcpy-chk-1.html + */ +char *__stpcpy_chk(char *dest, const char *src, size_t destlen) +{ + size_t n = strlen(src) + 1; + + assert(dest != NULL); + assert(src != NULL); + assert(destlen >= n); + if (dest < src) { + assert(dest + n <= src); + } else { + assert(src + n <= dest); + } + + return stpcpy(dest, src); +} + +/** + * Copy a fixed-length string, returning a pointer to the array end, with buffer + * overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---stpncpy-chk-1.html + */ +char *__stpncpy_chk(char *dest, const char *src, size_t n, size_t destlen) +{ + assert(dest != NULL); + assert(src != NULL); + assert(destlen >= n); + if (dest < src) { + assert(dest + n <= src); + } else { + assert(src + n <= dest); + } + + return stpncpy(dest, src, n); } -/* "Checked" strcpy */ +/** + * Concatenate two strings, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---strcat-chk-1.html + */ +char *__strcat_chk(char *dest, const char *src, size_t destlen) +{ + size_t n = strlen(src) + 1; + size_t total = strnlen(dest, destlen) + n; + + assert(dest != NULL); + assert(src != NULL); + assert(destlen >= total); + if (dest < src) { + assert(dest + total <= src); + } else { + assert(src + n <= dest); + } + + return strcat(dest, src); +} + +/** + * Copy a string, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---strcpy-chk-1.html + */ char *__strcpy_chk(char *dest, const char *src, size_t destlen) { + size_t n = strlen(src) + 1; + assert(dest != NULL); assert(src != NULL); - assert(strlen(src) < destlen); + assert(destlen >= n); + if (dest < src) { + assert(dest + n <= src); + } else { + assert(src + n <= dest); + } return strcpy(dest, src); } -/* Literally a useless __ alias. */ -char *__strndup(const char *str, size_t count) +/** + * Concatenate a string with part of another, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---strncat-chk-1.html + */ +char *__strncat_chk(char *dest, const char *src, size_t n, size_t destlen) { - return strndup(str, count); + size_t total = strnlen(dest, destlen) + n + 1; + + assert(dest != NULL); + assert(src != NULL); + assert(destlen >= total); + if (dest < src) { + assert(dest + total <= src); + } else { + assert(src + n <= dest); + } + + return strncat(dest, src, n); } -/* The existance of this method, and the fact it is used in real code, gives - * me nightmares. */ -void *__rawmemchr(const void *s, int c) +/** + * Copy a fixed-length string, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---strncpy-chk-1.html + */ +char *__strncpy_chk(char *dest, const char *src, size_t n, size_t destlen) { - const unsigned char *haystack = s; - unsigned char needle = (unsigned char) c; - while (*haystack++ != needle) - ; - return (void *) haystack; + assert(dest != NULL); + assert(src != NULL); + assert(destlen >= n); + if (dest < src) { + assert(dest + n <= src); + } else { + assert(src + n <= dest); + } + + return strncpy(dest, src, n); } -weak_alias(__rawmemchr, rawmemchr); -/* Another useless __ alias */ -char *__strtok_r(char *str, const char *delim, char **saveptr) +/** + * Duplicate a specific number of bytes from a string. + */ +char *__strndup(const char *s, size_t size) { - return strtok_r(str, delim, saveptr); + return strndup(s, size); } -/* The "global" definition of strsep in glibc, used when architecture dependent - * assembler versions aren't good enough. */ +/** + * Extract token from string. + * + * The "global" definition of strsep in glibc, used when architecture dependent + * assembler versions aren't good enough. + */ char *__strsep_g(char **stringp, const char *delim) { return strsep(stringp, delim); } + +/** + * Split string into tokens. + * + * LSB 5.0: LSB-Core-generic/baselib---strtok-r-1.html + */ +char *__strtok_r(char *s, const char *delim, char **save_ptr) +{ + return strtok_r(s, delim, save_ptr); +} -- cgit v1.2.3-60-g2f50 From 900ab571ba496f73b1e66204f8c66560afda29e6 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 23:21:32 -0600 Subject: version: Minor improvements * Document functions and sort by name. * Explicitly include stddef.h. Signed-off-by: Samuel Holland --- libgcompat/version.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/libgcompat/version.c b/libgcompat/version.c index 99c2c8c..1b7687c 100644 --- a/libgcompat/version.c +++ b/libgcompat/version.c @@ -1,16 +1,28 @@ +#include /* NULL */ #include /* getenv */ +/** + * Get glibc release. + * + * LSB 5.0: LSB-Core-generic/baselib-gnu-get-libc-version-1.html + */ +const char *gnu_get_libc_release(void) +{ + return "stable"; +} + +/** + * Get glibc version. + * + * LSB 5.0: LSB-Core-generic/baselib-gnu-get-libc-version-1.html + */ const char *gnu_get_libc_version(void) { char *ver = getenv("GLIBC_FAKE_VERSION"); + if (ver == NULL) { ver = "2.8"; } return ver; } - -const char *gnu_get_libc_release(void) -{ - return "stable"; -} -- cgit v1.2.3-60-g2f50 From b087b07c9649b7e4398093720ebcf96f205c2c49 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 23:24:00 -0600 Subject: error: Implement the error function This follows the exceptionally-detailed functional description in the manual page. Signed-off-by: Samuel Holland --- Makefile | 1 + libgcompat/error.c | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 libgcompat/error.c diff --git a/Makefile b/Makefile index b5fda64..2ff1495 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ LIBGCOMPAT_INCLUDE = \ libgcompat/alias.h LIBGCOMPAT_SRC = \ libgcompat/dlfcn.c \ + libgcompat/error.c \ libgcompat/execinfo.c \ libgcompat/gnulib.c \ libgcompat/grp.c \ diff --git a/libgcompat/error.c b/libgcompat/error.c new file mode 100644 index 0000000..c759b19 --- /dev/null +++ b/libgcompat/error.c @@ -0,0 +1,27 @@ +#define _GNU_SOURCE /* program_invocation_name */ +#include /* program_invocation_name */ +#include /* va_list, va_start, va_end */ +#include /* fflush, fputc, fputs, stderr, stdout, vfprintf */ +#include /* strerror */ + +/** + * Print an error message. + * + * LSB 5.0: LSB-Core-generic/baselib-error-n.html + */ +void error(int status, int errnum, const char *format, ...) +{ + va_list ap; + + fflush(stdout); + fputs(program_invocation_name, stderr); + fputs(": ", stderr); + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + if (errnum != 0) { + fputs(": ", stderr); + fputs(strerror(errnum), stderr); + fputc('\n', stderr); + } +} -- cgit v1.2.3-60-g2f50 From 509d6ec7c860e9c327cc9e2860a276787b4bb23f Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 23:27:19 -0600 Subject: misc: Implement some miscellaneous functions Signed-off-by: Samuel Holland --- Makefile | 1 + libgcompat/misc.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 libgcompat/misc.c diff --git a/Makefile b/Makefile index 2ff1495..5e6406d 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ LIBGCOMPAT_SRC = \ libgcompat/grp.c \ libgcompat/malloc.c \ libgcompat/math.c \ + libgcompat/misc.c \ libgcompat/pthread.c \ libgcompat/pwd.c \ libgcompat/resolv.c \ diff --git a/libgcompat/misc.c b/libgcompat/misc.c new file mode 100644 index 0000000..aee490f --- /dev/null +++ b/libgcompat/misc.c @@ -0,0 +1,33 @@ +#include /* abort, at_quick_exit */ +#include /* dev_t */ +#include /* major, makedev, minor */ + +/** + * Terminate a function in case of buffer overflow. + * + * LSB 5.0: LSB-Core-generic/baselib---chk-fail-1.html + */ +void __chk_fail(void) +{ + abort(); +} + +int __cxa_at_quick_exit(void (*func)(void), void *__dso_handle) +{ + return at_quick_exit(func); +} + +unsigned int gnu_dev_major(dev_t dev) +{ + return major(dev); +} + +dev_t gnu_dev_makedev(unsigned int maj, unsigned int min) +{ + return makedev(maj, min); +} + +unsigned int gnu_dev_minor(dev_t dev) +{ + return minor(dev); +} -- cgit v1.2.3-60-g2f50 From c13e6ac24f4139a354e068de8472eb6c831a7a23 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 23:30:25 -0600 Subject: netdb: Add protocol and service functions from LSB These take advantage of the musl implementation for simplicity. Signed-off-by: Samuel Holland --- Makefile | 1 + libgcompat/netdb.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 libgcompat/netdb.c diff --git a/Makefile b/Makefile index 5e6406d..37c7a70 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ LIBGCOMPAT_SRC = \ libgcompat/malloc.c \ libgcompat/math.c \ libgcompat/misc.c \ + libgcompat/netdb.c \ libgcompat/pthread.c \ libgcompat/pwd.c \ libgcompat/resolv.c \ diff --git a/libgcompat/netdb.c b/libgcompat/netdb.c new file mode 100644 index 0000000..ae7713a --- /dev/null +++ b/libgcompat/netdb.c @@ -0,0 +1,79 @@ +#include /* ENOENT */ +#include /* getproto* */ +#include /* NULL, size_t */ +#include /* memcpy */ + +/** + * Retrieve information from the network protocol database by protocol name, + * reentrantly. + * + * LSB 5.0: LSB-Core-generic/baselib-getprotobyname-r.html + */ +int getprotobyname_r(const char *name, struct protoent *result_buf, char *buf, + size_t buflen, struct protoent **result) +{ + struct protoent *prototmp = getprotobyname(name); + + /* musl does not reuse static storage, so no race is possible. */ + if (prototmp == NULL) { + *result = NULL; + return ENOENT; + } + *result = memcpy(result_buf, prototmp, sizeof(*result_buf)); + + return 0; +} + +/** + * Retrieve information from the network protocol database by protocol number, + * reentrantly. + * + * LSB 5.0: LSB-Core-generic/baselib-getprotobynumber-r.html + */ +int getprotobynumber_r(int proto, struct protoent *result_buf, char *buf, + size_t buflen, struct protoent **result) +{ + struct protoent *prototmp = getprotobynumber(proto); + + /* musl does not reuse static storage, so no race is possible. */ + if (prototmp == NULL) { + *result = NULL; + return ENOENT; + } + *result = memcpy(result_buf, prototmp, sizeof(*result_buf)); + + return 0; +} + +/** + * Read the next entry of the protocol database, reentrantly. + * + * LSB 5.0: LSB-Core-generic/baselib-getprotoent-r.html + */ +int getprotoent_r(struct protoent *result_buf, char *buf, size_t buflen, + struct protoent **result) +{ + struct protoent *prototmp = getprotoent(); + + /* musl does not reuse static storage, so no race is possible. */ + if (prototmp == NULL) { + *result = NULL; + return ENOENT; + } + *result = memcpy(result_buf, prototmp, sizeof(*result_buf)); + + return 0; +} + +/** + * Read the next entry of the network services database, reentrantly. + * + * LSB 5.0: LSB-Core-generic/baselib-getservent-r.html + */ +int getservent_r(struct servent *result_buf, char *buf, size_t buflen, + struct servent **result) +{ + /* musl does not implement getservent(). */ + *result = NULL; + return ENOENT; +} -- cgit v1.2.3-60-g2f50 From 8b7099b1e4ecca1357051142b589eaf24e29051c Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 23:33:24 -0600 Subject: signal: Add a signal function from LSB The other unimplemented signal function in LSB is sigreturn, with is not really implementable. Signed-off-by: Samuel Holland --- Makefile | 1 + libgcompat/signal.c | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 libgcompat/signal.c diff --git a/Makefile b/Makefile index 37c7a70..e377355 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,7 @@ LIBGCOMPAT_SRC = \ libgcompat/resolv.c \ libgcompat/resource.c \ libgcompat/setjmp.c \ + libgcompat/signal.c \ libgcompat/stdio.c \ libgcompat/stdlib.c \ libgcompat/string.c \ diff --git a/libgcompat/signal.c b/libgcompat/signal.c new file mode 100644 index 0000000..17e5443 --- /dev/null +++ b/libgcompat/signal.c @@ -0,0 +1,11 @@ +#include /* sigpause */ + +/** + * Remove a signal from the signal mask and suspend the thread. + * + * LSB 5.0: LSB-Core-generic/baselib---xpg-sigpause.html + */ +int __xpg_sigpause(int sig) +{ + return sigpause(sig); +} -- cgit v1.2.3-60-g2f50 From a6ab56ce62bc3c9fa4c63f2f13a3d5f3ea403f19 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 23:37:33 -0600 Subject: socket: Implement checked socket functions from LSB Signed-off-by: Samuel Holland --- Makefile | 1 + libgcompat/socket.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 libgcompat/socket.c diff --git a/Makefile b/Makefile index e377355..98f87ad 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ LIBGCOMPAT_SRC = \ libgcompat/resource.c \ libgcompat/setjmp.c \ libgcompat/signal.c \ + libgcompat/socket.c \ libgcompat/stdio.c \ libgcompat/stdlib.c \ libgcompat/string.c \ diff --git a/libgcompat/socket.c b/libgcompat/socket.c new file mode 100644 index 0000000..927ebe4 --- /dev/null +++ b/libgcompat/socket.c @@ -0,0 +1,31 @@ +#include /* assert */ +#include /* NULL */ +#include /* recv, recvfrom */ + +/** + * Receive a message from a connected socket, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---recv-chk-1.html + */ +ssize_t __recv_chk(int fd, void *buf, size_t len, size_t buflen, int flags) +{ + assert(buf != NULL); + assert(buflen >= len); + + return recv(fd, buf, len, flags); +} + +/** + * Receive a message from a socket, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---recvfrom-chk-1.html + */ +ssize_t __recvfrom_chk(int fd, void *buf, size_t len, size_t buflen, int flags, + struct sockaddr *address, socklen_t *address_len) +{ + assert(buf != NULL); + assert(buflen >= len); + assert(address != NULL ? address_len != NULL : address_len == NULL); + + return recvfrom(fd, buf, len, flags, address, address_len); +} -- cgit v1.2.3-60-g2f50 From d5183702e36eb43bbb0fa24e31048ca10553d3e9 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 23:39:30 -0600 Subject: syslog: Implement checked syslog functions from LSB Signed-off-by: Samuel Holland --- Makefile | 1 + libgcompat/syslog.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 libgcompat/syslog.c diff --git a/Makefile b/Makefile index 98f87ad..dbea5b6 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,7 @@ LIBGCOMPAT_SRC = \ libgcompat/stdlib.c \ libgcompat/string.c \ libgcompat/sysctl.c \ + libgcompat/syslog.c \ libgcompat/ucontext.c \ libgcompat/version.c \ libgcompat/wchar.c diff --git a/libgcompat/syslog.c b/libgcompat/syslog.c new file mode 100644 index 0000000..5409eba --- /dev/null +++ b/libgcompat/syslog.c @@ -0,0 +1,32 @@ +#include /* assert */ +#include /* va_list, va_start, va_end */ +#include /* NULL */ +#include /* vsyslog */ + +void __vsyslog_chk(int priority, int flag, const char *format, va_list ap); + +/** + * Log a message, with stack checking. + * + * LSB 5.0: LSB-Core-generic/baselib---syslog-chk-1.html + */ +void __syslog_chk(int priority, int flag, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + __vsyslog_chk(priority, flag, format, ap); + va_end(ap); +} + +/** + * Log a message, with stack checking. + * + * LSB 5.0: LSB-Core-generic/baselib---vsyslog-chk-1.html + */ +void __vsyslog_chk(int priority, int flag, const char *format, va_list ap) +{ + assert(format != NULL); + + vsyslog(priority, format, ap); +} -- cgit v1.2.3-60-g2f50 From 2d70dfb7ae8a3da8015ee9195fa600bf77358764 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 23:44:27 -0600 Subject: unistd: Implement LSB functions plus more On musl pread and pread64 are the same thing. Signed-off-by: Samuel Holland --- Makefile | 1 + libgcompat/unistd.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 libgcompat/unistd.c diff --git a/Makefile b/Makefile index dbea5b6..7996e6b 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,7 @@ LIBGCOMPAT_SRC = \ libgcompat/sysctl.c \ libgcompat/syslog.c \ libgcompat/ucontext.c \ + libgcompat/unistd.c \ libgcompat/version.c \ libgcompat/wchar.c LIBGCOMPAT_OBJ = ${LIBGCOMPAT_SRC:.c=.o} diff --git a/libgcompat/unistd.c b/libgcompat/unistd.c new file mode 100644 index 0000000..e19ec8e --- /dev/null +++ b/libgcompat/unistd.c @@ -0,0 +1,172 @@ +#include /* assert */ +#include /* NGROUPS_MAX */ +#include /* NULL, size_t */ +#include /* confstr, getcwd, getgroups, ... */ + +#include "alias.h" /* alias */ + +/** + * Get configurable variables, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---confstr-chk-1.html + */ +size_t __confstr_chk(int name, char *buf, size_t len, size_t buflen) +{ + assert(buf != NULL ? buflen >= len : len == 0); + + return confstr(name, buf, len); +} + +/** + * Get the pathname of the current working directory, with buffer overflow + * checking. + * + * LSB 5.0: LSB-Core-generic/baselib---getcwd-chk-1.html + */ +char *__getcwd_chk(char *buf, size_t len, size_t buflen) +{ + assert(buf != NULL); + assert(buflen >= len); + + return getcwd(buf, len); +} + +/** + * Get supplementary group IDs, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---getgroups-chk-1.html + */ +int __getgroups_chk(int gidsetsize, gid_t *grouplist, size_t listlen) +{ + assert(grouplist != NULL); + assert(listlen / sizeof(*grouplist) >= (size_t) gidsetsize); + + return getgroups(gidsetsize, grouplist); +} + +/** + * Get name of current host, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---gethostname-chk-1.html + */ +int __gethostname_chk(char *name, size_t namelen, size_t buflen) +{ + assert(name != NULL); + assert(buflen >= namelen); + + return gethostname(name, namelen); +} + +/** + * Get login name, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---getlogin-r-chk-1.html + */ +int __getlogin_r_chk(char *name, size_t namelen, size_t buflen) +{ + assert(name != NULL); + assert(buflen >= namelen); + + return getlogin_r(name, namelen); +} + +/** + * Get memory page size. + * + * LSB 5.0: LSB-Core-generic/baselib---getpagesize.html + */ +int __getpagesize(void) +{ + return getpagesize(); +} + +/** + * Get the process group ID for a process. + * + * LSB 5.0: LSB-Core-generic/baselib---getpgid-1.html + */ +pid_t __getpgid(pid_t pid) +{ + return getpgid(pid); +} + +/** + * Read from a file, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---pread-chk-1.html + */ +ssize_t __pread_chk(int fd, void *buf, size_t nbytes, off_t offset, + size_t buflen) +{ + assert(buf != NULL); + assert(buflen >= nbytes); + + return pread(fd, buf, nbytes, offset); +} +alias(__pread_chk, __pread64_chk); + +/** + * Read from a file, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---read-chk-1.html + */ +ssize_t __read_chk(int fd, void *buf, size_t nbytes, size_t buflen) +{ + assert(buf != NULL); + assert(buflen >= nbytes); + + return read(fd, buf, nbytes); +} + +/** + * Read the contents of a symbolic link, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---readlink-chk-1.html + */ +ssize_t __readlink_chk(const char *path, char *buf, size_t len, size_t buflen) +{ + assert(buf != NULL); + assert(buflen >= len); + + return readlink(path, buf, len); +} + +/** + * Get configurable system variables. + * + * LSB 5.0: LSB-Core-generic/baselib---sysconf.html + */ +long __sysconf(int name) +{ + return sysconf(name); +} + +/** + * Find the pathname of a terminal, with buffer overflow checking. + * + * LSB 5.0: LSB-Core-generic/baselib---ttyname-r-chk-1.html + */ +int __ttyname_r_chk(int fd, char *name, size_t namelen, size_t buflen) +{ + assert(name != NULL); + assert(buflen >= namelen); + + return ttyname_r(fd, name, namelen); +} + +/** + * Test whether a process is in a group. + */ +int group_member(gid_t gid) +{ + gid_t groups[NGROUPS_MAX]; + int ngroups = getgroups(NGROUPS_MAX, groups); + + for (int i = 0; i < ngroups; ++i) { + if (groups[i] == gid) { + return 1; + } + } + + return 0; +} -- cgit v1.2.3-60-g2f50 From bf7102a303ec86f2d9bc9fd451db78a6815ca175 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 23:46:06 -0600 Subject: utmp: Implement the reentrant utmp function from LSB This takes advantage of the (lack of a) musl implementation for simplicity. Signed-off-by: Samuel Holland --- Makefile | 1 + libgcompat/utmp.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 libgcompat/utmp.c diff --git a/Makefile b/Makefile index 7996e6b..5e5a12e 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ LIBGCOMPAT_SRC = \ libgcompat/syslog.c \ libgcompat/ucontext.c \ libgcompat/unistd.c \ + libgcompat/utmp.c \ libgcompat/version.c \ libgcompat/wchar.c LIBGCOMPAT_OBJ = ${LIBGCOMPAT_SRC:.c=.o} diff --git a/libgcompat/utmp.c b/libgcompat/utmp.c new file mode 100644 index 0000000..c2bdd91 --- /dev/null +++ b/libgcompat/utmp.c @@ -0,0 +1,14 @@ +#include /* NULL */ +#include /* struct utmp */ + +/** + * Get user accounting database entries. + * + * LSB 5.0: LSB-Core-generic/baselib-getutent-r-3.html + */ +int getutent_r(struct utmp *buffer, struct utmp **result) +{ + /* musl does not implement getutent(). */ + *result = NULL; + return -1; +} -- cgit v1.2.3-60-g2f50 From 6d391f9ef2d2588ae2faf0efb73bd1ac934b063a Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 23:54:49 -0600 Subject: readlink: Intercept readlink("/proc/self/exe") This allows programs run through gcompat to fork and re-exec themselves. It fixes readlink("/proc/self/exe") to return the executable's absolute path, instead of musl's path. Signed-off-by: Samuel Holland --- Makefile | 1 + libgcompat/readlink.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 libgcompat/readlink.c diff --git a/Makefile b/Makefile index 5e5a12e..b6bee29 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ LIBGCOMPAT_SRC = \ libgcompat/netdb.c \ libgcompat/pthread.c \ libgcompat/pwd.c \ + libgcompat/readlink.c \ libgcompat/resolv.c \ libgcompat/resource.c \ libgcompat/setjmp.c \ diff --git a/libgcompat/readlink.c b/libgcompat/readlink.c new file mode 100644 index 0000000..63def96 --- /dev/null +++ b/libgcompat/readlink.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include +#include +#include + +#ifndef LINKER +#error LINKER must be defined +#endif + +static char exe[PATH_MAX], *linker; +static ssize_t (*real_readlink)(const char *, char *, size_t); + +ssize_t readlink(const char *path, char *buf, size_t len) +{ + if (real_readlink == NULL) { + real_readlink = dlsym(RTLD_NEXT, "readlink"); + if (real_readlink == NULL) { + return -1; + } + } + + if (!strcmp(path, "/proc/self/exe")) { + int fd; + + if (exe[0] == '\0') { + if (linker == NULL) { + linker = realpath(LINKER, NULL); + if (linker == NULL) { + return -1; + } + } + if (real_readlink(path, exe, sizeof(exe)) < 1) { + goto fail; + } + if (!strcmp(exe, linker)) { + char c; + int arg = 0; + ssize_t arglen; + + fd = open("/proc/self/cmdline", + O_RDONLY | O_CLOEXEC); + if (fd < 0) { + goto fail; + } + /* Skip the --argv0/--preload ldso args. + * This number must be kept in sync with the + * argument order in loader/loader.c */ + while (arg < 5) { + if (read(fd, &c, 1) != 1) { + goto fail_close; + } + if (c == '\0') { + ++arg; + } + } + /* Read the executable path from the cmdline. */ + arglen = read(fd, exe, sizeof(exe)); + if (arglen < 1) { + goto fail_close; + } + close(fd); + /* Ensure the path exists, fits, and has NUL. */ + if (exe[0] == '\0') { + goto fail; + } + if (strnlen(exe, arglen) == (size_t) arglen) { + goto fail; + } + } + } + + return stpncpy(buf, exe, len) - buf; + + fail_close: + close(fd); + fail: + exe[0] = '\0'; + return -1; + } + + return real_readlink(path, buf, len); +} -- cgit v1.2.3-60-g2f50 From 78722ef403ffadcb78917e93e1859d43b9bf9df5 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Wed, 6 Dec 2017 03:18:58 +0000 Subject: stdlib: add __strtol_internal Signed-off-by: Samuel Holland --- libgcompat/stdlib.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libgcompat/stdlib.c b/libgcompat/stdlib.c index c1eaa92..a08f914 100644 --- a/libgcompat/stdlib.c +++ b/libgcompat/stdlib.c @@ -59,6 +59,16 @@ float __strtof_internal(const char *nptr, char **endptr, int group) return strtof(nptr, endptr); } +/** + * Underlying function for strtol. + */ +long __strtol_internal(const char *nptr, char **endptr, int base, int group) +{ + assert(group == 0); + + return strtol(nptr, endptr, base); +} + /** * Underlying function for strtold. * -- cgit v1.2.3-60-g2f50