Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not include the original insn in zext patchlet #30

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
sudo: required
language: bash
dist: bionic
services:
- docker

env:
global:
- PROJECT_NAME='libbpf'
- AUTHOR_EMAIL="$(git log -1 --pretty=\"%aE\")"
- REPO_ROOT="$TRAVIS_BUILD_DIR"
- CI_ROOT="$REPO_ROOT/travis-ci"
- VMTEST_ROOT="$CI_ROOT/vmtest"

addons:
apt:
packages:
- qemu-kvm
- zstd
- binutils-dev
- elfutils
- libcap-dev
- libelf-dev
- libdw-dev

jobs:
include:
- stage: Builds & Tests
name: Kernel LATEST + selftests
language: bash
env: KERNEL=LATEST
script: $CI_ROOT/vmtest/run_vmtest.sh || travis_terminate 1
4 changes: 2 additions & 2 deletions include/linux/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -892,8 +892,8 @@ static inline bool bpf_dump_raw_ok(const struct cred *cred)
return kallsyms_show_value(cred);
}

struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
const struct bpf_insn *patch, u32 len);
struct bpf_prog *bpf_patch_insns(struct bpf_prog *prog, u32 off, u32 len_old,
const struct bpf_insn *patch, u32 len);
int bpf_remove_insns(struct bpf_prog *prog, u32 off, u32 cnt);

void bpf_clear_redirect_map(struct bpf_map *map);
Expand Down
18 changes: 9 additions & 9 deletions kernel/bpf/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -429,10 +429,10 @@ static void bpf_adj_linfo(struct bpf_prog *prog, u32 off, u32 delta)
linfo[i].insn_off += delta;
}

struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
const struct bpf_insn *patch, u32 len)
struct bpf_prog *bpf_patch_insns(struct bpf_prog *prog, u32 off, u32 len_old,
const struct bpf_insn *patch, u32 len)
{
u32 insn_adj_cnt, insn_rest, insn_delta = len - 1;
u32 insn_adj_cnt, insn_rest, insn_delta = len - len_old;
const u32 cnt_max = S16_MAX;
struct bpf_prog *prog_adj;
int err;
Expand All @@ -451,7 +451,7 @@ struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
* we afterwards may not fail anymore.
*/
if (insn_adj_cnt > cnt_max &&
(err = bpf_adj_branches(prog, off, off + 1, off + len, true)))
(err = bpf_adj_branches(prog, off, off + len_old, off + len, true)))
return ERR_PTR(err);

/* Several new instructions need to be inserted. Make room
Expand All @@ -468,22 +468,22 @@ struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
/* Patching happens in 3 steps:
*
* 1) Move over tail of insnsi from next instruction onwards,
* so we can patch the single target insn with one or more
* new ones (patching is always from 1 to n insns, n > 0).
* so we can patch the target insns.
* 2) Inject new instructions at the target location.
* 3) Adjust branch offsets if necessary.
*/
insn_rest = insn_adj_cnt - off - len;

memmove(prog_adj->insnsi + off + len, prog_adj->insnsi + off + 1,
memmove(prog_adj->insnsi + off + len, prog_adj->insnsi + off + len_old,
sizeof(*patch) * insn_rest);
memcpy(prog_adj->insnsi + off, patch, sizeof(*patch) * len);

/* We are guaranteed to not fail at this point, otherwise
* the ship has sailed to reverse to the original state. An
* overflow cannot happen at this point.
*/
BUG_ON(bpf_adj_branches(prog_adj, off, off + 1, off + len, false));
BUG_ON(bpf_adj_branches(prog_adj, off, off + len_old, off + len,
false));

bpf_adj_linfo(prog_adj, off, insn_delta);

Expand Down Expand Up @@ -1155,7 +1155,7 @@ struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog)
if (!rewritten)
continue;

