As preparation for making the cpio parsing routines more generally available improve the error handling such that we pass back a suitable errno rather than a string message, and correctly exit execution when such an error is raised. Signed-off-by: Jonathan McDowell <noodles@xxxxxx> --- include/linux/cpio.h | 1 - init/initramfs.c | 10 ++++++-- lib/cpio.c | 56 +++++++++++++++++++++++++++----------------- 3 files changed, 43 insertions(+), 24 deletions(-) diff --git a/include/linux/cpio.h b/include/linux/cpio.h index 2f9fd735331e..69a15fffa5c6 100644 --- a/include/linux/cpio.h +++ b/include/linux/cpio.h @@ -44,7 +44,6 @@ struct cpio_context { unsigned long byte_count; bool csum_present; u32 io_csum; - char *errmsg; char *collected; long remains; diff --git a/init/initramfs.c b/init/initramfs.c index 00c101d04f4b..79c3a3f42cdb 100644 --- a/init/initramfs.c +++ b/init/initramfs.c @@ -62,10 +62,16 @@ static char * __init unpack_to_rootfs(char *buf, unsigned long len) if (*buf == '0' && !(ctx.this_header & 3)) { ctx.state = CPIO_START; written = cpio_write_buffer(&ctx, buf, len); + + if (written < 0) { + pr_err("Failed to process archive: %ld\n", + written); + error("failed to process archive"); + break; + } + buf += written; len -= written; - if (ctx.errmsg) - message = ctx.errmsg; continue; } if (!*buf) { diff --git a/lib/cpio.c b/lib/cpio.c index c71bebd4cc98..5d150939704f 100644 --- a/lib/cpio.c +++ b/lib/cpio.c @@ -221,12 +221,10 @@ static int __init do_header(struct cpio_context *ctx) ctx->csum_present = false; } else if (!memcmp(ctx->collected, "070702", 6)) { ctx->csum_present = true; + } else if (memcmp(ctx->collected, "070707", 6) == 0) { + return -EPROTONOSUPPORT; } else { - if (memcmp(ctx->collected, "070707", 6) == 0) - ctx->errmsg = "incorrect cpio method used: use -H newc option"; - else - ctx->errmsg = "no cpio magic"; - return 1; + return -EINVAL; } parse_header(ctx, ctx->collected); ctx->next_header = ctx->this_header + N_ALIGN(ctx->name_len) + ctx->body_len; @@ -266,7 +264,8 @@ static int __init do_reset(struct cpio_context *ctx) while (ctx->byte_count && *ctx->victim == '\0') eat(ctx, 1); if (ctx->byte_count && (ctx->this_header & 3)) - ctx->errmsg = "broken padding"; + return -EFAULT; + return 1; } @@ -344,23 +343,29 @@ static int __init do_name(struct cpio_context *ctx) static int __init do_copy(struct cpio_context *ctx) { + int ret; + if (ctx->byte_count >= ctx->body_len) { - if (xwrite(ctx, ctx->wfile, ctx->victim, ctx->body_len, - &ctx->wfile_pos) != ctx->body_len) - ctx->errmsg = "write error"; + ret = xwrite(ctx, ctx->wfile, ctx->victim, ctx->body_len, + &ctx->wfile_pos); + if (ret != ctx->body_len) + return (ret < 0) ? ret : -EIO; do_utime_path(&ctx->wfile->f_path, ctx->mtime); fput(ctx->wfile); if (ctx->csum_present && ctx->io_csum != ctx->hdr_csum) - ctx->errmsg = "bad data checksum"; + return -EBADMSG; + eat(ctx, ctx->body_len); ctx->state = CPIO_SKIPIT; return 0; } - if (xwrite(ctx, ctx->wfile, ctx->victim, ctx->byte_count, - &ctx->wfile_pos) != ctx->byte_count) - ctx->errmsg = "write error"; + ret = xwrite(ctx, ctx->wfile, ctx->victim, ctx->byte_count, + &ctx->wfile_pos); + if (ret != ctx->byte_count) + return (ret < 0) ? ret : -EIO; + ctx->body_len -= ctx->byte_count; eat(ctx, ctx->byte_count); return 1; @@ -392,12 +397,19 @@ static __initdata int (*actions[])(struct cpio_context *) = { long __init cpio_write_buffer(struct cpio_context *ctx, char *buf, unsigned long len) { + int ret; + ctx->byte_count = len; ctx->victim = buf; - while (!actions[ctx->state](ctx)) - ; - return len - ctx->byte_count; + ret = 0; + while (ret == 0) + ret = actions[ctx->state](ctx); + + if (ret < 0) + return ret; + else + return len - ctx->byte_count; } long __init cpio_process_buffer(struct cpio_context *ctx, void *bufv, @@ -407,11 +419,13 @@ long __init cpio_process_buffer(struct cpio_context *ctx, void *bufv, long written; long left = len; - if (ctx->errmsg) - return -1; + while ((written = cpio_write_buffer(ctx, buf, left)) < left) { + char c; + + if (written < 0) + return written; - while ((written = cpio_write_buffer(ctx, buf, left)) < left && !ctx->errmsg) { - char c = buf[written]; + c = buf[written]; if (c == '0') { buf += written; @@ -422,7 +436,7 @@ long __init cpio_process_buffer(struct cpio_context *ctx, void *bufv, left -= written; ctx->state = CPIO_RESET; } else { - ctx->errmsg = "junk within compressed archive"; + return -EINVAL; } } -- 2.30.2