gen_init_cpio: fix short read file handling

When processing a "file" entry, gen_init_cpio attempts to allocate a
buffer large enough to stage the entire contents of the source file.  It
then attempts to fill the buffer via a single read() call and subsequently
writes out the entire buffer length, without checking that read() returned
the full length, potentially writing uninitialized buffer memory.

Fix this by breaking up file I/O into 64k chunks and only writing the
length returned by the prior read() call.

Link: https://lkml.kernel.org/r/20220404093429.27570-5-ddiss@suse.de
Signed-off-by: David Disseldorp <ddiss@suse.de>
Reviewed-by: Martin Wilck <mwilck@suse.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christian Brauner <christian.brauner@ubuntu.com>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
David Disseldorp 2022-05-09 18:29:20 -07:00 committed by akpm
parent 1274aea127
commit 3a2699cfbe
1 changed files with 25 additions and 19 deletions

View File

@ -20,6 +20,7 @@
#define xstr(s) #s #define xstr(s) #s
#define str(s) xstr(s) #define str(s) xstr(s)
#define MIN(a, b) ((a) < (b) ? (a) : (b))
static unsigned int offset; static unsigned int offset;
static unsigned int ino = 721; static unsigned int ino = 721;
@ -297,9 +298,8 @@ static int cpio_mkfile(const char *name, const char *location,
unsigned int nlinks) unsigned int nlinks)
{ {
char s[256]; char s[256];
char *filebuf = NULL;
struct stat buf; struct stat buf;
long size; unsigned long size;
int file = -1; int file = -1;
int retval; int retval;
int rc = -1; int rc = -1;
@ -326,22 +326,17 @@ static int cpio_mkfile(const char *name, const char *location,
buf.st_mtime = 0xffffffff; buf.st_mtime = 0xffffffff;
} }
filebuf = malloc(buf.st_size); if (buf.st_size > 0xffffffff) {
if (!filebuf) { fprintf(stderr, "%s: Size exceeds maximum cpio file size\n",
fprintf (stderr, "out of memory\n"); location);
goto error;
}
retval = read (file, filebuf, buf.st_size);
if (retval < 0) {
fprintf (stderr, "Can not read %s file\n", location);
goto error; goto error;
} }
size = 0; size = 0;
for (i = 1; i <= nlinks; i++) { for (i = 1; i <= nlinks; i++) {
/* data goes on last link */ /* data goes on last link */
if (i == nlinks) size = buf.st_size; if (i == nlinks)
size = buf.st_size;
if (name[0] == '/') if (name[0] == '/')
name++; name++;
@ -366,23 +361,34 @@ static int cpio_mkfile(const char *name, const char *location,
push_string(name); push_string(name);
push_pad(); push_pad();
if (size) { while (size) {
if (fwrite(filebuf, size, 1, stdout) != 1) { unsigned char filebuf[65536];
ssize_t this_read;
size_t this_size = MIN(size, sizeof(filebuf));
this_read = read(file, filebuf, this_size);
if (this_read <= 0 || this_read > this_size) {
fprintf(stderr, "Can not read %s file\n", location);
goto error;
}
if (fwrite(filebuf, this_read, 1, stdout) != 1) {
fprintf(stderr, "writing filebuf failed\n"); fprintf(stderr, "writing filebuf failed\n");
goto error; goto error;
} }
offset += size; offset += this_read;
push_pad(); size -= this_read;
} }
push_pad();
name += namesize; name += namesize;
} }
ino++; ino++;
rc = 0; rc = 0;
error: error:
if (filebuf) free(filebuf); if (file >= 0)
if (file >= 0) close(file); close(file);
return rc; return rc;
} }