[RFCv2 4/7] bpf/kexec: Introduce three bpf kfunc for kexec

Pingfan Liu piliu at redhat.com
Wed Apr 30 03:47:05 PDT 2025


On Wed, Apr 30, 2025 at 8:04 AM Alexei Starovoitov
<alexei.starovoitov at gmail.com> wrote:
>
> On Mon, Apr 28, 2025 at 9:13 PM Pingfan Liu <piliu at redhat.com> wrote:
>  +__bpf_kfunc struct mem_range_result *bpf_kexec_decompress(char
> *image_gz_payload, int image_gz_sz,
> > +                       unsigned int expected_decompressed_sz)
> > +{
> > +       decompress_fn decompressor;
> > +       //todo, use flush to cap the memory size used by decompression
> > +       long (*flush)(void*, unsigned long) = NULL;
> > +       struct mem_range_result *range;
> > +       const char *name;
> > +       void *output_buf;
> > +       char *input_buf;
> > +       int ret;
> > +
> > +       range = kmalloc(sizeof(struct mem_range_result), GFP_KERNEL);
> > +       if (!range) {
> > +               pr_err("fail to allocate mem_range_result\n");
> > +               return NULL;
> > +       }
> > +       refcount_set(&range->usage, 1);
> > +
> > +       input_buf = vmalloc(image_gz_sz);
> > +       if (!input_buf) {
> > +               pr_err("fail to allocate input buffer\n");
> > +               kfree(range);
> > +               return NULL;
> > +       }
> > +
> > +       ret = copy_from_kernel_nofault(input_buf, image_gz_payload, image_gz_sz);
> > +       if (ret < 0) {
> > +               pr_err("Error when copying from 0x%px, size:0x%x\n",
> > +                               image_gz_payload, image_gz_sz);
> > +               kfree(range);
> > +               vfree(input_buf);
> > +               return NULL;
> > +       }
> > +
> > +       output_buf = vmalloc(expected_decompressed_sz);
> > +       if (!output_buf) {
> > +               pr_err("fail to allocate output buffer\n");
> > +               kfree(range);
> > +               vfree(input_buf);
> > +               return NULL;
> > +       }
> > +
> > +       decompressor = decompress_method(input_buf, image_gz_sz, &name);
> > +       if (!decompressor) {
> > +               pr_err("Can not find decompress method\n");
> > +               kfree(range);
> > +               vfree(input_buf);
> > +               vfree(output_buf);
> > +               return NULL;
> > +       }
> > +       //to do, use flush
> > +       ret = decompressor(image_gz_payload, image_gz_sz, NULL, NULL,
> > +                               output_buf, NULL, NULL);
> > +
> > +       /* Update the range map */
> > +       if (ret == 0) {
> > +               range->buf = output_buf;
> > +               range->size = expected_decompressed_sz;
> > +               range->status = 0;
> > +       } else {
> > +               pr_err("Decompress error\n");
> > +               vfree(output_buf);
> > +               kfree(range);
> > +               return NULL;
> > +       }
> > +       pr_info("%s, return range 0x%lx\n", __func__, range);
> > +       return range;
> > +}
>
> These kfuncs look like generic decompress routines.
> They're not related to kexec and probably should be in kernel/bpf/helpers.c
> or kernel/bpf/compression.c instead of kernel/kexec_pe_image.c.
>

Thanks for your suggestion. I originally considered using these kfuncs
only in kexec context (Later, introducing a dedicated BPF_PROG_TYPE
for kexec). They are placed under a lock so that a malice attack can
not exhaust the memory through repeatedly calling to the decompress
kfunc.

To generalize these kfunc, I think I can add some boundary control of
the memory usage to prevent such attacks.

> They also must be KF_SLEEPABLE.
> Please test your patches with all kernel debugs enabled.
> Otherwise you would have seen all these "sleeping while atomic"
> issues yourself.
>

See, I will have all these debug options for the V3 test.

Appreciate your insight.

Regards,

Pingfan




More information about the kexec mailing list