mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
Merge 4.19.19 into android-4.19
Changes in 4.19.19
amd-xgbe: Fix mdio access for non-zero ports and clause 45 PHYs
net: bridge: Fix ethernet header pointer before check skb forwardable
net: Fix usage of pskb_trim_rcsum
net: phy: marvell: Errata for mv88e6390 internal PHYs
net: phy: mdio_bus: add missing device_del() in mdiobus_register() error handling
net/sched: act_tunnel_key: fix memory leak in case of action replace
net_sched: refetch skb protocol for each filter
openvswitch: Avoid OOB read when parsing flow nlattrs
vhost: log dirty page correctly
mlxsw: pci: Increase PCI SW reset timeout
net: ipv4: Fix memory leak in network namespace dismantle
mlxsw: spectrum_fid: Update dummy FID index
mlxsw: pci: Ring CQ's doorbell before RDQ's
net/sched: cls_flower: allocate mask dynamically in fl_change()
udp: with udp_segment release on error path
ip6_gre: fix tunnel list corruption for x-netns
erspan: build the header with the right proto according to erspan_ver
net: phy: marvell: Fix deadlock from wrong locking
ip6_gre: update version related info when changing link
tcp: allow MSG_ZEROCOPY transmission also in CLOSE_WAIT state
mei: me: mark LBG devices as having dma support
mei: me: add denverton innovation engine device IDs
USB: leds: fix regression in usbport led trigger
USB: serial: simple: add Motorola Tetra TPG2200 device id
USB: serial: pl2303: add new PID to support PL2303TB
ceph: clear inode pointer when snap realm gets dropped by its inode
ASoC: atom: fix a missing check of snd_pcm_lib_malloc_pages
ASoC: rt5514-spi: Fix potential NULL pointer dereference
ASoC: tlv320aic32x4: Kernel OOPS while entering DAPM standby mode
clk: socfpga: stratix10: fix rate calculation for pll clocks
clk: socfpga: stratix10: fix naming convention for the fixed-clocks
inotify: Fix fd refcount leak in inotify_add_watch().
ALSA: hda/realtek - Fix typo for ALC225 model
ALSA: hda - Add mute LED support for HP ProBook 470 G5
ARCv2: lib: memeset: fix doing prefetchw outside of buffer
ARC: adjust memblock_reserve of kernel memory
ARC: perf: map generic branches to correct hardware condition
s390/mm: always force a load of the primary ASCE on context switch
s390/early: improve machine detection
s390/smp: fix CPU hotplug deadlock with CPU rescan
misc: ibmvsm: Fix potential NULL pointer dereference
char/mwave: fix potential Spectre v1 vulnerability
mmc: dw_mmc-bluefield: : Fix the license information
mmc: meson-gx: Free irq in release() callback
staging: rtl8188eu: Add device code for D-Link DWA-121 rev B1
tty: Handle problem if line discipline does not have receive_buf
uart: Fix crash in uart_write and uart_put_char
tty/n_hdlc: fix __might_sleep warning
hv_balloon: avoid touching uninitialized struct page during tail onlining
Drivers: hv: vmbus: Check for ring when getting debug info
vgacon: unconfuse vc_origin when using soft scrollback
CIFS: Fix possible hang during async MTU reads and writes
CIFS: Fix credits calculations for reads with errors
CIFS: Fix credit calculation for encrypted reads with errors
CIFS: Do not reconnect TCP session in add_credits()
smb3: add credits we receive from oplock/break PDUs
Input: xpad - add support for SteelSeries Stratus Duo
Input: input_event - provide override for sparc64
Input: uinput - fix undefined behavior in uinput_validate_absinfo()
acpi/nfit: Block function zero DSMs
acpi/nfit: Fix command-supported detection
scsi: ufs: Use explicit access size in ufshcd_dump_regs
dm thin: fix passdown_double_checking_shared_status()
dm crypt: fix parsing of extended IV arguments
drm/amdgpu: Add APTX quirk for Lenovo laptop
KVM: x86: Fix single-step debugging
KVM: x86: Fix PV IPIs for 32-bit KVM host
KVM: x86: WARN_ONCE if sending a PV IPI returns a fatal error
kvm: x86/vmx: Use kzalloc for cached_vmcs12
KVM/nVMX: Do not validate that posted_intr_desc_addr is page aligned
x86/pkeys: Properly copy pkey state at fork()
x86/selftests/pkeys: Fork() to check for state being preserved
x86/kaslr: Fix incorrect i8254 outb() parameters
x86/entry/64/compat: Fix stack switching for XEN PV
posix-cpu-timers: Unbreak timer rearming
net: sun: cassini: Cleanup license conflict
irqchip/gic-v3-its: Align PCI Multi-MSI allocation on their size
can: dev: __can_get_echo_skb(): fix bogous check for non-existing skb by removing it
can: bcm: check timer values before ktime conversion
can: flexcan: fix NULL pointer exception during bringup
vt: make vt_console_print() compatible with the unicode screen buffer
vt: always call notifier with the console lock held
vt: invoke notifier on screen size change
drm/meson: Fix atomic mode switching regression
bpf: improve verifier branch analysis
bpf: add per-insn complexity limit
bpf: move {prev_,}insn_idx into verifier env
bpf: move tmp variable into ax register in interpreter
bpf: enable access to ax register also from verifier rewrite
bpf: restrict map value pointer arithmetic for unprivileged
bpf: restrict stack pointer arithmetic for unprivileged
bpf: restrict unknown scalars of mixed signed bounds for unprivileged
bpf: fix check_map_access smin_value test when pointer contains offset
bpf: prevent out of bounds speculation on pointer arithmetic
bpf: fix sanitation of alu op with pointer / scalar type from different paths
bpf: fix inner map masking to prevent oob under speculation
s390/smp: Fix calling smp_call_ipl_cpu() from ipl CPU
nvmet-rdma: Add unlikely for response allocated check
nvmet-rdma: fix null dereference under heavy load
Revert "mm, memory_hotplug: initialize struct pages for the full memory section"
usb: dwc3: gadget: Clear req->needs_extra_trb flag on cleanup
ide: fix a typo in the settings proc file name
Input: input_event - fix the CONFIG_SPARC64 mixup
Linux 4.19.19
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
@@ -52,6 +52,7 @@
|
||||
#define DST regs[insn->dst_reg]
|
||||
#define SRC regs[insn->src_reg]
|
||||
#define FP regs[BPF_REG_FP]
|
||||
#define AX regs[BPF_REG_AX]
|
||||
#define ARG1 regs[BPF_REG_ARG1]
|
||||
#define CTX regs[BPF_REG_CTX]
|
||||
#define IMM insn->imm
|
||||
@@ -642,6 +643,26 @@ static int bpf_jit_blind_insn(const struct bpf_insn *from,
|
||||
BUILD_BUG_ON(BPF_REG_AX + 1 != MAX_BPF_JIT_REG);
|
||||
BUILD_BUG_ON(MAX_BPF_REG + 1 != MAX_BPF_JIT_REG);
|
||||
|
||||
/* Constraints on AX register:
|
||||
*
|
||||
* AX register is inaccessible from user space. It is mapped in
|
||||
* all JITs, and used here for constant blinding rewrites. It is
|
||||
* typically "stateless" meaning its contents are only valid within
|
||||
* the executed instruction, but not across several instructions.
|
||||
* There are a few exceptions however which are further detailed
|
||||
* below.
|
||||
*
|
||||
* Constant blinding is only used by JITs, not in the interpreter.
|
||||
* The interpreter uses AX in some occasions as a local temporary
|
||||
* register e.g. in DIV or MOD instructions.
|
||||
*
|
||||
* In restricted circumstances, the verifier can also use the AX
|
||||
* register for rewrites as long as they do not interfere with
|
||||
* the above cases!
|
||||
*/
|
||||
if (from->dst_reg == BPF_REG_AX || from->src_reg == BPF_REG_AX)
|
||||
goto out;
|
||||
|
||||
if (from->imm == 0 &&
|
||||
(from->code == (BPF_ALU | BPF_MOV | BPF_K) ||
|
||||
from->code == (BPF_ALU64 | BPF_MOV | BPF_K))) {
|
||||
@@ -971,7 +992,6 @@ bool bpf_opcode_in_insntable(u8 code)
|
||||
*/
|
||||
static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, u64 *stack)
|
||||
{
|
||||
u64 tmp;
|
||||
#define BPF_INSN_2_LBL(x, y) [BPF_##x | BPF_##y] = &&x##_##y
|
||||
#define BPF_INSN_3_LBL(x, y, z) [BPF_##x | BPF_##y | BPF_##z] = &&x##_##y##_##z
|
||||
static const void *jumptable[256] = {
|
||||
@@ -1045,36 +1065,36 @@ select_insn:
|
||||
(*(s64 *) &DST) >>= IMM;
|
||||
CONT;
|
||||
ALU64_MOD_X:
|
||||
div64_u64_rem(DST, SRC, &tmp);
|
||||
DST = tmp;
|
||||
div64_u64_rem(DST, SRC, &AX);
|
||||
DST = AX;
|
||||
CONT;
|
||||
ALU_MOD_X:
|
||||
tmp = (u32) DST;
|
||||
DST = do_div(tmp, (u32) SRC);
|
||||
AX = (u32) DST;
|
||||
DST = do_div(AX, (u32) SRC);
|
||||
CONT;
|
||||
ALU64_MOD_K:
|
||||
div64_u64_rem(DST, IMM, &tmp);
|
||||
DST = tmp;
|
||||
div64_u64_rem(DST, IMM, &AX);
|
||||
DST = AX;
|
||||
CONT;
|
||||
ALU_MOD_K:
|
||||
tmp = (u32) DST;
|
||||
DST = do_div(tmp, (u32) IMM);
|
||||
AX = (u32) DST;
|
||||
DST = do_div(AX, (u32) IMM);
|
||||
CONT;
|
||||
ALU64_DIV_X:
|
||||
DST = div64_u64(DST, SRC);
|
||||
CONT;
|
||||
ALU_DIV_X:
|
||||
tmp = (u32) DST;
|
||||
do_div(tmp, (u32) SRC);
|
||||
DST = (u32) tmp;
|
||||
AX = (u32) DST;
|
||||
do_div(AX, (u32) SRC);
|
||||
DST = (u32) AX;
|
||||
CONT;
|
||||
ALU64_DIV_K:
|
||||
DST = div64_u64(DST, IMM);
|
||||
CONT;
|
||||
ALU_DIV_K:
|
||||
tmp = (u32) DST;
|
||||
do_div(tmp, (u32) IMM);
|
||||
DST = (u32) tmp;
|
||||
AX = (u32) DST;
|
||||
do_div(AX, (u32) IMM);
|
||||
DST = (u32) AX;
|
||||
CONT;
|
||||
ALU_END_TO_BE:
|
||||
switch (IMM) {
|
||||
@@ -1330,7 +1350,7 @@ STACK_FRAME_NON_STANDARD(___bpf_prog_run); /* jump table */
|
||||
static unsigned int PROG_NAME(stack_size)(const void *ctx, const struct bpf_insn *insn) \
|
||||
{ \
|
||||
u64 stack[stack_size / sizeof(u64)]; \
|
||||
u64 regs[MAX_BPF_REG]; \
|
||||
u64 regs[MAX_BPF_EXT_REG]; \
|
||||
\
|
||||
FP = (u64) (unsigned long) &stack[ARRAY_SIZE(stack)]; \
|
||||
ARG1 = (u64) (unsigned long) ctx; \
|
||||
@@ -1343,7 +1363,7 @@ static u64 PROG_NAME_ARGS(stack_size)(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5, \
|
||||
const struct bpf_insn *insn) \
|
||||
{ \
|
||||
u64 stack[stack_size / sizeof(u64)]; \
|
||||
u64 regs[MAX_BPF_REG]; \
|
||||
u64 regs[MAX_BPF_EXT_REG]; \
|
||||
\
|
||||
FP = (u64) (unsigned long) &stack[ARRAY_SIZE(stack)]; \
|
||||
BPF_R1 = r1; \
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
struct bpf_map *bpf_map_meta_alloc(int inner_map_ufd)
|
||||
{
|
||||
struct bpf_map *inner_map, *inner_map_meta;
|
||||
u32 inner_map_meta_size;
|
||||
struct fd f;
|
||||
|
||||
f = fdget(inner_map_ufd);
|
||||
@@ -35,7 +36,12 @@ struct bpf_map *bpf_map_meta_alloc(int inner_map_ufd)
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
inner_map_meta = kzalloc(sizeof(*inner_map_meta), GFP_USER);
|
||||
inner_map_meta_size = sizeof(*inner_map_meta);
|
||||
/* In some cases verifier needs to access beyond just base map. */
|
||||
if (inner_map->ops == &array_map_ops)
|
||||
inner_map_meta_size = sizeof(struct bpf_array);
|
||||
|
||||
inner_map_meta = kzalloc(inner_map_meta_size, GFP_USER);
|
||||
if (!inner_map_meta) {
|
||||
fdput(f);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
@@ -45,9 +51,16 @@ struct bpf_map *bpf_map_meta_alloc(int inner_map_ufd)
|
||||
inner_map_meta->key_size = inner_map->key_size;
|
||||
inner_map_meta->value_size = inner_map->value_size;
|
||||
inner_map_meta->map_flags = inner_map->map_flags;
|
||||
inner_map_meta->ops = inner_map->ops;
|
||||
inner_map_meta->max_entries = inner_map->max_entries;
|
||||
|
||||
/* Misc members not needed in bpf_map_meta_equal() check. */
|
||||
inner_map_meta->ops = inner_map->ops;
|
||||
if (inner_map->ops == &array_map_ops) {
|
||||
inner_map_meta->unpriv_array = inner_map->unpriv_array;
|
||||
container_of(inner_map_meta, struct bpf_array, map)->index_mask =
|
||||
container_of(inner_map, struct bpf_array, map)->index_mask;
|
||||
}
|
||||
|
||||
fdput(f);
|
||||
return inner_map_meta;
|
||||
}
|
||||
|
||||
@@ -156,6 +156,7 @@ struct bpf_verifier_stack_elem {
|
||||
|
||||
#define BPF_COMPLEXITY_LIMIT_INSNS 131072
|
||||
#define BPF_COMPLEXITY_LIMIT_STACK 1024
|
||||
#define BPF_COMPLEXITY_LIMIT_STATES 64
|
||||
|
||||
#define BPF_MAP_PTR_UNPRIV 1UL
|
||||
#define BPF_MAP_PTR_POISON ((void *)((0xeB9FUL << 1) + \
|
||||
@@ -465,6 +466,7 @@ static int copy_verifier_state(struct bpf_verifier_state *dst_state,
|
||||
free_func_state(dst_state->frame[i]);
|
||||
dst_state->frame[i] = NULL;
|
||||
}
|
||||
dst_state->speculative = src->speculative;
|
||||
dst_state->curframe = src->curframe;
|
||||
dst_state->parent = src->parent;
|
||||
for (i = 0; i <= src->curframe; i++) {
|
||||
@@ -510,7 +512,8 @@ static int pop_stack(struct bpf_verifier_env *env, int *prev_insn_idx,
|
||||
}
|
||||
|
||||
static struct bpf_verifier_state *push_stack(struct bpf_verifier_env *env,
|
||||
int insn_idx, int prev_insn_idx)
|
||||
int insn_idx, int prev_insn_idx,
|
||||
bool speculative)
|
||||
{
|
||||
struct bpf_verifier_state *cur = env->cur_state;
|
||||
struct bpf_verifier_stack_elem *elem;
|
||||
@@ -528,6 +531,7 @@ static struct bpf_verifier_state *push_stack(struct bpf_verifier_env *env,
|
||||
err = copy_verifier_state(&elem->st, cur);
|
||||
if (err)
|
||||
goto err;
|
||||
elem->st.speculative |= speculative;
|
||||
if (env->stack_size > BPF_COMPLEXITY_LIMIT_STACK) {
|
||||
verbose(env, "BPF program is too complex\n");
|
||||
goto err;
|
||||
@@ -1237,6 +1241,31 @@ static int check_stack_read(struct bpf_verifier_env *env,
|
||||
}
|
||||
}
|
||||
|
||||
static int check_stack_access(struct bpf_verifier_env *env,
|
||||
const struct bpf_reg_state *reg,
|
||||
int off, int size)
|
||||
{
|
||||
/* Stack accesses must be at a fixed offset, so that we
|
||||
* can determine what type of data were returned. See
|
||||
* check_stack_read().
|
||||
*/
|
||||
if (!tnum_is_const(reg->var_off)) {
|
||||
char tn_buf[48];
|
||||
|
||||
tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
|
||||
verbose(env, "variable stack access var_off=%s off=%d size=%d",
|
||||
tn_buf, off, size);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
if (off >= 0 || off < -MAX_BPF_STACK) {
|
||||
verbose(env, "invalid stack off=%d size=%d\n", off, size);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check read/write into map element returned by bpf_map_lookup_elem() */
|
||||
static int __check_map_access(struct bpf_verifier_env *env, u32 regno, int off,
|
||||
int size, bool zero_size_allowed)
|
||||
@@ -1268,13 +1297,17 @@ static int check_map_access(struct bpf_verifier_env *env, u32 regno,
|
||||
*/
|
||||
if (env->log.level)
|
||||
print_verifier_state(env, state);
|
||||
|
||||
/* The minimum value is only important with signed
|
||||
* comparisons where we can't assume the floor of a
|
||||
* value is 0. If we are using signed variables for our
|
||||
* index'es we need to make sure that whatever we use
|
||||
* will have a set floor within our range.
|
||||
*/
|
||||
if (reg->smin_value < 0) {
|
||||
if (reg->smin_value < 0 &&
|
||||
(reg->smin_value == S64_MIN ||
|
||||
(off + reg->smin_value != (s64)(s32)(off + reg->smin_value)) ||
|
||||
reg->smin_value + off < 0)) {
|
||||
verbose(env, "R%d min value is negative, either use unsigned index or do a if (index >=0) check.\n",
|
||||
regno);
|
||||
return -EACCES;
|
||||
@@ -1735,24 +1768,10 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
|
||||
}
|
||||
|
||||
} else if (reg->type == PTR_TO_STACK) {
|
||||
/* stack accesses must be at a fixed offset, so that we can
|
||||
* determine what type of data were returned.
|
||||
* See check_stack_read().
|
||||
*/
|
||||
if (!tnum_is_const(reg->var_off)) {
|
||||
char tn_buf[48];
|
||||
|
||||
tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
|
||||
verbose(env, "variable stack access var_off=%s off=%d size=%d",
|
||||
tn_buf, off, size);
|
||||
return -EACCES;
|
||||
}
|
||||
off += reg->var_off.value;
|
||||
if (off >= 0 || off < -MAX_BPF_STACK) {
|
||||
verbose(env, "invalid stack off=%d size=%d\n", off,
|
||||
size);
|
||||
return -EACCES;
|
||||
}
|
||||
err = check_stack_access(env, reg, off, size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
state = func(env, reg);
|
||||
err = update_stack_depth(env, state, off);
|
||||
@@ -2682,6 +2701,125 @@ static bool check_reg_sane_offset(struct bpf_verifier_env *env,
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct bpf_insn_aux_data *cur_aux(struct bpf_verifier_env *env)
|
||||
{
|
||||
return &env->insn_aux_data[env->insn_idx];
|
||||
}
|
||||
|
||||
static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg,
|
||||
u32 *ptr_limit, u8 opcode, bool off_is_neg)
|
||||
{
|
||||
bool mask_to_left = (opcode == BPF_ADD && off_is_neg) ||
|
||||
(opcode == BPF_SUB && !off_is_neg);
|
||||
u32 off;
|
||||
|
||||
switch (ptr_reg->type) {
|
||||
case PTR_TO_STACK:
|
||||
off = ptr_reg->off + ptr_reg->var_off.value;
|
||||
if (mask_to_left)
|
||||
*ptr_limit = MAX_BPF_STACK + off;
|
||||
else
|
||||
*ptr_limit = -off;
|
||||
return 0;
|
||||
case PTR_TO_MAP_VALUE:
|
||||
if (mask_to_left) {
|
||||
*ptr_limit = ptr_reg->umax_value + ptr_reg->off;
|
||||
} else {
|
||||
off = ptr_reg->smin_value + ptr_reg->off;
|
||||
*ptr_limit = ptr_reg->map_ptr->value_size - off;
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static bool can_skip_alu_sanitation(const struct bpf_verifier_env *env,
|
||||
const struct bpf_insn *insn)
|
||||
{
|
||||
return env->allow_ptr_leaks || BPF_SRC(insn->code) == BPF_K;
|
||||
}
|
||||
|
||||
static int update_alu_sanitation_state(struct bpf_insn_aux_data *aux,
|
||||
u32 alu_state, u32 alu_limit)
|
||||
{
|
||||
/* If we arrived here from different branches with different
|
||||
* state or limits to sanitize, then this won't work.
|
||||
*/
|
||||
if (aux->alu_state &&
|
||||
(aux->alu_state != alu_state ||
|
||||
aux->alu_limit != alu_limit))
|
||||
return -EACCES;
|
||||
|
||||
/* Corresponding fixup done in fixup_bpf_calls(). */
|
||||
aux->alu_state = alu_state;
|
||||
aux->alu_limit = alu_limit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sanitize_val_alu(struct bpf_verifier_env *env,
|
||||
struct bpf_insn *insn)
|
||||
{
|
||||
struct bpf_insn_aux_data *aux = cur_aux(env);
|
||||
|
||||
if (can_skip_alu_sanitation(env, insn))
|
||||
return 0;
|
||||
|
||||
return update_alu_sanitation_state(aux, BPF_ALU_NON_POINTER, 0);
|
||||
}
|
||||
|
||||
static int sanitize_ptr_alu(struct bpf_verifier_env *env,
|
||||
struct bpf_insn *insn,
|
||||
const struct bpf_reg_state *ptr_reg,
|
||||
struct bpf_reg_state *dst_reg,
|
||||
bool off_is_neg)
|
||||
{
|
||||
struct bpf_verifier_state *vstate = env->cur_state;
|
||||
struct bpf_insn_aux_data *aux = cur_aux(env);
|
||||
bool ptr_is_dst_reg = ptr_reg == dst_reg;
|
||||
u8 opcode = BPF_OP(insn->code);
|
||||
u32 alu_state, alu_limit;
|
||||
struct bpf_reg_state tmp;
|
||||
bool ret;
|
||||
|
||||
if (can_skip_alu_sanitation(env, insn))
|
||||
return 0;
|
||||
|
||||
/* We already marked aux for masking from non-speculative
|
||||
* paths, thus we got here in the first place. We only care
|
||||
* to explore bad access from here.
|
||||
*/
|
||||
if (vstate->speculative)
|
||||
goto do_sim;
|
||||
|
||||
alu_state = off_is_neg ? BPF_ALU_NEG_VALUE : 0;
|
||||
alu_state |= ptr_is_dst_reg ?
|
||||
BPF_ALU_SANITIZE_SRC : BPF_ALU_SANITIZE_DST;
|
||||
|
||||
if (retrieve_ptr_limit(ptr_reg, &alu_limit, opcode, off_is_neg))
|
||||
return 0;
|
||||
if (update_alu_sanitation_state(aux, alu_state, alu_limit))
|
||||
return -EACCES;
|
||||
do_sim:
|
||||
/* Simulate and find potential out-of-bounds access under
|
||||
* speculative execution from truncation as a result of
|
||||
* masking when off was not within expected range. If off
|
||||
* sits in dst, then we temporarily need to move ptr there
|
||||
* to simulate dst (== 0) +/-= ptr. Needed, for example,
|
||||
* for cases where we use K-based arithmetic in one direction
|
||||
* and truncated reg-based in the other in order to explore
|
||||
* bad access.
|
||||
*/
|
||||
if (!ptr_is_dst_reg) {
|
||||
tmp = *dst_reg;
|
||||
*dst_reg = *ptr_reg;
|
||||
}
|
||||
ret = push_stack(env, env->insn_idx + 1, env->insn_idx, true);
|
||||
if (!ptr_is_dst_reg)
|
||||
*dst_reg = tmp;
|
||||
return !ret ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
/* Handles arithmetic on a pointer and a scalar: computes new min/max and var_off.
|
||||
* Caller should also handle BPF_MOV case separately.
|
||||
* If we return -EACCES, caller may want to try again treating pointer as a
|
||||
@@ -2700,8 +2838,9 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
|
||||
smin_ptr = ptr_reg->smin_value, smax_ptr = ptr_reg->smax_value;
|
||||
u64 umin_val = off_reg->umin_value, umax_val = off_reg->umax_value,
|
||||
umin_ptr = ptr_reg->umin_value, umax_ptr = ptr_reg->umax_value;
|
||||
u32 dst = insn->dst_reg, src = insn->src_reg;
|
||||
u8 opcode = BPF_OP(insn->code);
|
||||
u32 dst = insn->dst_reg;
|
||||
int ret;
|
||||
|
||||
dst_reg = ®s[dst];
|
||||
|
||||
@@ -2737,6 +2876,12 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
|
||||
dst);
|
||||
return -EACCES;
|
||||
}
|
||||
if (ptr_reg->type == PTR_TO_MAP_VALUE &&
|
||||
!env->allow_ptr_leaks && !known && (smin_val < 0) != (smax_val < 0)) {
|
||||
verbose(env, "R%d has unknown scalar with mixed signed bounds, pointer arithmetic with it prohibited for !root\n",
|
||||
off_reg == dst_reg ? dst : src);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
/* In case of 'scalar += pointer', dst_reg inherits pointer type and id.
|
||||
* The id may be overwritten later if we create a new variable offset.
|
||||
@@ -2750,6 +2895,11 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
|
||||
|
||||
switch (opcode) {
|
||||
case BPF_ADD:
|
||||
ret = sanitize_ptr_alu(env, insn, ptr_reg, dst_reg, smin_val < 0);
|
||||
if (ret < 0) {
|
||||
verbose(env, "R%d tried to add from different maps or paths\n", dst);
|
||||
return ret;
|
||||
}
|
||||
/* We can take a fixed offset as long as it doesn't overflow
|
||||
* the s32 'off' field
|
||||
*/
|
||||
@@ -2800,6 +2950,11 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
|
||||
}
|
||||
break;
|
||||
case BPF_SUB:
|
||||
ret = sanitize_ptr_alu(env, insn, ptr_reg, dst_reg, smin_val < 0);
|
||||
if (ret < 0) {
|
||||
verbose(env, "R%d tried to sub from different maps or paths\n", dst);
|
||||
return ret;
|
||||
}
|
||||
if (dst_reg == off_reg) {
|
||||
/* scalar -= pointer. Creates an unknown scalar */
|
||||
verbose(env, "R%d tried to subtract pointer from scalar\n",
|
||||
@@ -2879,6 +3034,25 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
|
||||
__update_reg_bounds(dst_reg);
|
||||
__reg_deduce_bounds(dst_reg);
|
||||
__reg_bound_offset(dst_reg);
|
||||
|
||||
/* For unprivileged we require that resulting offset must be in bounds
|
||||
* in order to be able to sanitize access later on.
|
||||
*/
|
||||
if (!env->allow_ptr_leaks) {
|
||||
if (dst_reg->type == PTR_TO_MAP_VALUE &&
|
||||
check_map_access(env, dst, dst_reg->off, 1, false)) {
|
||||
verbose(env, "R%d pointer arithmetic of map value goes out of range, "
|
||||
"prohibited for !root\n", dst);
|
||||
return -EACCES;
|
||||
} else if (dst_reg->type == PTR_TO_STACK &&
|
||||
check_stack_access(env, dst_reg, dst_reg->off +
|
||||
dst_reg->var_off.value, 1)) {
|
||||
verbose(env, "R%d stack pointer arithmetic goes out of range, "
|
||||
"prohibited for !root\n", dst);
|
||||
return -EACCES;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2897,6 +3071,8 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
|
||||
s64 smin_val, smax_val;
|
||||
u64 umin_val, umax_val;
|
||||
u64 insn_bitness = (BPF_CLASS(insn->code) == BPF_ALU64) ? 64 : 32;
|
||||
u32 dst = insn->dst_reg;
|
||||
int ret;
|
||||
|
||||
if (insn_bitness == 32) {
|
||||
/* Relevant for 32-bit RSH: Information can propagate towards
|
||||
@@ -2931,6 +3107,11 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
|
||||
|
||||
switch (opcode) {
|
||||
case BPF_ADD:
|
||||
ret = sanitize_val_alu(env, insn);
|
||||
if (ret < 0) {
|
||||
verbose(env, "R%d tried to add from different pointers or scalars\n", dst);
|
||||
return ret;
|
||||
}
|
||||
if (signed_add_overflows(dst_reg->smin_value, smin_val) ||
|
||||
signed_add_overflows(dst_reg->smax_value, smax_val)) {
|
||||
dst_reg->smin_value = S64_MIN;
|
||||
@@ -2950,6 +3131,11 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
|
||||
dst_reg->var_off = tnum_add(dst_reg->var_off, src_reg.var_off);
|
||||
break;
|
||||
case BPF_SUB:
|
||||
ret = sanitize_val_alu(env, insn);
|
||||
if (ret < 0) {
|
||||
verbose(env, "R%d tried to sub from different pointers or scalars\n", dst);
|
||||
return ret;
|
||||
}
|
||||
if (signed_sub_overflows(dst_reg->smin_value, smax_val) ||
|
||||
signed_sub_overflows(dst_reg->smax_value, smin_val)) {
|
||||
/* Overflow possible, we know nothing */
|
||||
@@ -3475,6 +3661,79 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *vstate,
|
||||
}
|
||||
}
|
||||
|
||||
/* compute branch direction of the expression "if (reg opcode val) goto target;"
|
||||
* and return:
|
||||
* 1 - branch will be taken and "goto target" will be executed
|
||||
* 0 - branch will not be taken and fall-through to next insn
|
||||
* -1 - unknown. Example: "if (reg < 5)" is unknown when register value range [0,10]
|
||||
*/
|
||||
static int is_branch_taken(struct bpf_reg_state *reg, u64 val, u8 opcode)
|
||||
{
|
||||
if (__is_pointer_value(false, reg))
|
||||
return -1;
|
||||
|
||||
switch (opcode) {
|
||||
case BPF_JEQ:
|
||||
if (tnum_is_const(reg->var_off))
|
||||
return !!tnum_equals_const(reg->var_off, val);
|
||||
break;
|
||||
case BPF_JNE:
|
||||
if (tnum_is_const(reg->var_off))
|
||||
return !tnum_equals_const(reg->var_off, val);
|
||||
break;
|
||||
case BPF_JGT:
|
||||
if (reg->umin_value > val)
|
||||
return 1;
|
||||
else if (reg->umax_value <= val)
|
||||
return 0;
|
||||
break;
|
||||
case BPF_JSGT:
|
||||
if (reg->smin_value > (s64)val)
|
||||
return 1;
|
||||
else if (reg->smax_value < (s64)val)
|
||||
return 0;
|
||||
break;
|
||||
case BPF_JLT:
|
||||
if (reg->umax_value < val)
|
||||
return 1;
|
||||
else if (reg->umin_value >= val)
|
||||
return 0;
|
||||
break;
|
||||
case BPF_JSLT:
|
||||
if (reg->smax_value < (s64)val)
|
||||
return 1;
|
||||
else if (reg->smin_value >= (s64)val)
|
||||
return 0;
|
||||
break;
|
||||
case BPF_JGE:
|
||||
if (reg->umin_value >= val)
|
||||
return 1;
|
||||
else if (reg->umax_value < val)
|
||||
return 0;
|
||||
break;
|
||||
case BPF_JSGE:
|
||||
if (reg->smin_value >= (s64)val)
|
||||
return 1;
|
||||
else if (reg->smax_value < (s64)val)
|
||||
return 0;
|
||||
break;
|
||||
case BPF_JLE:
|
||||
if (reg->umax_value <= val)
|
||||
return 1;
|
||||
else if (reg->umin_value > val)
|
||||
return 0;
|
||||
break;
|
||||
case BPF_JSLE:
|
||||
if (reg->smax_value <= (s64)val)
|
||||
return 1;
|
||||
else if (reg->smin_value > (s64)val)
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Adjusts the register min/max values in the case that the dst_reg is the
|
||||
* variable register that we are working on, and src_reg is a constant or we're
|
||||
* simply doing a BPF_K check.
|
||||
@@ -3868,28 +4127,23 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
|
||||
|
||||
dst_reg = ®s[insn->dst_reg];
|
||||
|
||||
/* detect if R == 0 where R was initialized to zero earlier */
|
||||
if (BPF_SRC(insn->code) == BPF_K &&
|
||||
(opcode == BPF_JEQ || opcode == BPF_JNE) &&
|
||||
dst_reg->type == SCALAR_VALUE &&
|
||||
tnum_is_const(dst_reg->var_off)) {
|
||||
if ((opcode == BPF_JEQ && dst_reg->var_off.value == insn->imm) ||
|
||||
(opcode == BPF_JNE && dst_reg->var_off.value != insn->imm)) {
|
||||
/* if (imm == imm) goto pc+off;
|
||||
* only follow the goto, ignore fall-through
|
||||
*/
|
||||
if (BPF_SRC(insn->code) == BPF_K) {
|
||||
int pred = is_branch_taken(dst_reg, insn->imm, opcode);
|
||||
|
||||
if (pred == 1) {
|
||||
/* only follow the goto, ignore fall-through */
|
||||
*insn_idx += insn->off;
|
||||
return 0;
|
||||
} else {
|
||||
/* if (imm != imm) goto pc+off;
|
||||
* only follow fall-through branch, since
|
||||
} else if (pred == 0) {
|
||||
/* only follow fall-through branch, since
|
||||
* that's where the program will go
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
other_branch = push_stack(env, *insn_idx + insn->off + 1, *insn_idx);
|
||||
other_branch = push_stack(env, *insn_idx + insn->off + 1, *insn_idx,
|
||||
false);
|
||||
if (!other_branch)
|
||||
return -EFAULT;
|
||||
other_branch_regs = other_branch->frame[other_branch->curframe]->regs;
|
||||
@@ -4604,6 +4858,12 @@ static bool states_equal(struct bpf_verifier_env *env,
|
||||
if (old->curframe != cur->curframe)
|
||||
return false;
|
||||
|
||||
/* Verification state from speculative execution simulation
|
||||
* must never prune a non-speculative execution one.
|
||||
*/
|
||||
if (old->speculative && !cur->speculative)
|
||||
return false;
|
||||
|
||||
/* for states to be equal callsites have to be the same
|
||||
* and all frame states need to be equivalent
|
||||
*/
|
||||
@@ -4668,7 +4928,7 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
|
||||
struct bpf_verifier_state_list *new_sl;
|
||||
struct bpf_verifier_state_list *sl;
|
||||
struct bpf_verifier_state *cur = env->cur_state;
|
||||
int i, j, err;
|
||||
int i, j, err, states_cnt = 0;
|
||||
|
||||
sl = env->explored_states[insn_idx];
|
||||
if (!sl)
|
||||
@@ -4695,8 +4955,12 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
|
||||
return 1;
|
||||
}
|
||||
sl = sl->next;
|
||||
states_cnt++;
|
||||
}
|
||||
|
||||
if (!env->allow_ptr_leaks && states_cnt > BPF_COMPLEXITY_LIMIT_STATES)
|
||||
return 0;
|
||||
|
||||
/* there were no equivalent states, remember current one.
|
||||
* technically the current state is not proven to be safe yet,
|
||||
* but it will either reach outer most bpf_exit (which means it's safe)
|
||||
@@ -4744,7 +5008,6 @@ static int do_check(struct bpf_verifier_env *env)
|
||||
struct bpf_insn *insns = env->prog->insnsi;
|
||||
struct bpf_reg_state *regs;
|
||||
int insn_cnt = env->prog->len, i;
|
||||
int insn_idx, prev_insn_idx = 0;
|
||||
int insn_processed = 0;
|
||||
bool do_print_state = false;
|
||||
|
||||
@@ -4752,7 +5015,7 @@ static int do_check(struct bpf_verifier_env *env)
|
||||
if (!state)
|
||||
return -ENOMEM;
|
||||
state->curframe = 0;
|
||||
state->parent = NULL;
|
||||
state->speculative = false;
|
||||
state->frame[0] = kzalloc(sizeof(struct bpf_func_state), GFP_KERNEL);
|
||||
if (!state->frame[0]) {
|
||||
kfree(state);
|
||||
@@ -4763,19 +5026,19 @@ static int do_check(struct bpf_verifier_env *env)
|
||||
BPF_MAIN_FUNC /* callsite */,
|
||||
0 /* frameno */,
|
||||
0 /* subprogno, zero == main subprog */);
|
||||
insn_idx = 0;
|
||||
|
||||
for (;;) {
|
||||
struct bpf_insn *insn;
|
||||
u8 class;
|
||||
int err;
|
||||
|
||||
if (insn_idx >= insn_cnt) {
|
||||
if (env->insn_idx >= insn_cnt) {
|
||||
verbose(env, "invalid insn idx %d insn_cnt %d\n",
|
||||
insn_idx, insn_cnt);
|
||||
env->insn_idx, insn_cnt);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
insn = &insns[insn_idx];
|
||||
insn = &insns[env->insn_idx];
|
||||
class = BPF_CLASS(insn->code);
|
||||
|
||||
if (++insn_processed > BPF_COMPLEXITY_LIMIT_INSNS) {
|
||||
@@ -4785,17 +5048,19 @@ static int do_check(struct bpf_verifier_env *env)
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
err = is_state_visited(env, insn_idx);
|
||||
err = is_state_visited(env, env->insn_idx);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (err == 1) {
|
||||
/* found equivalent state, can prune the search */
|
||||
if (env->log.level) {
|
||||
if (do_print_state)
|
||||
verbose(env, "\nfrom %d to %d: safe\n",
|
||||
prev_insn_idx, insn_idx);
|
||||
verbose(env, "\nfrom %d to %d%s: safe\n",
|
||||
env->prev_insn_idx, env->insn_idx,
|
||||
env->cur_state->speculative ?
|
||||
" (speculative execution)" : "");
|
||||
else
|
||||
verbose(env, "%d: safe\n", insn_idx);
|
||||
verbose(env, "%d: safe\n", env->insn_idx);
|
||||
}
|
||||
goto process_bpf_exit;
|
||||
}
|
||||
@@ -4808,10 +5073,12 @@ static int do_check(struct bpf_verifier_env *env)
|
||||
|
||||
if (env->log.level > 1 || (env->log.level && do_print_state)) {
|
||||
if (env->log.level > 1)
|
||||
verbose(env, "%d:", insn_idx);
|
||||
verbose(env, "%d:", env->insn_idx);
|
||||
else
|
||||
verbose(env, "\nfrom %d to %d:",
|
||||
prev_insn_idx, insn_idx);
|
||||
verbose(env, "\nfrom %d to %d%s:",
|
||||
env->prev_insn_idx, env->insn_idx,
|
||||
env->cur_state->speculative ?
|
||||
" (speculative execution)" : "");
|
||||
print_verifier_state(env, state->frame[state->curframe]);
|
||||
do_print_state = false;
|
||||
}
|
||||
@@ -4822,19 +5089,20 @@ static int do_check(struct bpf_verifier_env *env)
|
||||
.private_data = env,
|
||||
};
|
||||
|
||||
verbose(env, "%d: ", insn_idx);
|
||||
verbose(env, "%d: ", env->insn_idx);
|
||||
print_bpf_insn(&cbs, insn, env->allow_ptr_leaks);
|
||||
}
|
||||
|
||||
if (bpf_prog_is_dev_bound(env->prog->aux)) {
|
||||
err = bpf_prog_offload_verify_insn(env, insn_idx,
|
||||
prev_insn_idx);
|
||||
err = bpf_prog_offload_verify_insn(env, env->insn_idx,
|
||||
env->prev_insn_idx);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
regs = cur_regs(env);
|
||||
env->insn_aux_data[insn_idx].seen = true;
|
||||
env->insn_aux_data[env->insn_idx].seen = true;
|
||||
|
||||
if (class == BPF_ALU || class == BPF_ALU64) {
|
||||
err = check_alu_op(env, insn);
|
||||
if (err)
|
||||
@@ -4859,13 +5127,13 @@ static int do_check(struct bpf_verifier_env *env)
|
||||
/* check that memory (src_reg + off) is readable,
|
||||
* the state of dst_reg will be updated by this func
|
||||
*/
|
||||
err = check_mem_access(env, insn_idx, insn->src_reg, insn->off,
|
||||
BPF_SIZE(insn->code), BPF_READ,
|
||||
insn->dst_reg, false);
|
||||
err = check_mem_access(env, env->insn_idx, insn->src_reg,
|
||||
insn->off, BPF_SIZE(insn->code),
|
||||
BPF_READ, insn->dst_reg, false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
prev_src_type = &env->insn_aux_data[insn_idx].ptr_type;
|
||||
prev_src_type = &env->insn_aux_data[env->insn_idx].ptr_type;
|
||||
|
||||
if (*prev_src_type == NOT_INIT) {
|
||||
/* saw a valid insn
|
||||
@@ -4892,10 +5160,10 @@ static int do_check(struct bpf_verifier_env *env)
|
||||
enum bpf_reg_type *prev_dst_type, dst_reg_type;
|
||||
|
||||
if (BPF_MODE(insn->code) == BPF_XADD) {
|
||||
err = check_xadd(env, insn_idx, insn);
|
||||
err = check_xadd(env, env->insn_idx, insn);
|
||||
if (err)
|
||||
return err;
|
||||
insn_idx++;
|
||||
env->insn_idx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -4911,13 +5179,13 @@ static int do_check(struct bpf_verifier_env *env)
|
||||
dst_reg_type = regs[insn->dst_reg].type;
|
||||
|
||||
/* check that memory (dst_reg + off) is writeable */
|
||||
err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
|
||||
BPF_SIZE(insn->code), BPF_WRITE,
|
||||
insn->src_reg, false);
|
||||
err = check_mem_access(env, env->insn_idx, insn->dst_reg,
|
||||
insn->off, BPF_SIZE(insn->code),
|
||||
BPF_WRITE, insn->src_reg, false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
prev_dst_type = &env->insn_aux_data[insn_idx].ptr_type;
|
||||
prev_dst_type = &env->insn_aux_data[env->insn_idx].ptr_type;
|
||||
|
||||
if (*prev_dst_type == NOT_INIT) {
|
||||
*prev_dst_type = dst_reg_type;
|
||||
@@ -4946,9 +5214,9 @@ static int do_check(struct bpf_verifier_env *env)
|
||||
}
|
||||
|
||||
/* check that memory (dst_reg + off) is writeable */
|
||||
err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
|
||||
BPF_SIZE(insn->code), BPF_WRITE,
|
||||
-1, false);
|
||||
err = check_mem_access(env, env->insn_idx, insn->dst_reg,
|
||||
insn->off, BPF_SIZE(insn->code),
|
||||
BPF_WRITE, -1, false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -4966,9 +5234,9 @@ static int do_check(struct bpf_verifier_env *env)
|
||||
}
|
||||
|
||||
if (insn->src_reg == BPF_PSEUDO_CALL)
|
||||
err = check_func_call(env, insn, &insn_idx);
|
||||
err = check_func_call(env, insn, &env->insn_idx);
|
||||
else
|
||||
err = check_helper_call(env, insn->imm, insn_idx);
|
||||
err = check_helper_call(env, insn->imm, env->insn_idx);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -4981,7 +5249,7 @@ static int do_check(struct bpf_verifier_env *env)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
insn_idx += insn->off + 1;
|
||||
env->insn_idx += insn->off + 1;
|
||||
continue;
|
||||
|
||||
} else if (opcode == BPF_EXIT) {
|
||||
@@ -4995,8 +5263,8 @@ static int do_check(struct bpf_verifier_env *env)
|
||||
|
||||
if (state->curframe) {
|
||||
/* exit from nested function */
|
||||
prev_insn_idx = insn_idx;
|
||||
err = prepare_func_exit(env, &insn_idx);
|
||||
env->prev_insn_idx = env->insn_idx;
|
||||
err = prepare_func_exit(env, &env->insn_idx);
|
||||
if (err)
|
||||
return err;
|
||||
do_print_state = true;
|
||||
@@ -5022,7 +5290,8 @@ static int do_check(struct bpf_verifier_env *env)
|
||||
if (err)
|
||||
return err;
|
||||
process_bpf_exit:
|
||||
err = pop_stack(env, &prev_insn_idx, &insn_idx);
|
||||
err = pop_stack(env, &env->prev_insn_idx,
|
||||
&env->insn_idx);
|
||||
if (err < 0) {
|
||||
if (err != -ENOENT)
|
||||
return err;
|
||||
@@ -5032,7 +5301,7 @@ process_bpf_exit:
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
err = check_cond_jmp_op(env, insn, &insn_idx);
|
||||
err = check_cond_jmp_op(env, insn, &env->insn_idx);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@@ -5049,8 +5318,8 @@ process_bpf_exit:
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
insn_idx++;
|
||||
env->insn_aux_data[insn_idx].seen = true;
|
||||
env->insn_idx++;
|
||||
env->insn_aux_data[env->insn_idx].seen = true;
|
||||
} else {
|
||||
verbose(env, "invalid BPF_LD mode\n");
|
||||
return -EINVAL;
|
||||
@@ -5060,7 +5329,7 @@ process_bpf_exit:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
insn_idx++;
|
||||
env->insn_idx++;
|
||||
}
|
||||
|
||||
verbose(env, "processed %d insns (limit %d), stack depth ",
|
||||
@@ -5756,6 +6025,57 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (insn->code == (BPF_ALU64 | BPF_ADD | BPF_X) ||
|
||||
insn->code == (BPF_ALU64 | BPF_SUB | BPF_X)) {
|
||||
const u8 code_add = BPF_ALU64 | BPF_ADD | BPF_X;
|
||||
const u8 code_sub = BPF_ALU64 | BPF_SUB | BPF_X;
|
||||
struct bpf_insn insn_buf[16];
|
||||
struct bpf_insn *patch = &insn_buf[0];
|
||||
bool issrc, isneg;
|
||||
u32 off_reg;
|
||||
|
||||
aux = &env->insn_aux_data[i + delta];
|
||||
if (!aux->alu_state)
|
||||
continue;
|
||||
|
||||
isneg = aux->alu_state & BPF_ALU_NEG_VALUE;
|
||||
issrc = (aux->alu_state & BPF_ALU_SANITIZE) ==
|
||||
BPF_ALU_SANITIZE_SRC;
|
||||
|
||||
off_reg = issrc ? insn->src_reg : insn->dst_reg;
|
||||
if (isneg)
|
||||
*patch++ = BPF_ALU64_IMM(BPF_MUL, off_reg, -1);
|
||||
*patch++ = BPF_MOV32_IMM(BPF_REG_AX, aux->alu_limit - 1);
|
||||
*patch++ = BPF_ALU64_REG(BPF_SUB, BPF_REG_AX, off_reg);
|
||||
*patch++ = BPF_ALU64_REG(BPF_OR, BPF_REG_AX, off_reg);
|
||||
*patch++ = BPF_ALU64_IMM(BPF_NEG, BPF_REG_AX, 0);
|
||||
*patch++ = BPF_ALU64_IMM(BPF_ARSH, BPF_REG_AX, 63);
|
||||
if (issrc) {
|
||||
*patch++ = BPF_ALU64_REG(BPF_AND, BPF_REG_AX,
|
||||
off_reg);
|
||||
insn->src_reg = BPF_REG_AX;
|
||||
} else {
|
||||
*patch++ = BPF_ALU64_REG(BPF_AND, off_reg,
|
||||
BPF_REG_AX);
|
||||
}
|
||||
if (isneg)
|
||||
insn->code = insn->code == code_add ?
|
||||
code_sub : code_add;
|
||||
*patch++ = *insn;
|
||||
if (issrc && isneg)
|
||||
*patch++ = BPF_ALU64_IMM(BPF_MUL, off_reg, -1);
|
||||
cnt = patch - insn_buf;
|
||||
|
||||
new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
|
||||
if (!new_prog)
|
||||
return -ENOMEM;
|
||||
|
||||
delta += cnt - 1;
|
||||
env->prog = prog = new_prog;
|
||||
insn = new_prog->insnsi + i + delta;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (insn->code != (BPF_JMP | BPF_CALL))
|
||||
continue;
|
||||
if (insn->src_reg == BPF_PSEUDO_CALL)
|
||||
|
||||
@@ -685,6 +685,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
|
||||
* set up the signal and overrun bookkeeping.
|
||||
*/
|
||||
timer->it.cpu.incr = timespec64_to_ns(&new->it_interval);
|
||||
timer->it_interval = ns_to_ktime(timer->it.cpu.incr);
|
||||
|
||||
/*
|
||||
* This acts as a modification timestamp for the timer,
|
||||
|
||||
Reference in New Issue
Block a user