diff options
author | Oliver O'Halloran <oohall@gmail.com> | 2020-06-09 14:40:51 +1000 |
---|---|---|
committer | Oliver O'Halloran <oohal@users.noreply.github.com> | 2020-06-11 10:22:43 +1000 |
commit | cfd6168cdd763d722fa7327317ea643c3422bb5c (patch) | |
tree | 9a5b5ad92490489b25c3ab7ec391a9ec62f69b3e /external | |
parent | 3da602776f445f50488d9407661f1addd1eac180 (diff) | |
download | skiboot-cfd6168cdd763d722fa7327317ea643c3422bb5c.zip skiboot-cfd6168cdd763d722fa7327317ea643c3422bb5c.tar.gz skiboot-cfd6168cdd763d722fa7327317ea643c3422bb5c.tar.bz2 |
external/ffspart: Use read() rather than mmap()
The various ffspart test cases use /dev/zero as an input which doesn't
behave like a normal file. The stat.st_size field for char devs is
generally zero so the subsequent attempt to mmap() the file fails
because we requested a zero size mapping.
Previously we didn't notice this, but it sort of worked since the
partitions in the test script that used /dev/zero as an input were
also had those partitions marked as ECC. This resulted in the partition
contents being re-generated (using a buffer libflash allocates) and
the source data pointer being ignored since we said it was zero length.
Fix all this by dropping mmap() entirely and inhale the input file into
a buffer we malloc() instead. This works for any file, including
/dev/urandom, which can't be mmap()ed.
Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
Diffstat (limited to 'external')
-rw-r--r-- | external/ffspart/ffspart.c | 42 |
1 files changed, 34 insertions, 8 deletions
diff --git a/external/ffspart/ffspart.c b/external/ffspart/ffspart.c index d41bdfd..98e790b 100644 --- a/external/ffspart/ffspart.c +++ b/external/ffspart/ffspart.c @@ -241,6 +241,8 @@ static int parse_entry(struct blocklevel_device *bl, ffs_entry_put(new_entry); if (*line != '\0' && *(line + 1) != '\0') { + size_t data_len; + filename = line + 1; /* @@ -263,9 +265,30 @@ static int parse_entry(struct blocklevel_device *bl, close(data_fd); return -1; } + + data_ptr = calloc(1, psize); + if (!data_ptr) { + return -1; + } + pactual = data_stat.st_size; /* + * There's two char device inputs we care about: /dev/zero and + * /dev/urandom. Both have a stat.st_size of zero so read in + * a full partition worth, accounting for ECC overhead. + */ + if (!pactual && S_ISCHR(data_stat.st_mode)) { + pactual = psize; + + if (has_ecc(new_entry)) { + pactual = ecc_buffer_size_minus_ecc(pactual); + + /* ECC input size needs to be a multiple of 8 */ + pactual = pactual & ~0x7; + } + } + /* * Sanity check that the file isn't too large for * partition */ @@ -279,19 +302,22 @@ static int parse_entry(struct blocklevel_device *bl, return -1; } - data_ptr = mmap(NULL, pactual, PROT_READ, MAP_SHARED, data_fd, 0); - if (!data_ptr) { - fprintf(stderr, "Couldn't mmap file '%s' for '%s' partition " - "(%m)\n", filename, name); - close(data_fd); - return -1; + for (data_len = 0; data_len < pactual; data_len += rc) { + rc = read(data_fd, &data_ptr[data_len], pactual - data_len); + if (rc == -1) { + fprintf(stderr, "error reading from '%s'", filename); + exit(1); + } } rc = blocklevel_write(bl, pbase, data_ptr, pactual); - if (rc) + if (rc) { fprintf(stderr, "Couldn't write file '%s' for '%s' partition to PNOR " "(%m)\n", filename, name); - munmap(data_ptr, pactual); + exit(1); + } + + free(data_ptr); close(data_fd); } else { if (!allow_empty) { |