[bpf-next,v5,1/3] bpf, x86: clean garbage values when store args from regs into stack

Message ID 20230613025226.3167956-2-imagedong@tencent.com
State New
Headers
Series bpf, x86: allow function arguments up to 12 for TRACING |

Commit Message

Menglong Dong June 13, 2023, 2:52 a.m. UTC
  From: Menglong Dong <imagedong@tencent.com>

There are garbage values in upper bytes when we store the arguments
into stack in save_regs() if the size of the argument less then 8.

As we already reserve 8 byte for the arguments in regs and stack,
it is ok to store/restore the regs in BPF_DW size. Then, the garbage
values in upper bytes will be cleaned.

Signed-off-by: Menglong Dong <imagedong@tencent.com>
---
 arch/x86/net/bpf_jit_comp.c | 35 ++++++-----------------------------
 1 file changed, 6 insertions(+), 29 deletions(-)
  

Comments

Yonghong Song June 18, 2023, 10:52 p.m. UTC | #1
On 6/12/23 7:52 PM, menglong8.dong@gmail.com wrote:
> From: Menglong Dong <imagedong@tencent.com>
> 
> There are garbage values in upper bytes when we store the arguments
> into stack in save_regs() if the size of the argument less then 8.
> 
> As we already reserve 8 byte for the arguments in regs and stack,
> it is ok to store/restore the regs in BPF_DW size. Then, the garbage
> values in upper bytes will be cleaned.

Please make it clear that there are no bugs in the existing code
since for each argument, a type case will happen like
     (parameter_type)ctx[stack_slot]
where ctx[] is an u64 type array. The compiler will generate
correct code to do type casting so garbage value will not impact
the final result. But indeed, uniformly
do save/restore with BPF_DW size can simplify code.

> 
> Signed-off-by: Menglong Dong <imagedong@tencent.com>

Acked-by: Yonghong Song <yhs@fb.com>

