Skip to content

Commit 3e29ecc

Browse files
mdouchametan-ucw
authored andcommitted
Add test for CVE 2018-18445
Fixes #413 Signed-off-by: Martin Doucha <[email protected]> Reviewed-by: Cyril Hrubis <[email protected]>
1 parent 79660ff commit 3e29ecc

File tree

4 files changed

+148
-0
lines changed

4 files changed

+148
-0
lines changed

runtest/cve

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ cve-2018-9568 connect02
5252
cve-2018-1000001 realpath01
5353
cve-2018-1000199 ptrace08
5454
cve-2018-1000204 ioctl_sg01
55+
cve-2018-18445 bpf_prog04
5556
cve-2018-18559 bind06
5657
cve-2018-19854 crypto_user01
5758
cve-2019-8912 af_alg07

runtest/syscalls

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ bpf_map01 bpf_map01
4141
bpf_prog01 bpf_prog01
4242
bpf_prog02 bpf_prog02
4343
bpf_prog03 bpf_prog03
44+
bpf_prog04 bpf_prog04
4445

4546
brk01 brk01
4647

testcases/kernel/syscalls/bpf/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ bpf_map01
22
bpf_prog01
33
bpf_prog02
44
bpf_prog03
5+
bpf_prog04
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (c) 2018 Jann Horn <[email protected]>
4+
* Copyright (c) 2020 SUSE LLC <[email protected]>
5+
*/
6+
7+
/*
8+
* CVE 2018-18445
9+
*
10+
* Check that eBPF verifier correctly handles 32-bit arithmetic, in particular
11+
* the right bit shift instruction. It is an error if the BPF program passes
12+
* verification regardless of whether it then causes any actual damage. Kernel
13+
* bug fixed in:
14+
*
15+
* commit b799207e1e1816b09e7a5920fbb2d5fcf6edd681
16+
* Author: Jann Horn <[email protected]>
17+
* Date: Fri Oct 5 18:17:59 2018 +0200
18+
*
19+
* bpf: 32-bit RSH verification must truncate input before the ALU op
20+
*/
21+
22+
#include <stdio.h>
23+
#include <string.h>
24+
25+
#include "config.h"
26+
#include "tst_test.h"
27+
#include "tst_taint.h"
28+
#include "tst_capability.h"
29+
#include "lapi/socket.h"
30+
#include "lapi/bpf.h"
31+
#include "bpf_common.h"
32+
33+
#define BUFSIZE 8192
34+
#define CHECK_BPF_RET(x) ((x) >= 0 || ((x) == -1 && errno != EACCES))
35+
36+
static const char MSG[] = "Ahoj!";
37+
static char *msg;
38+
39+
static char *log;
40+
static union bpf_attr *attr;
41+
42+
static int load_prog(int fd)
43+
{
44+
int ret;
45+
struct bpf_insn insn[] = {
46+
BPF_MOV64_IMM(BPF_REG_8, 2),
47+
BPF_ALU64_IMM(BPF_LSH, BPF_REG_8, 31),
48+
BPF_ALU32_IMM(BPF_RSH, BPF_REG_8, 31),
49+
BPF_ALU32_IMM(BPF_SUB, BPF_REG_8, 2),
50+
51+
// store r8 into map
52+
BPF_LD_MAP_FD(BPF_REG_1, fd),
53+
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
54+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),
55+
BPF_ST_MEM(BPF_W, BPF_REG_2, 0, 0),
56+
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
57+
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
58+
BPF_EXIT_INSN(),
59+
BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_8),
60+
BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_8, 0),
61+
62+
BPF_MOV64_IMM(BPF_REG_0, 0),
63+
BPF_EXIT_INSN()
64+
};
65+
66+
bpf_init_prog_attr(attr, insn, sizeof(insn), log, BUFSIZE);
67+
ret = TST_RETRY_FUNC(bpf(BPF_PROG_LOAD, attr, sizeof(*attr)),
68+
CHECK_BPF_RET);
69+
70+
if (ret >= 0) {
71+
tst_res(TINFO, "Verification log:");
72+
fputs(log, stderr);
73+
return ret;
74+
}
75+
76+
if (ret < -1)
77+
tst_brk(TBROK, "Invalid bpf() return value %d", ret);
78+
79+
if (!*log)
80+
tst_brk(TBROK | TERRNO, "Failed to load BPF program");
81+
82+
tst_res(TPASS | TERRNO, "BPF program failed verification");
83+
return ret;
84+
}
85+
86+
static void setup(void)
87+
{
88+
tst_taint_init(TST_TAINT_W | TST_TAINT_D);
89+
90+
rlimit_bump_memlock();
91+
memcpy(msg, MSG, sizeof(MSG));
92+
}
93+
94+
static void run(void)
95+
{
96+
int map_fd, prog_fd;
97+
int sk[2];
98+
99+
memset(attr, 0, sizeof(*attr));
100+
attr->map_type = BPF_MAP_TYPE_ARRAY;
101+
attr->key_size = 4;
102+
attr->value_size = 8;
103+
attr->max_entries = 1;
104+
105+
map_fd = bpf_map_create(attr);
106+
prog_fd = load_prog(map_fd);
107+
108+
if (prog_fd >= 0) {
109+
tst_res(TFAIL, "Malicious eBPF code passed verification. "
110+
"Now let's try crashing the kernel.");
111+
SAFE_SOCKETPAIR(AF_UNIX, SOCK_DGRAM, 0, sk);
112+
SAFE_SETSOCKOPT(sk[1], SOL_SOCKET, SO_ATTACH_BPF, &prog_fd,
113+
sizeof(prog_fd));
114+
115+
SAFE_WRITE(1, sk[0], msg, sizeof(MSG));
116+
SAFE_CLOSE(sk[0]);
117+
SAFE_CLOSE(sk[1]);
118+
}
119+
120+
if (prog_fd >= 0)
121+
SAFE_CLOSE(prog_fd);
122+
123+
SAFE_CLOSE(map_fd);
124+
}
125+
126+
static struct tst_test test = {
127+
.setup = setup,
128+
.test_all = run,
129+
.min_kver = "3.18",
130+
.caps = (struct tst_cap []) {
131+
TST_CAP(TST_CAP_DROP, CAP_SYS_ADMIN),
132+
{}
133+
},
134+
.bufs = (struct tst_buffers []) {
135+
{&log, .size = BUFSIZE},
136+
{&attr, .size = sizeof(*attr)},
137+
{&msg, .size = sizeof(MSG)},
138+
{}
139+
},
140+
.tags = (const struct tst_tag[]) {
141+
{"linux-git", "b799207e1e18"},
142+
{"CVE", "2018-18445"},
143+
{}
144+
}
145+
};

0 commit comments

Comments
 (0)