util: introduce READ_FULL_FILE_SECURE flag for reading secure data

This commit is contained in:
Yu Watanabe
2019-04-08 02:22:40 +09:00
parent 2432d09c7a
commit 15f8f026cf
2 changed files with 59 additions and 24 deletions

View File

@@ -264,26 +264,27 @@ int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
return 1; return 1;
} }
int read_full_stream( int read_full_stream_full(
FILE *f, FILE *f,
ReadFullFileFlags flags,
char **ret_contents, char **ret_contents,
size_t *ret_size) { size_t *ret_size) {
_cleanup_free_ char *buf = NULL; _cleanup_free_ char *buf = NULL;
struct stat st; struct stat st;
size_t n, l; size_t n, n_next, l;
int fd; int fd, r;
assert(f); assert(f);
assert(ret_contents); assert(ret_contents);
n = LINE_MAX; /* Start size */ n_next = LINE_MAX; /* Start size */
fd = fileno(f); 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 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) */ * optimize our buffering) */
if (fstat(fileno(f), &st) < 0) if (fstat(fd, &st) < 0)
return -errno; return -errno;
if (S_ISREG(st.st_mode)) { 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 * 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. */ * already makes us notice the EOF. */
if (st.st_size > 0) if (st.st_size > 0)
n = st.st_size + 1; n_next = st.st_size + 1;
} }
} }
l = 0; n = l = 0;
for (;;) { for (;;) {
char *t; char *t;
size_t k; size_t k;
t = realloc(buf, n + 1); if (flags & READ_FULL_FILE_SECURE) {
if (!t) t = malloc(n_next + 1);
return -ENOMEM; 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; buf = t;
n = n_next;
errno = 0; errno = 0;
k = fread(buf + l, 1, n - l, f); k = fread(buf + l, 1, n - l, f);
if (k > 0) if (k > 0)
l += k; l += k;
if (ferror(f)) if (ferror(f)) {
return errno > 0 ? -errno : -EIO; r = errno > 0 ? -errno : -EIO;
goto finalize;
}
if (feof(f)) if (feof(f))
break; break;
@@ -327,10 +342,12 @@ int read_full_stream(
assert(l == n); assert(l == n);
/* Safety check */ /* Safety check */
if (n >= READ_FULL_BYTES_MAX) if (n >= READ_FULL_BYTES_MAX) {
return -E2BIG; r = -E2BIG;
goto finalize;
}
n = MIN(n * 2, READ_FULL_BYTES_MAX); n_next = MIN(n * 2, READ_FULL_BYTES_MAX);
} }
if (!ret_size) { 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 * 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. */ * there'd be ambiguity about what we just read. */
if (memchr(buf, 0, l)) if (memchr(buf, 0, l)) {
return -EBADMSG; r = -EBADMSG;
goto finalize;
}
} }
buf[l] = 0; buf[l] = 0;
@@ -349,21 +368,27 @@ int read_full_stream(
*ret_size = l; *ret_size = l;
return 0; 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; _cleanup_fclose_ FILE *f = NULL;
assert(fn); assert(filename);
assert(contents); assert(contents);
f = fopen(fn, "re"); f = fopen(filename, "re");
if (!f) if (!f)
return -errno; return -errno;
(void) __fsetlocking(f, FSETLOCKING_BYCALLER); (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) { int executable_is_script(const char *path, char **interpreter) {

View File

@@ -27,6 +27,10 @@ typedef enum {
} WriteStringFileFlags; } 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); 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) { static inline int write_string_stream(FILE *f, const char *line, WriteStringFileFlags flags) {
return write_string_stream_ts(f, line, flags, NULL); 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 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_one_line_file(const char *filename, char **line);
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);
int read_full_stream(FILE *f, 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); int verify_file(const char *fn, const char *blob, bool accept_extra_nl);