Images may consist of multiple layers, each with a distinct format. For
example, an AArch64 UKI image typically embeds a zboot image in the
.linux section. The parser therefore determines whether its output
should be forwarded to the next stage.

Intermediate results are stored in next_parsing_buf and then promoted to
parsing_buf for the subsequent stage.

Signed-off-by: Pingfan Liu <[email protected]>
Cc: Baoquan He <[email protected]>
Cc: Dave Young <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Philipp Rudo <[email protected]>
To: [email protected]
---
 kernel/kexec_bpf_loader.c | 47 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 46 insertions(+), 1 deletion(-)

diff --git a/kernel/kexec_bpf_loader.c b/kernel/kexec_bpf_loader.c
index af16f7b685d9a..7f7884411e2c7 100644
--- a/kernel/kexec_bpf_loader.c
+++ b/kernel/kexec_bpf_loader.c
@@ -41,6 +41,8 @@ struct kexec_context {
        bool parsed;
        char *parsing_buf[MAX_PARSING_BUF_NUM];
        unsigned long parsing_buf_sz[MAX_PARSING_BUF_NUM];
+       char *next_parsing_buf[MAX_PARSING_BUF_NUM];
+       unsigned long next_parsing_buf_sz[MAX_PARSING_BUF_NUM];
 
        char *kernel;
        unsigned long kernel_sz;
@@ -278,8 +280,9 @@ static int kexec_buff_parser(struct bpf_parser_context 
*parser)
        struct bpf_parser_buf *pbuf = parser->buf;
        struct kexec_context *ctx = (struct kexec_context *)parser->data;
        struct cmd_hdr *cmd = (struct cmd_hdr *)pbuf->buf;
-       char *decompressed_buf, *buf, *p;
+       char *decompressed_buf, *buf, *p, *pn;
        unsigned long decompressed_sz;
+       bool fill_pipeline = false;
        int ret = 0;
 
        buf = pbuf->buf + sizeof(struct cmd_hdr);
@@ -288,6 +291,7 @@ static int kexec_buff_parser(struct bpf_parser_context 
*parser)
                                cmd->payload_len, pbuf->size);
                return -EINVAL;
        }
+       fill_pipeline = cmd->pipeline_flag & KEXEC_BPF_PIPELINE_FILL;
        switch (cmd->cmd) {
        case KEXEC_BPF_CMD_DONE:
                ctx->parsed = true;
@@ -301,6 +305,23 @@ static int kexec_buff_parser(struct bpf_parser_context 
*parser)
                                vfree(ctx->kernel);
                                ctx->kernel = decompressed_buf;
                                ctx->kernel_sz = decompressed_sz;
+                               if (fill_pipeline) {
+                                       int i;
+
+                                       for (i = 0; i < MAX_PARSING_BUF_NUM; 
i++) {
+                                               if (ctx->next_parsing_buf[i])
+                                                       continue;
+                                               ctx->next_parsing_buf[i] = 
decompressed_buf;
+                                               ctx->next_parsing_buf_sz[i] = 
decompressed_sz;
+                                               break;
+                                       }
+                                       /* No enough parsing slot */
+                                       if (i == MAX_PARSING_BUF_NUM) {
+                                               ctx->kernel = NULL;
+                                               vfree(decompressed_buf);
+                                               return -ENOMEM;
+                                       }
+                               }
                                break;
                        default:
                                vfree(decompressed_buf);
@@ -313,6 +334,22 @@ static int kexec_buff_parser(struct bpf_parser_context 
*parser)
                if (!p)
                        return -ENOMEM;
                memcpy(p, buf, cmd->payload_len);
+               if (fill_pipeline) {
+                       pn = __vmalloc(cmd->payload_len, GFP_KERNEL | 
__GFP_ACCOUNT);
+                       if (!pn) {
+                               vfree(p);
+                               return -ENOMEM;
+                       }
+                       memcpy(pn, buf, cmd->payload_len);
+                       for (int i = 0; i < MAX_PARSING_BUF_NUM; i++) {
+                               if (!ctx->next_parsing_buf[i]) {
+                                       ctx->next_parsing_buf[i] = pn;
+                                       ctx->next_parsing_buf_sz[i] = 
cmd->payload_len;
+                                       break;
+                               }
+                       }
+               }
+
                switch (cmd->subcmd) {
                case KEXEC_BPF_SUBCMD_KERNEL:
                        vfree(ctx->kernel);
@@ -637,6 +674,14 @@ static int process_bpf_parsers_container(const char 
*elf_buf, size_t elf_sz,
                        context->parsing_buf[i] = NULL;
                        context->parsing_buf_sz[i] = 0;
                }
+               for (int i = 0; i < MAX_PARSING_BUF_NUM; i++) {
+                       if (!context->next_parsing_buf[i])
+                               break;
+                       context->parsing_buf[i] = context->next_parsing_buf[i];
+                       context->parsing_buf_sz[i] = 
context->next_parsing_buf_sz[i];
+                       context->next_parsing_buf[i] = NULL;
+                       context->next_parsing_buf_sz[i] = 0;
+               }
 
                put_bpf_parser_context(bpf);
                /* If the bpf-prog success, it flags by KEXEC_BPF_CMD_DONE */
-- 
2.49.0

Reply via email to