From e66342c537343770cd574105c57e6cf725be7f71 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 21 Feb 2019 18:37:08 +0100 Subject: [PATCH] lib: Make fd_load work for non-regular files Follow-up to https://lists.samba.org/archive/samba/2018-September/217992.html and following. This also fixes a small and very theoretical race: Between the fstat and the read call the file size might change. This would make us fail on potentially legitimate files. This is more complex and probably slower, but looking at the use cases I don't think the speed matters. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13859 Signed-off-by: Volker Lendecke Reviewed-by: Andrew Bartlett Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Tue Mar 26 04:43:40 UTC 2019 on sn-devel-144 (cherry picked from commit ac487bf4d04c9771ada1ca7eeb9dac4e5fe34185) --- lib/util/util_file.c | 63 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 15 deletions(-) diff --git a/lib/util/util_file.c b/lib/util/util_file.c index 926eda240f6..29c0be91b6b 100644 --- a/lib/util/util_file.c +++ b/lib/util/util_file.c @@ -168,30 +168,63 @@ load a file into memory from a fd. **/ _PUBLIC_ char *fd_load(int fd, size_t *psize, size_t maxsize, TALLOC_CTX *mem_ctx) { - struct stat sbuf; - char *p; - size_t size; + FILE *file; + char *p = NULL; + size_t size = 0; + size_t chunk = 1024; + int err; + + if (maxsize == 0) { + maxsize = SIZE_MAX; + } - if (fstat(fd, &sbuf) != 0) return NULL; + file = fdopen(fd, "r"); + if (file == NULL) { + return NULL; + } - size = sbuf.st_size; + while (size < maxsize) { + size_t newbufsize; + size_t nread; - if (maxsize) { - size = MIN(size, maxsize); - } + chunk = MIN(chunk, (maxsize - size)); - p = (char *)talloc_size(mem_ctx, size+1); - if (!p) return NULL; + newbufsize = size + (chunk+1); /* chunk+1 can't overflow */ + if (newbufsize < size) { + goto fail; /* overflow */ + } - if (read(fd, p, size) != size) { - talloc_free(p); - return NULL; + p = talloc_realloc(mem_ctx, p, char, newbufsize); + if (p == NULL) { + goto fail; + } + + nread = fread(p+size, 1, chunk, file); + size += nread; + + if (nread != chunk) { + break; + } } - p[size] = 0; - if (psize) *psize = size; + err = ferror(file); + if (err != 0) { + goto fail; + } + p[size] = '\0'; + + if (psize != NULL) { + *psize = size; + } + + fclose(file); return p; + +fail: + TALLOC_FREE(p); + fclose(file); + return NULL; } /** -- 2.11.0