tmp = bpf_patch_insn_single(clone, i, insn_buff, rewritten);
tmp = bpf_patch_insns(clone, i, 1, insn_buff, rewritten);
if (IS_ERR(tmp)) {
/* Patching may have repointed aux->prog during
* realloc from the original one, so we need to
Expand Down
100 changes: 59 additions & 41 deletions kernel/bpf/verifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -9572,35 +9572,40 @@ static void convert_pseudo_ld_imm64(struct bpf_verifier_env *env)
insn->src_reg = 0;
}

/* single env->prog->insni[off] instruction was replaced with the range
* insni[off, off + cnt). Adjust corresponding insn_aux_data by copying
* [0, off) and [off, end) to new locations, so the patched range stays zero
/* Instructions from the range env->prog->insni[off, off + cnt_old) were
* replaced with the range insni[off, off + cnt). Adjust corresponding
* insn_aux_data by copying [0, off) and [off, end) to new locations, so the
* patched range stays zero.
*/
static int adjust_insn_aux_data(struct bpf_verifier_env *env,
struct bpf_prog *new_prog, u32 off, u32 cnt)
static int adjust_insns_aux_data(struct bpf_verifier_env *env,
struct bpf_prog *new_prog, u32 off,
u32 cnt_old, u32 cnt)
{
struct bpf_insn_aux_data *new_data, *old_data = env->insn_aux_data;
struct bpf_insn *insn = new_prog->insnsi;
u32 prog_len;
int i;

/* aux info at OFF always needs adjustment, no matter fast path
* (cnt == 1) is taken or not. There is no guarantee INSN at OFF is the
* original insn at old prog.
/* aux infos at [off, off + cnt_old) need adjustment even on the fast
* path (cnt == cnt_old). There is no guarantee the insns at [off,
* off + cnt_old) are the original ones at old prog.
*/
old_data[off].zext_dst = insn_has_def32(env, insn + off + cnt - 1);
for (i = off; i < off + cnt_old; i++)
old_data[i].zext_dst =
insn_has_def32(env, insn + i + cnt - cnt_old);

if (cnt == 1)
if (cnt == cnt_old)
return 0;
prog_len = new_prog->len;
new_data = vzalloc(array_size(prog_len,
sizeof(struct bpf_insn_aux_data)));
if (!new_data)
return -ENOMEM;
memcpy(new_data, old_data, sizeof(struct bpf_insn_aux_data) * off);
memcpy(new_data + off + cnt - 1, old_data + off,
sizeof(struct bpf_insn_aux_data) * (prog_len - off - cnt + 1));
for (i = off; i < off + cnt - 1; i++) {
memcpy(new_data + off + cnt - cnt_old, old_data + off,
sizeof(struct bpf_insn_aux_data) *
(prog_len - off - cnt + cnt_old));
for (i = off; i < off + cnt - cnt_old; i++) {
new_data[i].seen = env->pass_cnt;
new_data[i].zext_dst = insn_has_def32(env, insn + i);
}
Expand All @@ -9609,36 +9614,39 @@ static int adjust_insn_aux_data(struct bpf_verifier_env *env,
return 0;
}

static void adjust_subprog_starts(struct bpf_verifier_env *env, u32 off, u32 len)
static void adjust_subprog_starts(struct bpf_verifier_env *env, u32 off,
u32 len_old, u32 len)
{
int i;

if (len == 1)
if (len == len_old)
return;
/* NOTE: fake 'exit' subprog should be updated as well. */
for (i = 0; i <= env->subprog_cnt; i++) {
if (env->subprog_info[i].start <= off)
continue;
env->subprog_info[i].start += len - 1;
env->subprog_info[i].start += len - len_old;
}
}

static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
const struct bpf_insn *patch, u32 len)
static struct bpf_prog *bpf_patch_insns_data(struct bpf_verifier_env *env,
u32 off, u32 len_old,
const struct bpf_insn *patch,
u32 len)
{
struct bpf_prog *new_prog;

new_prog = bpf_patch_insn_single(env->prog, off, patch, len);
new_prog = bpf_patch_insns(env->prog, off, len_old, patch, len);
if (IS_ERR(new_prog)) {
if (PTR_ERR(new_prog) == -ERANGE)
verbose(env,
"insn %d cannot be patched due to 16-bit range\n",
env->insn_aux_data[off].orig_idx);
return NULL;
}
if (adjust_insn_aux_data(env, new_prog, off, len))
if (adjust_insns_aux_data(env, new_prog, off, len_old, len))
return NULL;
adjust_subprog_starts(env, off, len);
adjust_subprog_starts(env, off, len_old, len);
return new_prog;
}

Expand Down Expand Up @@ -9903,21 +9911,22 @@ static int opt_remove_nops(struct bpf_verifier_env *env)
static int opt_subreg_zext_lo32_rnd_hi32(struct bpf_verifier_env *env,
const union bpf_attr *attr)
{
struct bpf_insn *patch, zext_patch[2], rnd_hi32_patch[4];
struct bpf_insn *patch, zext_patch, rnd_hi32_patch[4];
struct bpf_insn_aux_data *aux = env->insn_aux_data;
int i, patch_len, delta = 0, len = env->prog->len;
struct bpf_insn *insns = env->prog->insnsi;
struct bpf_prog *new_prog;
bool rnd_hi32;

rnd_hi32 = attr->prog_flags & BPF_F_TEST_RND_HI32;
zext_patch[1] = BPF_ZEXT_REG(0);
zext_patch = BPF_ZEXT_REG(0);
rnd_hi32_patch[1] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, 0);
rnd_hi32_patch[2] = BPF_ALU64_IMM(BPF_LSH, BPF_REG_AX, 32);
rnd_hi32_patch[3] = BPF_ALU64_REG(BPF_OR, 0, BPF_REG_AX);
for (i = 0; i < len; i++) {
int adj_idx = i + delta;
struct bpf_insn insn;
int len_old = 1;

insn = insns[adj_idx];
if (!aux[adj_idx].zext_dst) {
Expand Down Expand Up @@ -9960,19 +9969,21 @@ static int opt_subreg_zext_lo32_rnd_hi32(struct bpf_verifier_env *env,
if (!bpf_jit_needs_zext())
continue;

zext_patch[0] = insn;
zext_patch[1].dst_reg = insn.dst_reg;
zext_patch[1].src_reg = insn.dst_reg;
patch = zext_patch;
patch_len = 2;
zext_patch.dst_reg = insn.dst_reg;
zext_patch.src_reg = insn.dst_reg;
patch = &zext_patch;
patch_len = 1;
adj_idx++;
len_old = 0;
apply_patch_buffer:
new_prog = bpf_patch_insn_data(env, adj_idx, patch, patch_len);
new_prog = bpf_patch_insns_data(env, adj_idx, len_old, patch,
patch_len);
if (!new_prog)
return -ENOMEM;
env->prog = new_prog;
insns = new_prog->insnsi;
aux = env->insn_aux_data;
delta += patch_len - 1;
delta += patch_len - len_old;
}

return 0;
Expand Down Expand Up @@ -10005,7 +10016,8 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
verbose(env, "bpf verifier is misconfigured\n");
return -EINVAL;
} else if (cnt) {
new_prog = bpf_patch_insn_data(env, 0, insn_buf, cnt);
new_prog =
bpf_patch_insns_data(env, 0, 1, insn_buf, cnt);
if (!new_prog)
return -ENOMEM;

Expand Down Expand Up @@ -10053,7 +10065,8 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
};

cnt = ARRAY_SIZE(patch);
new_prog = bpf_patch_insn_data(env, i + delta, patch, cnt);
new_prog = bpf_patch_insns_data(env, i + delta, 1,
patch, cnt);
if (!new_prog)
return -ENOMEM;

Expand Down Expand Up @@ -10151,7 +10164,8 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
}
}

new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
new_prog =
bpf_patch_insns_data(env, i + delta, 1, insn_buf, cnt);
if (!new_prog)
return -ENOMEM;

Expand Down Expand Up @@ -10429,7 +10443,8 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
cnt = ARRAY_SIZE(mask_and_mod) - (is64 ? 1 : 0);
}

