lib: Make fd_load work for non-regular files
authorVolker Lendecke <vl@samba.org>
Thu, 21 Feb 2019 17:37:08 +0000 (18:37 +0100)
committerKarolin Seeger <kseeger@samba.org>
Tue, 2 Apr 2019 09:10:56 +0000 (09:10 +0000)
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 <vl@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Autobuild-User(master): Andrew Bartlett <abartlet@samba.org>
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

index 926eda240f6c196d02cd6933521b8db631f2cd3f..29c0be91b6b6eb9020b49e4801d17fc6983e695c 100644 (file)
@@ -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;
 }
 
 /**