From 5518859b6609d7a3df332fbcb68e7bdab3c6be9c Mon Sep 17 00:00:00 2001 From: Andrew Bettison Date: Mon, 25 Feb 2013 15:25:53 +1030 Subject: [PATCH] Refactor: move read_symlink() from log.c to os.c --- log.c | 43 +------------------------------------------ os.c | 17 +++++++++++++++++ os.h | 30 ++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 42 deletions(-) diff --git a/log.c b/log.c index 6c7eb0cc..a4712d8c 100644 --- a/log.c +++ b/log.c @@ -36,6 +36,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "log.h" #include "net.h" +#include "os.h" #include "conf.h" #include "str.h" #include "strbuf.h" @@ -303,48 +304,6 @@ int logDump(int level, struct __sourceloc whence, char *name, const unsigned cha return 0; } -/* Read the symbolic link into the supplied buffer and add a terminating nul. Return -1 if the - * buffer is too short to hold the link content and the nul. If readlink(2) returns an error, then - * logs it and returns -1. Otherwise, returns the number of bytes read, including the terminating - * nul, ie, returns what readlink(2) returns plus one. If the 'len' argument is given as zero, then - * returns the number of bytes that would be read, by calling lstat(2) instead of readlink(2), plus - * one for the terminating nul. Beware of the following race condition: a symbolic link may be - * altered between calling the lstat(2) and readlink(2), so the following apparently overflow-proof - * code may still fail from a buffer overflow in the second call to read_symlink(): - * - * char *readlink_malloc(const char *path) { - * ssize_t len = read_symlink(path, NULL, 0); - * if (len == -1) - * return NULL; - * char *buf = malloc(len); - * if (buf == NULL) - * return NULL; - * if (read_symlink(path, buf, len) == -1) { - * free(buf); - * return NULL; - * } - * return buf; - * } - * - * @author Andrew Bettison - */ -ssize_t read_symlink(const char *path, char *buf, size_t len) -{ - if (len == 0) { - struct stat stat; - if (lstat(path, &stat) == -1) - return WHYF_perror("lstat(%s)", path); - return stat.st_size; - } - ssize_t nr = readlink(path, buf, len); - if (nr == -1) - return WHYF_perror("readlink(%s)", path); - if (nr >= len) - return WHYF("buffer overrun from readlink(%s, len=%lu)", path, (unsigned long) len); - buf[nr] = '\0'; - return nr; -} - ssize_t get_self_executable_path(char *buf, size_t len) { #if defined(linux) diff --git a/os.c b/os.c index 61426349..769ea99b 100644 --- a/os.c +++ b/os.c @@ -140,3 +140,20 @@ time_ms_t sleep_ms(time_ms_t milliseconds) FATALF_perror("nanosleep(tv_sec=%ld, tv_nsec=%ld)", delay.tv_sec, delay.tv_nsec); return remain.tv_sec * 1000 + remain.tv_nsec / 1000000; } + +ssize_t read_symlink(const char *path, char *buf, size_t len) +{ + if (len == 0) { + struct stat stat; + if (lstat(path, &stat) == -1) + return WHYF_perror("lstat(%s)", path); + return stat.st_size; + } + ssize_t nr = readlink(path, buf, len); + if (nr == -1) + return WHYF_perror("readlink(%s)", path); + if (nr >= len) + return WHYF("buffer overrun from readlink(%s, len=%lu)", path, (unsigned long) len); + buf[nr] = '\0'; + return nr; +} diff --git a/os.h b/os.h index 9ef888a9..3bb4f8ed 100644 --- a/os.h +++ b/os.h @@ -75,4 +75,34 @@ int mkdirsn(const char *path, size_t len, mode_t mode); void srandomdev(); int urandombytes(unsigned char *buf, unsigned long long len); +/* Read the symbolic link into the supplied buffer and add a terminating nul. + * Logs an ERROR and returns -1 if the buffer is too short to hold the link + * content and the terminating nul. If readlink(2) returns an error, then logs + * an ERROR and returns -1. Otherwise, returns the number of bytes read, + * including the terminating nul, ie, returns what readlink(2) returns plus + * one. If the 'len' argument is given as zero, then returns the number of + * bytes that would be read, by calling lstat(2) instead of readlink(2), plus + * one for the terminating nul. Beware of the following race condition: a + * symbolic link may be altered between calling the lstat(2) and readlink(2), + * so the following apparently overflow-proof code may still fail from a buffer + * overflow in the second call to read_symlink(): + * + * char *readlink_malloc(const char *path) { + * ssize_t len = read_symlink(path, NULL, 0); + * if (len == -1) + * return NULL; + * char *buf = malloc(len); + * if (buf == NULL) + * return NULL; + * if (read_symlink(path, buf, len) == -1) { + * free(buf); + * return NULL; + * } + * return buf; + * } + * + * @author Andrew Bettison + */ +ssize_t read_symlink(const char *path, char *buf, size_t len); + #endif //__SERVALDNA_OS_H