new_prog = bpf_patch_insn_data(env, i + delta, patchlet, cnt);
new_prog = bpf_patch_insns_data(env, i + delta, 1,
patchlet, cnt);
if (!new_prog)
return -ENOMEM;

Expand All @@ -10448,7 +10463,8 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
return -EINVAL;
}

new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
new_prog = bpf_patch_insns_data(env, i + delta, 1,
insn_buf, cnt);
if (!new_prog)
return -ENOMEM;

Expand Down Expand Up @@ -10500,7 +10516,8 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
*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);
new_prog = bpf_patch_insns_data(env, i + delta, 1,
insn_buf, cnt);
if (!new_prog)
return -ENOMEM;

Expand Down Expand Up @@ -10584,7 +10601,8 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
map)->index_mask);
insn_buf[2] = *insn;
cnt = 3;
new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
new_prog = bpf_patch_insns_data(env, i + delta, 1,
insn_buf, cnt);
if (!new_prog)
return -ENOMEM;

Expand Down Expand Up @@ -10619,8 +10637,8 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
return -EINVAL;
}

new_prog = bpf_patch_insn_data(env, i + delta,
insn_buf, cnt);
new_prog = bpf_patch_insns_data(
env, i + delta, 1, insn_buf, cnt);
if (!new_prog)
return -ENOMEM;

Expand Down Expand Up @@ -10688,8 +10706,8 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
BPF_REG_0, 0);
cnt = 3;

new_prog = bpf_patch_insn_data(env, i + delta, insn_buf,
cnt);
new_prog = bpf_patch_insns_data(env, i + delta, 1,
insn_buf, cnt);
if (!new_prog)
return -ENOMEM;

Expand Down
Loading