Skip to content

Commit

Permalink
fix(skipcpio): improve error checking
Browse files Browse the repository at this point in the history
Some other minor tweaks

Signed-off-by: Shreenidhi Shedi <sshedi@vmware.com>
  • Loading branch information
sshedi authored and johannbg committed Aug 27, 2021
1 parent dfbfd33 commit f6d16b6
Showing 1 changed file with 106 additions and 74 deletions.
180 changes: 106 additions & 74 deletions src/skipcpio/skipcpio.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* dracut-install.c -- install files and executables
/* skipcpio.c
Copyright (C) 2012 Harald Hoyer
Copyright (C) 2012 Red Hat, Inc. All rights reserved.
Expand Down Expand Up @@ -28,11 +28,18 @@
#include <string.h>

#define CPIO_MAGIC "070701"

#define CPIO_END "TRAILER!!!"
#define CPIO_ENDLEN (sizeof(CPIO_END) - 1)

#define CPIO_ALIGNMENT 4

#define ALIGN_UP(n, a) (((n) + (a) - 1) & (~((a) - 1)))

#define pr_err(fmt, ...) \
fprintf(stderr, "ERROR: %s:%d:%s(): " fmt, __FILE__, __LINE__, \
__func__, ##__VA_ARGS__)

struct cpio_header {
char c_magic[6];
char c_ino[8];
Expand Down Expand Up @@ -62,110 +69,135 @@ union buf_union {

static union buf_union buf;

#define ALIGN_UP(n, a) (((n) + (a) - 1) & (~((a) - 1)))

int main(int argc, char **argv)
{
FILE *f;
size_t s;
long pos = 0;
FILE *f = NULL;
char *fname = NULL;
int ret = EXIT_FAILURE;
unsigned long filesize;
unsigned long filename_length;

if (argc != 2) {
fprintf(stderr, "Usage: %s <file>\n", argv[0]);
exit(1);
goto end;
}

f = fopen(argv[1], "r");

fname = argv[1];
f = fopen(fname, "r");
if (f == NULL) {
fprintf(stderr, "Cannot open file '%s'\n", argv[1]);
exit(1);
pr_err("Cannot open file '%s'\n", fname);
goto end;
}

s = fread(&buf.cpio, sizeof(buf.cpio), 1, f);
if (s <= 0) {
fprintf(stderr, "Read error from file '%s'\n", argv[1]);
fclose(f);
exit(1);
if ((fread(&buf.cpio, sizeof(buf.cpio), 1, f) != 1) ||
ferror(f)) {
pr_err("Read error from file '%s'\n", fname);
goto end;
}
fseek(f, 0, SEEK_SET);

/* check, if this is a cpio archive */
if (memcmp(buf.cpio.h.c_magic, CPIO_MAGIC, 6) == 0) {

long pos = 0;
if (fseek(f, 0, SEEK_SET)) {
pr_err("fseek error on file '%s'\n", fname);
goto end;
}

unsigned long filesize;
unsigned long filename_length;
/* check, if this is a cpio archive */
if (memcmp(buf.cpio.h.c_magic, CPIO_MAGIC, 6)) {
goto cat_rest;
}

do {
// zero string, spilling into next unused field, to use strtol
buf.cpio.h.c_chksum[0] = 0;
filename_length = strtoul(buf.cpio.h.c_namesize, NULL, 16);
pos = ALIGN_UP(pos + sizeof(struct cpio_header) + filename_length, CPIO_ALIGNMENT);

// zero string, spilling into next unused field, to use strtol
buf.cpio.h.c_dev_maj[0] = 0;
filesize = strtoul(buf.cpio.h.c_filesize, NULL, 16);
pos = ALIGN_UP(pos + filesize, CPIO_ALIGNMENT);

if (filename_length == (CPIO_ENDLEN + 1)
&& strncmp(buf.cpio.filename, CPIO_END, CPIO_ENDLEN) == 0) {
fseek(f, pos, SEEK_SET);
break;
do {
// zero string, spilling into next unused field, to use strtol
buf.cpio.h.c_chksum[0] = 0;
filename_length = strtoul(buf.cpio.h.c_namesize, NULL, 16);
pos = ALIGN_UP(pos + sizeof(struct cpio_header) + filename_length, CPIO_ALIGNMENT);

// zero string, spilling into next unused field, to use strtol
buf.cpio.h.c_dev_maj[0] = 0;
filesize = strtoul(buf.cpio.h.c_filesize, NULL, 16);
pos = ALIGN_UP(pos + filesize, CPIO_ALIGNMENT);

if (filename_length == (CPIO_ENDLEN + 1)
&& strncmp(buf.cpio.filename, CPIO_END, CPIO_ENDLEN) == 0) {
if (fseek(f, pos, SEEK_SET)) {
pr_err("fseek\n");
goto end;
}
break;
}

if (fseek(f, pos, SEEK_SET) != 0) {
perror("fseek");
exit(1);
}
if (fseek(f, pos, SEEK_SET)) {
pr_err("fseek\n");
goto end;
}

if (fread(&buf.cpio, sizeof(buf.cpio), 1, f) != 1) {
perror("fread");
exit(1);
}
if ((fread(&buf.cpio, sizeof(buf.cpio), 1, f) != 1) ||
ferror(f)) {
pr_err("fread\n");
goto end;
}

if (memcmp(buf.cpio.h.c_magic, CPIO_MAGIC, 6) != 0) {
fprintf(stderr, "Corrupt CPIO archive!\n");
exit(1);
}
} while (!feof(f));
if (memcmp(buf.cpio.h.c_magic, CPIO_MAGIC, 6)) {
pr_err("Corrupt CPIO archive!\n");
goto end;
}
} while (!feof(f));

if (feof(f)) {
/* CPIO_END not found, just cat the whole file */
fseek(f, 0, SEEK_SET);
} else {
/* skip zeros */
do {
size_t i;
if (feof(f)) {
/* CPIO_END not found, just cat the whole file */
if (fseek(f, 0, SEEK_SET)) {
pr_err("fseek\n");
goto end;
}
} else {
/* skip zeros */
do {
size_t i;

s = fread(buf.copy_buffer, 1, sizeof(buf.copy_buffer) - 1, f);
if (s <= 0)
break;
s = fread(buf.copy_buffer, 1, sizeof(buf.copy_buffer) - 1, f);
if (ferror(f)) {
pr_err("fread\n");
goto end;
}

for (i = 0; (i < s) && (buf.copy_buffer[i] == 0); i++) ;
for (i = 0; (i < s) && (buf.copy_buffer[i] == 0); i++) ;

if (buf.copy_buffer[i] != 0) {
pos += i;
if (buf.copy_buffer[i]) {
pos += i;

fseek(f, pos, SEEK_SET);
break;
if (fseek(f, pos, SEEK_SET)) {
pr_err("fseek\n");
goto end;
}
break;
}

pos += s;
} while (!feof(f));
}
pos += s;
} while (!feof(f));
}

cat_rest:
/* cat out the rest */
while (!feof(f)) {
s = fread(buf.copy_buffer, 1, sizeof(buf.copy_buffer), f);
if (s <= 0)
break;
if (ferror(f)) {
pr_err("fread\n");
goto end;
}

s = fwrite(buf.copy_buffer, 1, s, stdout);
if (s <= 0)
break;
if (fwrite(buf.copy_buffer, 1, s, stdout) != s) {
pr_err("fwrite\n");
goto end;
}
}

ret = EXIT_SUCCESS;

end:
if (f) {
fclose(f);
}
fclose(f);

return EXIT_SUCCESS;
return ret;
}

0 comments on commit f6d16b6

Please sign in to comment.