> ---
>   arch/x86/net/bpf_jit_comp.c | 35 ++++++-----------------------------
>   1 file changed, 6 insertions(+), 29 deletions(-)
> 
> diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
> index 1056bbf55b17..a407fbbffecd 100644
> --- a/arch/x86/net/bpf_jit_comp.c
> +++ b/arch/x86/net/bpf_jit_comp.c
> @@ -1860,57 +1860,34 @@ st:			if (is_imm8(insn->off))
>   static void save_regs(const struct btf_func_model *m, u8 **prog, int nr_regs,
>   		      int stack_size)
>   {
> -	int i, j, arg_size;
> -	bool next_same_struct = false;
> +	int i;
>   
>   	/* Store function arguments to stack.
>   	 * For a function that accepts two pointers the sequence will be:
>   	 * mov QWORD PTR [rbp-0x10],rdi
>   	 * mov QWORD PTR [rbp-0x8],rsi
>   	 */
> -	for (i = 0, j = 0; i < min(nr_regs, 6); i++) {
> -		/* The arg_size is at most 16 bytes, enforced by the verifier. */
> -		arg_size = m->arg_size[j];
> -		if (arg_size > 8) {
> -			arg_size = 8;
> -			next_same_struct = !next_same_struct;
> -		}
> -
> -		emit_stx(prog, bytes_to_bpf_size(arg_size),
> -			 BPF_REG_FP,
> +	for (i = 0; i < min(nr_regs, 6); i++)
> +		emit_stx(prog, BPF_DW, BPF_REG_FP,
>   			 i == 5 ? X86_REG_R9 : BPF_REG_1 + i,
>   			 -(stack_size - i * 8));
> -
> -		j = next_same_struct ? j : j + 1;
> -	}
>   }
>   
[...]
  
Menglong Dong June 19, 2023, 2:17 a.m. UTC | #2
On Mon, Jun 19, 2023 at 6:52 AM Yonghong Song <yhs@meta.com> wrote:
>
>
>
> On 6/12/23 7:52 PM, menglong8.dong@gmail.com wrote:
> > From: Menglong Dong <imagedong@tencent.com>
> >
> > There are garbage values in upper bytes when we store the arguments
> > into stack in save_regs() if the size of the argument less then 8.
> >
> > As we already reserve 8 byte for the arguments in regs and stack,
> > it is ok to store/restore the regs in BPF_DW size. Then, the garbage
> > values in upper bytes will be cleaned.
>
> Please make it clear that there are no bugs in the existing code
> since for each argument, a type case will happen like
>      (parameter_type)ctx[stack_slot]
> where ctx[] is an u64 type array. The compiler will generate
> correct code to do type casting so garbage value will not impact
> the final result. But indeed, uniformly
> do save/restore with BPF_DW size can simplify code.
>

Yeah, this is to prepare for the next commit and no bugs
in the existing code. I'll make it clear in the commit log in
the next version.

Thanks!
Menglong Dong

> >
> > Signed-off-by: Menglong Dong <imagedong@tencent.com>
>
> Acked-by: Yonghong Song <yhs@fb.com>
>
> > ---
> >   arch/x86/net/bpf_jit_comp.c | 35 ++++++-----------------------------
> >   1 file changed, 6 insertions(+), 29 deletions(-)
> >
> > diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
> > index 1056bbf55b17..a407fbbffecd 100644
> > --- a/arch/x86/net/bpf_jit_comp.c
> > +++ b/arch/x86/net/bpf_jit_comp.c
> > @@ -1860,57 +1860,34 @@ st:                   if (is_imm8(insn->off))
> >   static void save_regs(const struct btf_func_model *m, u8 **prog, int nr_regs,
> >                     int stack_size)
> >   {
> > -     int i, j, arg_size;
> > -     bool next_same_struct = false;
> > +     int i;
> >
> >       /* Store function arguments to stack.
> >        * For a function that accepts two pointers the sequence will be:
> >        * mov QWORD PTR [rbp-0x10],rdi
> >        * mov QWORD PTR [rbp-0x8],rsi
> >        */
> > -     for (i = 0, j = 0; i < min(nr_regs, 6); i++) {
> > -             /* The arg_size is at most 16 bytes, enforced by the verifier. */
> > -             arg_size = m->arg_size[j];
> > -             if (arg_size > 8) {
> > -                     arg_size = 8;
> > -                     next_same_struct = !next_same_struct;
> > -             }
> > -
> > -             emit_stx(prog, bytes_to_bpf_size(arg_size),
> > -                      BPF_REG_FP,
> > +     for (i = 0; i < min(nr_regs, 6); i++)
> > +             emit_stx(prog, BPF_DW, BPF_REG_FP,
> >                        i == 5 ? X86_REG_R9 : BPF_REG_1 + i,
> >                        -(stack_size - i * 8));
> > -
> > -             j = next_same_struct ? j : j + 1;
> > -     }
> >   }
> >
> [...]
  

Patch

diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 1056bbf55b17..a407fbbffecd 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -1860,57 +1860,34 @@  st:			if (is_imm8(insn->off))
 static void save_regs(const struct btf_func_model *m, u8 **prog, int nr_regs,
 		      int stack_size)
 {
-	int i, j, arg_size;
-	bool next_same_struct = false;
+	int i;
 
 	/* Store function arguments to stack.
 	 * For a function that accepts two pointers the sequence will be:
 	 * mov QWORD PTR [rbp-0x10],rdi
 	 * mov QWORD PTR [rbp-0x8],rsi
 	 */
-	for (i = 0, j = 0; i < min(nr_regs, 6); i++) {
-		/* The arg_size is at most 16 bytes, enforced by the verifier. */
-		arg_size = m->arg_size[j];
-		if (arg_size > 8) {
-			arg_size = 8;
-			next_same_struct = !next_same_struct;
-		}
-
-		emit_stx(prog, bytes_to_bpf_size(arg_size),
-			 BPF_REG_FP,
+	for (i = 0; i < min(nr_regs, 6); i++)
+		emit_stx(prog, BPF_DW, BPF_REG_FP,
 			 i == 5 ? X86_REG_R9 : BPF_REG_1 + i,
 			 -(stack_size - i * 8));
-
-		j = next_same_struct ? j : j + 1;
-	}
 }
 
 static void restore_regs(const struct btf_func_model *m, u8 **prog, int nr_regs,
 			 int stack_size)
 {
-	int i, j, arg_size;
-	bool next_same_struct = false;
+	int i;
 
 	/* Restore function arguments from stack.
 	 * For a function that accepts two pointers the sequence will be:
 	 * EMIT4(0x48, 0x8B, 0x7D, 0xF0); mov rdi,QWORD PTR [rbp-0x10]
 	 * EMIT4(0x48, 0x8B, 0x75, 0xF8); mov rsi,QWORD PTR [rbp-0x8]
 	 */
-	for (i = 0, j = 0; i < min(nr_regs, 6); i++) {
-		/* The arg_size is at most 16 bytes, enforced by the verifier. */
-		arg_size = m->arg_size[j];
-		if (arg_size > 8) {
-			arg_size = 8;
-			next_same_struct = !next_same_struct;
-		}
-
-		emit_ldx(prog, bytes_to_bpf_size(arg_size),
+	for (i = 0; i < min(nr_regs, 6); i++)
+		emit_ldx(prog, BPF_DW,
 			 i == 5 ? X86_REG_R9 : BPF_REG_1 + i,
 			 BPF_REG_FP,
 			 -(stack_size - i * 8));
-
-		j = next_same_struct ? j : j + 1;
-	}
 }
 
 static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog,