summaryrefslogtreecommitdiff
path: root/src/basic/fileio.c
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2019-04-08 02:22:40 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2019-04-09 15:50:16 +0900
commit15f8f026cf73b3a9c185897e184861c5f72c3862 (patch)
tree275450f1d6a8407c6ac2b64876c697eb12b147ce /src/basic/fileio.c
parent2432d09c7a7115004b16eb11bf81ffeeb32d15ad (diff)
downloadsystemd-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.c67
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) {