diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2019-04-08 02:22:40 +0900 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2019-04-09 15:50:16 +0900 |
commit | 15f8f026cf73b3a9c185897e184861c5f72c3862 (patch) | |
tree | 275450f1d6a8407c6ac2b64876c697eb12b147ce /src/basic/fileio.c | |
parent | 2432d09c7a7115004b16eb11bf81ffeeb32d15ad (diff) | |
download | systemd-15f8f026cf73b3a9c185897e184861c5f72c3862.tar.gz systemd-15f8f026cf73b3a9c185897e184861c5f72c3862.tar.bz2 systemd-15f8f026cf73b3a9c185897e184861c5f72c3862.zip |
util: introduce READ_FULL_FILE_SECURE flag for reading secure data
Diffstat (limited to 'src/basic/fileio.c')
-rw-r--r-- | src/basic/fileio.c | 67 |
1 files changed, 46 insertions, 21 deletions
diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 91e0c9ec8b..028e81cf96 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -264,26 +264,27 @@ int verify_file(const char *fn, const char *blob, bool accept_extra_nl) { return 1; } -int read_full_stream( +int read_full_stream_full( FILE *f, + ReadFullFileFlags flags, char **ret_contents, size_t *ret_size) { _cleanup_free_ char *buf = NULL; struct stat st; - size_t n, l; - int fd; + size_t n, n_next, l; + int fd, r; assert(f); assert(ret_contents); - n = LINE_MAX; /* Start size */ + n_next = LINE_MAX; /* Start size */ fd = fileno(f); if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen(), let's * optimize our buffering) */ - if (fstat(fileno(f), &st) < 0) + if (fstat(fd, &st) < 0) return -errno; if (S_ISREG(st.st_mode)) { @@ -296,27 +297,41 @@ int read_full_stream( * size of 0. Note that we increase the size to read here by one, so that the first read attempt * already makes us notice the EOF. */ if (st.st_size > 0) - n = st.st_size + 1; + n_next = st.st_size + 1; } } - l = 0; + n = l = 0; for (;;) { char *t; size_t k; - t = realloc(buf, n + 1); - if (!t) - return -ENOMEM; + if (flags & READ_FULL_FILE_SECURE) { + t = malloc(n_next + 1); + if (!t) { + r = -ENOMEM; + goto finalize; + } + memcpy_safe(t, buf, n); + explicit_bzero_safe(buf, n); + } else { + t = realloc(buf, n_next + 1); + if (!t) + return -ENOMEM; + } buf = t; + n = n_next; + errno = 0; k = fread(buf + l, 1, n - l, f); if (k > 0) l += k; - if (ferror(f)) - return errno > 0 ? -errno : -EIO; + if (ferror(f)) { + r = errno > 0 ? -errno : -EIO; + goto finalize; + } if (feof(f)) break; @@ -327,10 +342,12 @@ int read_full_stream( assert(l == n); /* Safety check */ - if (n >= READ_FULL_BYTES_MAX) - return -E2BIG; + if (n >= READ_FULL_BYTES_MAX) { + r = -E2BIG; + goto finalize; + } - n = MIN(n * 2, READ_FULL_BYTES_MAX); + n_next = MIN(n * 2, READ_FULL_BYTES_MAX); } if (!ret_size) { @@ -338,8 +355,10 @@ int read_full_stream( * trailing NUL byte. But if there's an embedded NUL byte, then we should refuse operation as otherwise * there'd be ambiguity about what we just read. */ - if (memchr(buf, 0, l)) - return -EBADMSG; + if (memchr(buf, 0, l)) { + r = -EBADMSG; + goto finalize; + } } buf[l] = 0; @@ -349,21 +368,27 @@ int read_full_stream( *ret_size = l; return 0; + +finalize: + if (flags & READ_FULL_FILE_SECURE) + explicit_bzero_safe(buf, n); + + return r; } -int read_full_file(const char *fn, char **contents, size_t *size) { +int read_full_file_full(const char *filename, ReadFullFileFlags flags, char **contents, size_t *size) { _cleanup_fclose_ FILE *f = NULL; - assert(fn); + assert(filename); assert(contents); - f = fopen(fn, "re"); + f = fopen(filename, "re"); if (!f) return -errno; (void) __fsetlocking(f, FSETLOCKING_BYCALLER); - return read_full_stream(f, contents, size); + return read_full_stream_full(f, flags, contents, size); } int executable_is_script(const char *path, char **interpreter) { |