| From foo@baz Sun Jun 17 12:07:34 CEST 2018 |
| From: Daniel Borkmann <daniel@iogearbox.net> |
| Date: Wed, 2 May 2018 20:12:23 +0200 |
| Subject: bpf, x64: fix memleak when not converging on calls |
| |
| From: Daniel Borkmann <daniel@iogearbox.net> |
| |
| [ Upstream commit 39f56ca945af86112753646316c4c92dcd4acd82 ] |
| |
| The JIT logic in jit_subprogs() is as follows: for all subprogs we |
| allocate a bpf_prog_alloc(), populate it (prog->is_func = 1 here), |
| and pass it to bpf_int_jit_compile(). If a failure occurred during |
| JIT and prog->jited is not set, then we bail out from attempting to |
| JIT the whole program, and punt to the interpreter instead. In case |
| JITing went successful, we fixup BPF call offsets and do another |
| pass to bpf_int_jit_compile() (extra_pass is true at that point) to |
| complete JITing calls. Given that requires to pass JIT context around |
| addrs and jit_data from x86 JIT are freed in the extra_pass in |
| bpf_int_jit_compile() when calls are involved (if not, they can |
| be freed immediately). However, if in the original pass, the JIT |
| image didn't converge then we leak addrs and jit_data since image |
| itself is NULL, the prog->is_func is set and extra_pass is false |
| in that case, meaning both will become unreachable and are never |
| cleaned up, therefore we need to free as well on !image. Only x64 |
| JIT is affected. |
| |
| Fixes: 1c2a088a6626 ("bpf: x64: add JIT support for multi-function programs") |
| Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> |
| Acked-by: Alexei Starovoitov <ast@kernel.org> |
| Acked-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Alexei Starovoitov <ast@kernel.org> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/x86/net/bpf_jit_comp.c | 2 +- |
| 1 file changed, 1 insertion(+), 1 deletion(-) |
| |
| --- a/arch/x86/net/bpf_jit_comp.c |
| +++ b/arch/x86/net/bpf_jit_comp.c |
| @@ -1249,7 +1249,7 @@ out_image: |
| prog = orig_prog; |
| } |
| |
| - if (!prog->is_func || extra_pass) { |
| + if (!image || !prog->is_func || extra_pass) { |
| out_addrs: |
| kfree(addrs); |
| kfree(jit_data); |