Commit 3a2699cf authored by David Disseldorp's avatar David Disseldorp Committed by Andrew Morton
Browse files

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: default avatarDavid Disseldorp <ddiss@suse.de>
Reviewed-by: default avatarMartin 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: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 1274aea1
Loading
Loading
Loading
Loading
+25 −19
Original line number Original line Diff line number Diff line
@@ -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,14 +361,25 @@ 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;
	}
	}
@@ -381,8 +387,8 @@ static int cpio_mkfile(const char *name, const char *location,
	rc = 0;
	rc = 0;


error:
error:
	if (filebuf) free(filebuf);
	if (file >= 0)
	if (file >= 0) close(file);
		close(file);
	return rc;
	return rc;
}
}