diff mbox series

[bpf-next,v2,05/15] bpf: Support new signed div/mod instructions.

Message ID 20230713060744.390929-1-yhs@fb.com (mailing list archive)
State Superseded
Delegated to: BPF
Headers show
Series bpf: Support new insns from cpu v4 | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-PR fail PR summary
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ${{ matrix.test }} on ${{ matrix.arch }} with ${{ matrix.toolchain_full }}
bpf/vmtest-bpf-next-VM_Test-2 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-3 fail Logs for build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-4 fail Logs for build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-5 fail Logs for build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-6 fail Logs for build for x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-7 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-8 success Logs for veristat
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for bpf-next, async
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 27 this patch: 27
netdev/cc_maintainers warning 16 maintainers not CCed: tglx@linutronix.de hpa@zytor.com dsahern@kernel.org mingo@redhat.com kpsingh@kernel.org x86@kernel.org john.fastabend@gmail.com sdf@google.com netdev@vger.kernel.org martin.lau@linux.dev song@kernel.org dave.hansen@linux.intel.com davem@davemloft.net jolsa@kernel.org haoluo@google.com bp@alien8.de
netdev/build_clang fail Errors and warnings before: 18 this patch: 18
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 27 this patch: 27
netdev/checkpatch warning CHECK: No space is necessary after a cast WARNING: line length of 82 exceeds 80 columns WARNING: line length of 89 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Yonghong Song July 13, 2023, 6:07 a.m. UTC
Add interpreter/jit support for new signed div/mod insns.
The new signed div/mod instructions are encoded with
unsigned div/mod instructions plus insn->off == 1.
Also add basic verifier support to ensure new insns get
accepted.

Signed-off-by: Yonghong Song <yhs@fb.com>
---
 arch/x86/net/bpf_jit_comp.c | 27 +++++++----
 kernel/bpf/core.c           | 96 ++++++++++++++++++++++++++++++-------
 kernel/bpf/verifier.c       |  6 ++-
 3 files changed, 103 insertions(+), 26 deletions(-)

Comments

