From: Volker Lendecke Date: Thu, 21 Feb 2019 17:37:08 +0000 (+0100) Subject: lib: Make fd_load work for non-regular files X-Git-Tag: tdb-1.4.1~622 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ac487bf4d04c9771ada1ca7eeb9dac4e5fe34185;p=thirdparty%2Fsamba.git 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 --- diff --git a/lib/util/util_file.c b/lib/util/util_file.c index 90d39f7cdd3..7a8644e3f5d 100644 --- a/lib/util/util_file.c +++ b/lib/util/util_file.c @@ -170,30 +170,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; } /**