42_linux_32bit_arg_fixup.patch (4027B)
1 commit e0a00891b67ec162a17aa241a83b171b313de9fe 2 Author: Jed Davis <jld@mozilla.com> 3 Date: Mon Apr 18 18:00:10 2022 -0600 4 5 Make the sandbox fix up non-extended 32-bit types. 6 7 diff --git a/sandbox/linux/bpf_dsl/policy_compiler.cc b/sandbox/linux/bpf_dsl/policy_compiler.cc 8 index 347304889eae4..b909fc37f6174 100644 9 --- a/sandbox/linux/bpf_dsl/policy_compiler.cc 10 +++ b/sandbox/linux/bpf_dsl/policy_compiler.cc 11 @@ -19,6 +19,7 @@ 12 #include "sandbox/linux/bpf_dsl/policy.h" 13 #include "sandbox/linux/bpf_dsl/seccomp_macros.h" 14 #include "sandbox/linux/bpf_dsl/syscall_set.h" 15 +#include "sandbox/linux/seccomp-bpf/syscall.h" 16 #include "sandbox/linux/system_headers/linux_filter.h" 17 #include "sandbox/linux/system_headers/linux_seccomp.h" 18 #include "sandbox/linux/system_headers/linux_syscalls.h" 19 @@ -318,8 +319,7 @@ CodeGen::Node PolicyCompiler::MaskedEqualHalf(int argno, 20 // Special logic for sanity checking the upper 32-bits of 32-bit system 21 // call arguments. 22 23 - // TODO(mdempsky): Compile Unexpected64bitArgument() just per program. 24 - CodeGen::Node invalid_64bit = Unexpected64bitArgument(); 25 + CodeGen::Node invalid_64bit = Unexpected64bitArgument(argno); 26 27 const uint32_t upper = SECCOMP_ARG_MSB_IDX(argno); 28 const uint32_t lower = SECCOMP_ARG_LSB_IDX(argno); 29 @@ -335,8 +335,13 @@ CodeGen::Node PolicyCompiler::MaskedEqualHalf(int argno, 30 BPF_JMP + BPF_JEQ + BPF_K, 0, passed, invalid_64bit)); 31 } 32 33 - // On 64-bit platforms, the upper 32-bits may be 0 or ~0; but we only allow 34 - // ~0 if the sign bit of the lower 32-bits is set too: 35 + // On 64-bit platforms, the ABI (at least on x86_64) allows any value 36 + // for the upper half, but to avoid potential vulnerabilties if an 37 + // argument is incorrectly tested as a 32-bit type, we require it to be 38 + // either zero-extended or sign-extended. That is, the upper 32-bits 39 + // may be 0 or ~0; but we only allow ~0 if the sign bit of the lower 40 + // 32-bits is set too: 41 + // 42 // LDW [upper] 43 // JEQ 0, passed, (next) 44 // JEQ ~0, (next), invalid 45 @@ -424,8 +429,18 @@ CodeGen::Node PolicyCompiler::MaskedEqualHalf(int argno, 46 BPF_JMP + BPF_JEQ + BPF_K, value, passed, failed))); 47 } 48 49 -CodeGen::Node PolicyCompiler::Unexpected64bitArgument() { 50 - return CompileResult(panic_func_("Unexpected 64bit argument detected")); 51 +CodeGen::Node PolicyCompiler::Unexpected64bitArgument(int argno) { 52 + // This situation is unlikely, but possible. Return to userspace, 53 + // zero-extend the problematic argument, and re-issue the syscall. 54 + return CompileResult(bpf_dsl::Trap( 55 + [](const arch_seccomp_data& args_ref, void* aux) -> intptr_t { 56 + arch_seccomp_data args = args_ref; 57 + int argno = (int)(intptr_t)aux; 58 + args.args[argno] &= 0xFFFFFFFF; 59 + return Syscall::Call(args.nr, args.args[0], args.args[1], args.args[2], 60 + args.args[3], args.args[4], args.args[5]); 61 + }, 62 + (void*)(intptr_t)argno)); 63 } 64 65 CodeGen::Node PolicyCompiler::Return(uint32_t ret) { 66 diff --git a/sandbox/linux/bpf_dsl/policy_compiler.h b/sandbox/linux/bpf_dsl/policy_compiler.h 67 index 48b1d780d956f..2acf878474a7d 100644 68 --- a/sandbox/linux/bpf_dsl/policy_compiler.h 69 +++ b/sandbox/linux/bpf_dsl/policy_compiler.h 70 @@ -132,9 +132,11 @@ class SANDBOX_EXPORT PolicyCompiler { 71 CodeGen::Node passed, 72 CodeGen::Node failed); 73 74 - // Returns the fatal CodeGen::Node that is used to indicate that somebody 75 - // attempted to pass a 64bit value in a 32bit system call argument. 76 - CodeGen::Node Unexpected64bitArgument(); 77 + // Returns the CodeGen::Node that is used to handle the case where a 78 + // system call argument was expected to be a 32-bit type, but the 79 + // value in the 64-bit register doesn't correspond to a 80 + // zero-extended or sign-extended 32-bit value. 81 + CodeGen::Node Unexpected64bitArgument(int argno); 82 83 const Policy* policy_; 84 TrapRegistry* registry_;