Eduard Zingerman July 18, 2023, 11 p.m. UTC | #1
On Wed, 2023-07-12 at 23:07 -0700, Yonghong Song wrote:
> Add interpreter/jit support for new signed div/mod insns.
> The new signed div/mod instructions are encoded with
> unsigned div/mod instructions plus insn->off == 1.
> Also add basic verifier support to ensure new insns get
> accepted.
> 
> Signed-off-by: Yonghong Song <yhs@fb.com>
> ---
>  arch/x86/net/bpf_jit_comp.c | 27 +++++++----
>  kernel/bpf/core.c           | 96 ++++++++++++++++++++++++++++++-------
>  kernel/bpf/verifier.c       |  6 ++-
>  3 files changed, 103 insertions(+), 26 deletions(-)
> 
> diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
> index adda5e7626b4..3176b60d25c7 100644
> --- a/arch/x86/net/bpf_jit_comp.c
> +++ b/arch/x86/net/bpf_jit_comp.c
> @@ -1194,15 +1194,26 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
>  				/* mov rax, dst_reg */
>  				emit_mov_reg(&prog, is64, BPF_REG_0, dst_reg);
>  
> -			/*
> -			 * xor edx, edx
> -			 * equivalent to 'xor rdx, rdx', but one byte less
> -			 */
> -			EMIT2(0x31, 0xd2);
> +			if (insn->off == 0) {
> +				/*
> +				 * xor edx, edx
> +				 * equivalent to 'xor rdx, rdx', but one byte less
> +				 */
> +				EMIT2(0x31, 0xd2);
>  
> -			/* div src_reg */
> -			maybe_emit_1mod(&prog, src_reg, is64);
> -			EMIT2(0xF7, add_1reg(0xF0, src_reg));
> +				/* div src_reg */
> +				maybe_emit_1mod(&prog, src_reg, is64);
> +				EMIT2(0xF7, add_1reg(0xF0, src_reg));
> +			} else {
> +				if (BPF_CLASS(insn->code) == BPF_ALU)
> +					EMIT1(0x99); /* cltd */
> +				else
> +					EMIT2(0x48, 0x99); /* cqto */

Nitpick: I can't find names cltd/cqto in the Intel instruction manual,
         instead it uses names cdq/cqo for these instructions.
         (See Vol. 2A pages 3-315 and 3-497)

> +
> +				/* idiv src_reg */
> +				maybe_emit_1mod(&prog, src_reg, is64);
> +				EMIT2(0xF7, add_1reg(0xF8, src_reg));
> +			}
>  
>  			if (BPF_OP(insn->code) == BPF_MOD &&
>  			    dst_reg != BPF_REG_3)
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index 86bb412fee39..6f7134657935 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
> @@ -1789,36 +1789,100 @@ static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn)
>  		(*(s64 *) &DST) >>= IMM;
>  		CONT;
>  	ALU64_MOD_X:
> -		div64_u64_rem(DST, SRC, &AX);
> -		DST = AX;
> +		switch (OFF) {
> +		case 0:
> +			div64_u64_rem(DST, SRC, &AX);
> +			DST = AX;
> +			break;
> +		case 1:
> +			AX = div64_s64(DST, SRC);
> +			DST = DST - AX * SRC;
> +			break;
> +		}
>  		CONT;
>  	ALU_MOD_X:
> -		AX = (u32) DST;
> -		DST = do_div(AX, (u32) SRC);
> +		switch (OFF) {
> +		case 0:
> +			AX = (u32) DST;
> +			DST = do_div(AX, (u32) SRC);
> +			break;
> +		case 1:
> +			AX = (s32) DST;
> +			DST = (u32)do_div(AX, (s32) SRC);
> +			break;
> +		}
>  		CONT;
>  	ALU64_MOD_K:
> -		div64_u64_rem(DST, IMM, &AX);
> -		DST = AX;
> +		switch (OFF) {
> +		case 0:
> +			div64_u64_rem(DST, IMM, &AX);
> +			DST = AX;
> +			break;
> +		case 1:
> +			AX = div64_s64(DST, IMM);
> +			DST = DST - AX * IMM;
> +			break;
> +		}
>  		CONT;
>  	ALU_MOD_K:
> -		AX = (u32) DST;
> -		DST = do_div(AX, (u32) IMM);
> +		switch (OFF) {
> +		case 0:
> +			AX = (u32) DST;
> +			DST = do_div(AX, (u32) IMM);
> +			break;
> +		case 1:
> +			AX = (s32) DST;
> +			DST = (u32)do_div(AX, (s32) IMM);
> +			break;
> +		}
>  		CONT;
>  	ALU64_DIV_X:
> -		DST = div64_u64(DST, SRC);
> +		switch (OFF) {
> +		case 0:
> +			DST = div64_u64(DST, SRC);
> +			break;
> +		case 1:
> +			DST = div64_s64(DST, SRC);
> +			break;
> +		}
>  		CONT;
>  	ALU_DIV_X:
> -		AX = (u32) DST;
> -		do_div(AX, (u32) SRC);
> -		DST = (u32) AX;
> +		switch (OFF) {
> +		case 0:
> +			AX = (u32) DST;
> +			do_div(AX, (u32) SRC);
> +			DST = (u32) AX;
> +			break;
> +		case 1:
> +			AX = (s32) DST;
> +			do_div(AX, (s32) SRC);
> +			DST = (u32) AX;
> +			break;
> +		}
>  		CONT;
>  	ALU64_DIV_K:
> -		DST = div64_u64(DST, IMM);
> +		switch (OFF) {
> +		case 0:
> +			DST = div64_u64(DST, IMM);
> +			break;
> +		case 1:
> +			DST = div64_s64(DST, IMM);
> +			break;
> +		}
>  		CONT;
>  	ALU_DIV_K:
> -		AX = (u32) DST;
> -		do_div(AX, (u32) IMM);
> -		DST = (u32) AX;
> +		switch (OFF) {
> +		case 0:
> +			AX = (u32) DST;
> +			do_div(AX, (u32) IMM);
> +			DST = (u32) AX;
> +			break;
> +		case 1:
> +			AX = (s32) DST;
> +			do_div(AX, (s32) IMM);
> +			DST = (u32) AX;
> +			break;
> +		}
>  		CONT;
>  	ALU_END_TO_BE:
>  		switch (IMM) {
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 22ba0744547b..b606c8ed5470 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -13192,7 +13192,8 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
>  	} else {	/* all other ALU ops: and, sub, xor, add, ... */
>  
>  		if (BPF_SRC(insn->code) == BPF_X) {
> -			if (insn->imm != 0 || insn->off != 0) {
> +			if (insn->imm != 0 || insn->off > 1 ||
> +			    (insn->off == 1 && opcode != BPF_MOD && opcode != BPF_DIV)) {
>  				verbose(env, "BPF_ALU uses reserved fields\n");
>  				return -EINVAL;
>  			}
> @@ -13201,7 +13202,8 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
>  			if (err)
>  				return err;
>  		} else {
> -			if (insn->src_reg != BPF_REG_0 || insn->off != 0) {
> +			if (insn->src_reg != BPF_REG_0 || insn->off > 1 ||
> +			    (insn->off == 1 && opcode != BPF_MOD && opcode != BPF_DIV)) {
>  				verbose(env, "BPF_ALU uses reserved fields\n");
>  				return -EINVAL;
>  			}
Yonghong Song July 19, 2023, 2:30 a.m. UTC | #2
On 7/18/23 4:00 PM, Eduard Zingerman wrote:
> On Wed, 2023-07-12 at 23:07 -0700, Yonghong Song wrote:
>> Add interpreter/jit support for new signed div/mod insns.
>> The new signed div/mod instructions are encoded with
>> unsigned div/mod instructions plus insn->off == 1.
>> Also add basic verifier support to ensure new insns get
>> accepted.
>>
>> Signed-off-by: Yonghong Song <yhs@fb.com>
>> ---
>>   arch/x86/net/bpf_jit_comp.c | 27 +++++++----
>>   kernel/bpf/core.c           | 96 ++++++++++++++++++++++++++++++-------
>>   kernel/bpf/verifier.c       |  6 ++-
>>   3 files changed, 103 insertions(+), 26 deletions(-)
>>
>> diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
>> index adda5e7626b4..3176b60d25c7 100644
>> --- a/arch/x86/net/bpf_jit_comp.c
>> +++ b/arch/x86/net/bpf_jit_comp.c
>> @@ -1194,15 +1194,26 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
>>   				/* mov rax, dst_reg */
>>   				emit_mov_reg(&prog, is64, BPF_REG_0, dst_reg);
>>   
>> -			/*
>> -			 * xor edx, edx
>> -			 * equivalent to 'xor rdx, rdx', but one byte less
>> -			 */
>> -			EMIT2(0x31, 0xd2);
>> +			if (insn->off == 0) {
>> +				/*
>> +				 * xor edx, edx
>> +				 * equivalent to 'xor rdx, rdx', but one byte less
>> +				 */
>> +				EMIT2(0x31, 0xd2);
>>   
>> -			/* div src_reg */
>> -			maybe_emit_1mod(&prog, src_reg, is64);
>> -			EMIT2(0xF7, add_1reg(0xF0, src_reg));
>> +				/* div src_reg */
>> +				maybe_emit_1mod(&prog, src_reg, is64);
>> +				EMIT2(0xF7, add_1reg(0xF0, src_reg));
>> +			} else {
>> +				if (BPF_CLASS(insn->code) == BPF_ALU)
>> +					EMIT1(0x99); /* cltd */
>> +				else
>> +					EMIT2(0x48, 0x99); /* cqto */
> 
> Nitpick: I can't find names cltd/cqto in the Intel instruction manual,
>           instead it uses names cdq/cqo for these instructions.
>           (See Vol. 2A pages 3-315 and 3-497)

I got these asm names from
   https://defuse.ca/online-x86-assembler.htm
I will check the Intel insn manual and make the change
accordingly.

> 
>> +
>> +				/* idiv src_reg */
>> +				maybe_emit_1mod(&prog, src_reg, is64);
>> +				EMIT2(0xF7, add_1reg(0xF8, src_reg));
>> +			}
>>   
>>   			if (BPF_OP(insn->code) == BPF_MOD &&
>>   			    dst_reg != BPF_REG_3)
[...]
Alexei Starovoitov July 19, 2023, 2:44 a.m. UTC | #3
On Tue, Jul 18, 2023 at 7:31 PM Yonghong Song <yhs@meta.com> wrote:
>
>
>
> On 7/18/23 4:00 PM, Eduard Zingerman wrote:
> > On Wed, 2023-07-12 at 23:07 -0700, Yonghong Song wrote:
> >> Add interpreter/jit support for new signed div/mod insns.
> >> The new signed div/mod instructions are encoded with
> >> unsigned div/mod instructions plus insn->off == 1.
> >> Also add basic verifier support to ensure new insns get
> >> accepted.
> >>
> >> Signed-off-by: Yonghong Song <yhs@fb.com>
> >> ---
> >>   arch/x86/net/bpf_jit_comp.c | 27 +++++++----
> >>   kernel/bpf/core.c           | 96 ++++++++++++++++++++++++++++++-------
> >>   kernel/bpf/verifier.c       |  6 ++-
> >>   3 files changed, 103 insertions(+), 26 deletions(-)
> >>
> >> diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
> >> index adda5e7626b4..3176b60d25c7 100644
> >> --- a/arch/x86/net/bpf_jit_comp.c
> >> +++ b/arch/x86/net/bpf_jit_comp.c
> >> @@ -1194,15 +1194,26 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
> >>                              /* mov rax, dst_reg */
> >>                              emit_mov_reg(&prog, is64, BPF_REG_0, dst_reg);
> >>
> >> -                    /*
> >> -                     * xor edx, edx
> >> -                     * equivalent to 'xor rdx, rdx', but one byte less
> >> -                     */
> >> -                    EMIT2(0x31, 0xd2);
> >> +                    if (insn->off == 0) {
> >> +                            /*
> >> +                             * xor edx, edx
> >> +                             * equivalent to 'xor rdx, rdx', but one byte less
> >> +                             */
> >> +                            EMIT2(0x31, 0xd2);
> >>
> >> -                    /* div src_reg */
> >> -                    maybe_emit_1mod(&prog, src_reg, is64);
> >> -                    EMIT2(0xF7, add_1reg(0xF0, src_reg));
> >> +                            /* div src_reg */
> >> +                            maybe_emit_1mod(&prog, src_reg, is64);
> >> +                            EMIT2(0xF7, add_1reg(0xF0, src_reg));
> >> +                    } else {
> >> +                            if (BPF_CLASS(insn->code) == BPF_ALU)
> >> +                                    EMIT1(0x99); /* cltd */
> >> +                            else
> >> +                                    EMIT2(0x48, 0x99); /* cqto */
> >
> > Nitpick: I can't find names cltd/cqto in the Intel instruction manual,
> >           instead it uses names cdq/cqo for these instructions.
> >           (See Vol. 2A pages 3-315 and 3-497)
>
> I got these asm names from
>    https://defuse.ca/online-x86-assembler.htm
> I will check the Intel insn manual and make the change
> accordingly.

Heh. I've been using the same.
Most of the comments in the x86 JIT code are from there :)

and it actually returns 99 -> cdq, 4899 -> cqo

cltd/cqto must be aliases ?
Yonghong Song July 19, 2023, 6:57 a.m. UTC | #4
On 7/18/23 7:44 PM, Alexei Starovoitov wrote:
> On Tue, Jul 18, 2023 at 7:31 PM Yonghong Song <yhs@meta.com> wrote:
>>
>>
>>
>> On 7/18/23 4:00 PM, Eduard Zingerman wrote:
>>> On Wed, 2023-07-12 at 23:07 -0700, Yonghong Song wrote:
>>>> Add interpreter/jit support for new signed div/mod insns.
>>>> The new signed div/mod instructions are encoded with
>>>> unsigned div/mod instructions plus insn->off == 1.
>>>> Also add basic verifier support to ensure new insns get
>>>> accepted.
>>>>
>>>> Signed-off-by: Yonghong Song <yhs@fb.com>
>>>> ---
>>>>    arch/x86/net/bpf_jit_comp.c | 27 +++++++----
>>>>    kernel/bpf/core.c           | 96 ++++++++++++++++++++++++++++++-------
>>>>    kernel/bpf/verifier.c       |  6 ++-
>>>>    3 files changed, 103 insertions(+), 26 deletions(-)
>>>>
>>>> diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
>>>> index adda5e7626b4..3176b60d25c7 100644
>>>> --- a/arch/x86/net/bpf_jit_comp.c
>>>> +++ b/arch/x86/net/bpf_jit_comp.c
>>>> @@ -1194,15 +1194,26 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
>>>>                               /* mov rax, dst_reg */
>>>>                               emit_mov_reg(&prog, is64, BPF_REG_0, dst_reg);
>>>>
>>>> -                    /*
>>>> -                     * xor edx, edx
>>>> -                     * equivalent to 'xor rdx, rdx', but one byte less
>>>> -                     */
>>>> -                    EMIT2(0x31, 0xd2);
>>>> +                    if (insn->off == 0) {
>>>> +                            /*
>>>> +                             * xor edx, edx
>>>> +                             * equivalent to 'xor rdx, rdx', but one byte less
>>>> +                             */
>>>> +                            EMIT2(0x31, 0xd2);
>>>>
>>>> -                    /* div src_reg */
>>>> -                    maybe_emit_1mod(&prog, src_reg, is64);
>>>> -                    EMIT2(0xF7, add_1reg(0xF0, src_reg));
>>>> +                            /* div src_reg */
>>>> +                            maybe_emit_1mod(&prog, src_reg, is64);
>>>> +                            EMIT2(0xF7, add_1reg(0xF0, src_reg));
>>>> +                    } else {
>>>> +                            if (BPF_CLASS(insn->code) == BPF_ALU)
>>>> +                                    EMIT1(0x99); /* cltd */
>>>> +                            else
>>>> +                                    EMIT2(0x48, 0x99); /* cqto */
>>>
>>> Nitpick: I can't find names cltd/cqto in the Intel instruction manual,
>>>            instead it uses names cdq/cqo for these instructions.
>>>            (See Vol. 2A pages 3-315 and 3-497)
>>
>> I got these asm names from
>>     https://defuse.ca/online-x86-assembler.htm
>> I will check the Intel insn manual and make the change
>> accordingly.
> 
> Heh. I've been using the same.
> Most of the comments in the x86 JIT code are from there :)
> 
> and it actually returns 99 -> cdq, 4899 -> cqo
> 
> cltd/cqto must be aliases ?

Yes, cltd/cqto are aliases.

 From llvm-project repo:

[~/work/llvm-project/llvm/lib/Target/X86 (ni23)]$ egrep -r cltd
egrep: warning: egrep is obsolescent; using grep -E
README.txt:        cltd
X86InstrAsmAlias.td:def : MnemonicAlias<"cdq",  "cltd", "att">;
X86InstrExtension.td:              "{cltd|cdq}", []>, OpSize32, 
Sched<[WriteALU]>;

[~/work/llvm-project/llvm/lib/Target/X86 (ni23)]$ egrep -r cqto
egrep: warning: egrep is obsolescent; using grep -E
X86InstrAsmAlias.td:def : MnemonicAlias<"cqo",  "cqto", "att">;
X86InstrExtension.td:                "{cqto|cqo}", []>, 
Sched<[WriteALU]>, Requires<[In64BitMode]>;

I will change to use cdq and cgo.
diff mbox series

Patch

diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index adda5e7626b4..3176b60d25c7 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -1194,15 +1194,26 @@  static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
 				/* mov rax, dst_reg */
 				emit_mov_reg(&prog, is64, BPF_REG_0, dst_reg);
 
-			/*
-			 * xor edx, edx
-			 * equivalent to 'xor rdx, rdx', but one byte less
-			 */
-			EMIT2(0x31, 0xd2);
+			if (insn->off == 0) {
+				/*
+				 * xor edx, edx
+				 * equivalent to 'xor rdx, rdx', but one byte less
+				 */
+				EMIT2(0x31, 0xd2);
 
-			/* div src_reg */
-			maybe_emit_1mod(&prog, src_reg, is64);
-			EMIT2(0xF7, add_1reg(0xF0, src_reg));
+				/* div src_reg */
+				maybe_emit_1mod(&prog, src_reg, is64);
+				EMIT2(0xF7, add_1reg(0xF0, src_reg));
+			} else {
+				if (BPF_CLASS(insn->code) == BPF_ALU)
+					EMIT1(0x99); /* cltd */
+				else
+					EMIT2(0x48, 0x99); /* cqto */
+
+				/* idiv src_reg */
+				maybe_emit_1mod(&prog, src_reg, is64);
+				EMIT2(0xF7, add_1reg(0xF8, src_reg));
+			}
 
 			if (BPF_OP(insn->code) == BPF_MOD &&
 			    dst_reg != BPF_REG_3)
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 86bb412fee39..6f7134657935 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -1789,36 +1789,100 @@  static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn)
 		(*(s64 *) &DST) >>= IMM;
 		CONT;
 	ALU64_MOD_X:
-		div64_u64_rem(DST, SRC, &AX);
-		DST = AX;
+		switch (OFF) {
+		case 0:
+			div64_u64_rem(DST, SRC, &AX);
+			DST = AX;
+			break;
+		case 1:
+			AX = div64_s64(DST, SRC);
+			DST = DST - AX * SRC;
+			break;
+		}
 		CONT;
 	ALU_MOD_X:
-		AX = (u32) DST;
-		DST = do_div(AX, (u32) SRC);
+		switch (OFF) {
+		case 0:
+			AX = (u32) DST;
+			DST = do_div(AX, (u32) SRC);
+			break;
+		case 1:
+			AX = (s32) DST;
+			DST = (u32)do_div(AX, (s32) SRC);
+			break;
+		}
 		CONT;
 	ALU64_MOD_K:
-		div64_u64_rem(DST, IMM, &AX);
-		DST = AX;
+		switch (OFF) {
+		case 0:
+			div64_u64_rem(DST, IMM, &AX);
+			DST = AX;
+			break;
+		case 1:
+			AX = div64_s64(DST, IMM);
+			DST = DST - AX * IMM;
+			break;
+		}
 		CONT;
 	ALU_MOD_K:
-		AX = (u32) DST;
-		DST = do_div(AX, (u32) IMM);
+		switch (OFF) {
+		case 0:
+			AX = (u32) DST;
+			DST = do_div(AX, (u32) IMM);
+			break;
+		case 1:
+			AX = (s32) DST;
+			DST = (u32)do_div(AX, (s32) IMM);
+			break;
+		}
 		CONT;
 	ALU64_DIV_X:
-		DST = div64_u64(DST, SRC);
+		switch (OFF) {
+		case 0:
+			DST = div64_u64(DST, SRC);
+			break;
+		case 1:
+			DST = div64_s64(DST, SRC);
+			break;
+		}
 		CONT;
 	ALU_DIV_X:
-		AX = (u32) DST;
-		do_div(AX, (u32) SRC);
-		DST = (u32) AX;
+		switch (OFF) {
+		case 0:
+			AX = (u32) DST;
+			do_div(AX, (u32) SRC);
+			DST = (u32) AX;
+			break;
+		case 1:
+			AX = (s32) DST;
+			do_div(AX, (s32) SRC);
+			DST = (u32) AX;
+			break;
+		}
 		CONT;
 	ALU64_DIV_K:
-		DST = div64_u64(DST, IMM);
+		switch (OFF) {
+		case 0:
+			DST = div64_u64(DST, IMM);
+			break;
+		case 1:
+			DST = div64_s64(DST, IMM);
+			break;
+		}
 		CONT;
 	ALU_DIV_K:
-		AX = (u32) DST;
-		do_div(AX, (u32) IMM);
-		DST = (u32) AX;
+		switch (OFF) {
+		case 0:
+			AX = (u32) DST;
+			do_div(AX, (u32) IMM);
+			DST = (u32) AX;
+			break;
+		case 1:
+			AX = (s32) DST;
+			do_div(AX, (s32) IMM);
+			DST = (u32) AX;
+			break;
+		}
 		CONT;
 	ALU_END_TO_BE:
 		switch (IMM) {
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 22ba0744547b..b606c8ed5470 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -13192,7 +13192,8 @@  static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
 	} else {	/* all other ALU ops: and, sub, xor, add, ... */
 
 		if (BPF_SRC(insn->code) == BPF_X) {
-			if (insn->imm != 0 || insn->off != 0) {
+			if (insn->imm != 0 || insn->off > 1 ||
+			    (insn->off == 1 && opcode != BPF_MOD && opcode != BPF_DIV)) {
 				verbose(env, "BPF_ALU uses reserved fields\n");
 				return -EINVAL;
 			}
@@ -13201,7 +13202,8 @@  static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
 			if (err)
 				return err;
 		} else {
-			if (insn->src_reg != BPF_REG_0 || insn->off != 0) {
+			if (insn->src_reg != BPF_REG_0 || insn->off > 1 ||
+			    (insn->off == 1 && opcode != BPF_MOD && opcode != BPF_DIV)) {
 				verbose(env, "BPF_ALU uses reserved fields\n");
 				return -EINVAL;
 			}