• Gianluca Borello's avatar
    bpf: allow helpers access to variable memory · 06c1c049
    Gianluca Borello authored
    Currently, helpers that read and write from/to the stack can do so using
    a pair of arguments of type ARG_PTR_TO_STACK and ARG_CONST_STACK_SIZE.
    ARG_CONST_STACK_SIZE accepts a constant register of type CONST_IMM, so
    that the verifier can safely check the memory access. However, requiring
    the argument to be a constant can be limiting in some circumstances.
    
    Since the current logic keeps track of the minimum and maximum value of
    a register throughout the simulated execution, ARG_CONST_STACK_SIZE can
    be changed to also accept an UNKNOWN_VALUE register in case its
    boundaries have been set and the range doesn't cause invalid memory
    accesses.
    
    One common situation when this is useful:
    
    int len;
    char buf[BUFSIZE]; /* BUFSIZE is 128 */
    
    if (some_condition)
    	len = 42;
    else
    	len = 84;
    
    some_helper(..., buf, len & (BUFSIZE - 1));
    
    The compiler can often decide to assign the constant values 42 or 48
    into a variable on the stack, instead of keeping it in a register. When
    the variable is then read back from stack into the register in order to
    be passed to the helper, the verifier will not be able to recognize the
    register as constant (the verifier is not currently tracking all
    constant writes into memory), and the program won't be valid.
    
    However, by allowing the helper to accept an UNKNOWN_VALUE register,
    this program will work because the bitwise AND operation will set the
    range of possible values for the UNKNOWN_VALUE register to [0, BUFSIZE),
    so the verifier can guarantee the helper call will be safe (assuming the
    argument is of type ARG_CONST_STACK_SIZE_OR_ZERO, otherwise one more
    check against 0 would be needed). Custom ranges can be set not only with
    ALU operations, but also by explicitly comparing the UNKNOWN_VALUE
    register with constants.
    
    Another very common example happens when intercepting system call
    arguments and accessing user-provided data of variable size using
    bpf_probe_read(). One can load at runtime the user-provided length in an
    UNKNOWN_VALUE register, and then read that exact amount of data up to a
    compile-time determined limit in order to fit into the proper local
    storage allocated on the stack, without having to guess a suboptimal
    access size at compile time.
    
    Also, in case the helpers accepting the UNKNOWN_VALUE register operate
    in raw mode, disable the raw mode so that the program is required to
    initialize all memory, since there is no guarantee the helper will fill
    it completely, leaving possibilities for data leak (just relevant when
    the memory used by the helper is the stack, not when using a pointer to
    map element value or packet). In other words, ARG_PTR_TO_RAW_STACK will
    be treated as ARG_PTR_TO_STACK.
    Signed-off-by: default avatarGianluca Borello <g.borello@gmail.com>
    Acked-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
    Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    06c1c049
verifier.c 95.2 KB