summaryrefslogtreecommitdiff
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
parent2432d09c7a7115004b16eb11bf81ffeeb32d15ad (diff)
downloadsystemd-15f8f026cf73b3a9c185897e184861c5f72c3862.tar.gz
util: introduce READ_FULL_FILE_SECURE flag for reading secure data
-rw-r--r--src/basic/fileio.c67
-rw-r--r--src/basic/fileio.h16
2 files changed, 59 insertions, 24 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) {
diff --git a/src/basic/fileio.h b/src/basic/fileio.h
index 53e3f4ef5f..b5b34fe1c3 100644
--- a/src/basic/fileio.h
+++ b/src/basic/fileio.h
@@ -27,6 +27,10 @@ typedef enum {
} WriteStringFileFlags;
+typedef enum {
+ READ_FULL_FILE_SECURE = 1 << 0,
+} ReadFullFileFlags;
+
int write_string_stream_ts(FILE *f, const char *line, WriteStringFileFlags flags, struct timespec *ts);
static inline int write_string_stream(FILE *f, const char *line, WriteStringFileFlags flags) {
return write_string_stream_ts(f, line, flags, NULL);
@@ -38,9 +42,15 @@ static inline int write_string_file(const char *fn, const char *line, WriteStrin
int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *format, ...) _printf_(3, 4);
-int read_one_line_file(const char *fn, char **line);
-int read_full_file(const char *fn, char **contents, size_t *size);
-int read_full_stream(FILE *f, char **contents, size_t *size);
+int read_one_line_file(const char *filename, char **line);
+int read_full_file_full(const char *filename, ReadFullFileFlags flags, char **contents, size_t *size);
+static inline int read_full_file(const char *filename, char **contents, size_t *size) {
+ return read_full_file_full(filename, 0, contents, size);
+}
+int read_full_stream_full(FILE *f, ReadFullFileFlags flags, char **contents, size_t *size);
+static inline int read_full_stream(FILE *f, char **contents, size_t *size) {
+ return read_full_stream_full(f, 0, contents, size);
+}
int verify_file(const char *fn, const char *blob, bool accept_extra_nl);