1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2020 SUSE LLC <mdoucha@suse.cz>
4f08c3bdfSopenharmony_ci */
5f08c3bdfSopenharmony_ci
6f08c3bdfSopenharmony_ci/*
7f08c3bdfSopenharmony_ci * CVE-2019-8912
8f08c3bdfSopenharmony_ci *
9f08c3bdfSopenharmony_ci * Check for possible use-after-free in sockfs_setattr() on AF_ALG socket
10f08c3bdfSopenharmony_ci * closed by dup2() or dup3(). Unlike regular close(), dup*() syscalls don't
11f08c3bdfSopenharmony_ci * set sock->sk = NULL after closing the socket. Racing fchownat() against
12f08c3bdfSopenharmony_ci * dup2() may then result in sockfs_setattr() using the stale pointer and
13f08c3bdfSopenharmony_ci * writing into a block of released memory that may have been reused in the
14f08c3bdfSopenharmony_ci * mean time.
15f08c3bdfSopenharmony_ci *
16f08c3bdfSopenharmony_ci * The race window is small and it's hard to trigger a kernel crash but
17f08c3bdfSopenharmony_ci * fchownat() will return ENOENT as it should only when the bug is not
18f08c3bdfSopenharmony_ci * present. Race fixed specifically for af_alg in:
19f08c3bdfSopenharmony_ci *
20f08c3bdfSopenharmony_ci *  commit 9060cb719e61b685ec0102574e10337fa5f445ea
21f08c3bdfSopenharmony_ci *  Author: Mao Wenan <maowenan@huawei.com>
22f08c3bdfSopenharmony_ci *  Date:   Mon Feb 18 10:44:44 2019 +0800
23f08c3bdfSopenharmony_ci *
24f08c3bdfSopenharmony_ci *  net: crypto set sk to NULL when af_alg_release.
25f08c3bdfSopenharmony_ci *
26f08c3bdfSopenharmony_ci * It was observed that the same bug is present on many other
27f08c3bdfSopenharmony_ci * protocols. A more general fix is in:
28f08c3bdfSopenharmony_ci *
29f08c3bdfSopenharmony_ci *  commit ff7b11aa481f682e0e9711abfeb7d03f5cd612bf
30f08c3bdfSopenharmony_ci *  Author: Eric Biggers <ebiggers@google.com>
31f08c3bdfSopenharmony_ci *  Date:   Thu Feb 21 14:13:56 2019 -0800
32f08c3bdfSopenharmony_ci *
33f08c3bdfSopenharmony_ci *  net: socket: set sock->sk to NULL after calling proto_ops::release()
34f08c3bdfSopenharmony_ci */
35f08c3bdfSopenharmony_ci
36f08c3bdfSopenharmony_ci#include <sys/types.h>
37f08c3bdfSopenharmony_ci#include <sys/stat.h>
38f08c3bdfSopenharmony_ci#include <unistd.h>
39f08c3bdfSopenharmony_ci#include <pwd.h>
40f08c3bdfSopenharmony_ci#include "lapi/fcntl.h"
41f08c3bdfSopenharmony_ci
42f08c3bdfSopenharmony_ci#include "tst_test.h"
43f08c3bdfSopenharmony_ci#include "tst_af_alg.h"
44f08c3bdfSopenharmony_ci#include "tst_fuzzy_sync.h"
45f08c3bdfSopenharmony_ci#include "tst_taint.h"
46f08c3bdfSopenharmony_ci
47f08c3bdfSopenharmony_cistatic int fd = -1, sock = -1;
48f08c3bdfSopenharmony_cistatic int uid, gid;
49f08c3bdfSopenharmony_cistatic struct tst_fzsync_pair fzsync_pair;
50f08c3bdfSopenharmony_ci
51f08c3bdfSopenharmony_cistatic void setup(void)
52f08c3bdfSopenharmony_ci{
53f08c3bdfSopenharmony_ci	uid = getuid();
54f08c3bdfSopenharmony_ci	gid = getgid();
55f08c3bdfSopenharmony_ci
56f08c3bdfSopenharmony_ci	fd = SAFE_OPEN("tmpfile", O_RDWR | O_CREAT, 0644);
57f08c3bdfSopenharmony_ci
58f08c3bdfSopenharmony_ci	tst_fzsync_pair_init(&fzsync_pair);
59f08c3bdfSopenharmony_ci}
60f08c3bdfSopenharmony_ci
61f08c3bdfSopenharmony_cistatic void *thread_run(void *arg)
62f08c3bdfSopenharmony_ci{
63f08c3bdfSopenharmony_ci	while (tst_fzsync_run_b(&fzsync_pair)) {
64f08c3bdfSopenharmony_ci		tst_fzsync_start_race_b(&fzsync_pair);
65f08c3bdfSopenharmony_ci		dup2(fd, sock);
66f08c3bdfSopenharmony_ci		tst_fzsync_end_race_b(&fzsync_pair);
67f08c3bdfSopenharmony_ci	}
68f08c3bdfSopenharmony_ci
69f08c3bdfSopenharmony_ci	return arg;
70f08c3bdfSopenharmony_ci}
71f08c3bdfSopenharmony_ci
72f08c3bdfSopenharmony_cistatic void run(void)
73f08c3bdfSopenharmony_ci{
74f08c3bdfSopenharmony_ci	tst_fzsync_pair_reset(&fzsync_pair, thread_run);
75f08c3bdfSopenharmony_ci
76f08c3bdfSopenharmony_ci	while (tst_fzsync_run_a(&fzsync_pair)) {
77f08c3bdfSopenharmony_ci		sock = tst_alg_setup_reqfd("hash", "sha1", NULL, 0);
78f08c3bdfSopenharmony_ci		tst_fzsync_start_race_a(&fzsync_pair);
79f08c3bdfSopenharmony_ci		TEST(fchownat(sock, "", uid, gid, AT_EMPTY_PATH));
80f08c3bdfSopenharmony_ci		tst_fzsync_end_race_a(&fzsync_pair);
81f08c3bdfSopenharmony_ci		SAFE_CLOSE(sock);
82f08c3bdfSopenharmony_ci
83f08c3bdfSopenharmony_ci		if (tst_taint_check()) {
84f08c3bdfSopenharmony_ci			tst_res(TFAIL, "Kernel is vulnerable");
85f08c3bdfSopenharmony_ci			return;
86f08c3bdfSopenharmony_ci		}
87f08c3bdfSopenharmony_ci
88f08c3bdfSopenharmony_ci		if (TST_RET == -1 && TST_ERR == EBADF) {
89f08c3bdfSopenharmony_ci			tst_fzsync_pair_add_bias(&fzsync_pair, 1);
90f08c3bdfSopenharmony_ci			continue;
91f08c3bdfSopenharmony_ci		}
92f08c3bdfSopenharmony_ci
93f08c3bdfSopenharmony_ci		if (TST_RET == -1 && TST_ERR == ENOENT) {
94f08c3bdfSopenharmony_ci			tst_res(TPASS | TTERRNO,
95f08c3bdfSopenharmony_ci				"fchownat() failed successfully");
96f08c3bdfSopenharmony_ci			return;
97f08c3bdfSopenharmony_ci		}
98f08c3bdfSopenharmony_ci
99f08c3bdfSopenharmony_ci		if (TST_RET == -1) {
100f08c3bdfSopenharmony_ci			tst_brk(TBROK | TTERRNO,
101f08c3bdfSopenharmony_ci				"fchownat() failed unexpectedly");
102f08c3bdfSopenharmony_ci		}
103f08c3bdfSopenharmony_ci
104f08c3bdfSopenharmony_ci		if (TST_RET) {
105f08c3bdfSopenharmony_ci			tst_brk(TBROK | TTERRNO,
106f08c3bdfSopenharmony_ci				"Invalid fchownat() return value");
107f08c3bdfSopenharmony_ci		}
108f08c3bdfSopenharmony_ci	}
109f08c3bdfSopenharmony_ci
110f08c3bdfSopenharmony_ci	tst_res(TFAIL, "fchownat() failed to fail, kernel may be vulnerable");
111f08c3bdfSopenharmony_ci}
112f08c3bdfSopenharmony_ci
113f08c3bdfSopenharmony_cistatic void cleanup(void)
114f08c3bdfSopenharmony_ci{
115f08c3bdfSopenharmony_ci	tst_fzsync_pair_cleanup(&fzsync_pair);
116f08c3bdfSopenharmony_ci
117f08c3bdfSopenharmony_ci	if (fd >= 0)
118f08c3bdfSopenharmony_ci		SAFE_CLOSE(fd);
119f08c3bdfSopenharmony_ci}
120f08c3bdfSopenharmony_ci
121f08c3bdfSopenharmony_cistatic struct tst_test test = {
122f08c3bdfSopenharmony_ci	.needs_tmpdir = 1,
123f08c3bdfSopenharmony_ci	.test_all = run,
124f08c3bdfSopenharmony_ci	.setup = setup,
125f08c3bdfSopenharmony_ci	.cleanup = cleanup,
126f08c3bdfSopenharmony_ci	.min_kver = "4.10.0",
127f08c3bdfSopenharmony_ci	.min_cpus = 2,
128f08c3bdfSopenharmony_ci	.max_runtime = 150,
129f08c3bdfSopenharmony_ci	.taint_check = TST_TAINT_W | TST_TAINT_D,
130f08c3bdfSopenharmony_ci	.tags = (const struct tst_tag[]) {
131f08c3bdfSopenharmony_ci		{"linux-git", "ff7b11aa481f"},
132f08c3bdfSopenharmony_ci		{"linux-git", "9060cb719e61"},
133f08c3bdfSopenharmony_ci		{"CVE", "2019-8912"},
134f08c3bdfSopenharmony_ci		{}
135f08c3bdfSopenharmony_ci	}
136f08c3bdfSopenharmony_ci};
137