1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright 2018 Google LLC
4f08c3bdfSopenharmony_ci */
5f08c3bdfSopenharmony_ci
6f08c3bdfSopenharmony_ci/*
7f08c3bdfSopenharmony_ci * Regression test for commit f43f39958beb ("crypto: user - fix leaking
8f08c3bdfSopenharmony_ci * uninitialized memory to userspace"), or CVE-2018-19854; it was also a
9f08c3bdfSopenharmony_ci * re-introduction of CVE-2013-2547.  This bug caused uninitialized kernel stack
10f08c3bdfSopenharmony_ci * memory to be leaked in some string fields in the replies to CRYPTO_MSG_GETALG
11f08c3bdfSopenharmony_ci * messages over NETLINK_CRYPTO.  To try to detect the bug, this test dumps all
12f08c3bdfSopenharmony_ci * algorithms using NLM_F_DUMP mode and checks all string fields for unexpected
13f08c3bdfSopenharmony_ci * nonzero bytes.
14f08c3bdfSopenharmony_ci */
15f08c3bdfSopenharmony_ci
16f08c3bdfSopenharmony_ci#include <stdlib.h>
17f08c3bdfSopenharmony_ci
18f08c3bdfSopenharmony_ci#include "tst_test.h"
19f08c3bdfSopenharmony_ci#include "tst_crypto.h"
20f08c3bdfSopenharmony_ci#include "tst_netlink.h"
21f08c3bdfSopenharmony_ci
22f08c3bdfSopenharmony_ci/*
23f08c3bdfSopenharmony_ci * include after <sys/socket.h> (via tst_test.h), to work around dependency bug
24f08c3bdfSopenharmony_ci * in old kernel headers (https://www.spinics.net/lists/netdev/msg171764.html)
25f08c3bdfSopenharmony_ci */
26f08c3bdfSopenharmony_ci#include <linux/rtnetlink.h>
27f08c3bdfSopenharmony_ci
28f08c3bdfSopenharmony_cistatic struct tst_crypto_session ses = TST_CRYPTO_SESSION_INIT;
29f08c3bdfSopenharmony_ci
30f08c3bdfSopenharmony_cistatic void setup(void)
31f08c3bdfSopenharmony_ci{
32f08c3bdfSopenharmony_ci	tst_crypto_open(&ses);
33f08c3bdfSopenharmony_ci}
34f08c3bdfSopenharmony_ci
35f08c3bdfSopenharmony_cistatic void do_check_for_leaks(const char *name, const char *value, size_t vlen)
36f08c3bdfSopenharmony_ci{
37f08c3bdfSopenharmony_ci	size_t i;
38f08c3bdfSopenharmony_ci
39f08c3bdfSopenharmony_ci	for (i = strnlen(value, vlen); i < vlen; i++) {
40f08c3bdfSopenharmony_ci		if (value[i] != '\0')
41f08c3bdfSopenharmony_ci			tst_brk(TFAIL, "information leak in field '%s'", name);
42f08c3bdfSopenharmony_ci	}
43f08c3bdfSopenharmony_ci}
44f08c3bdfSopenharmony_ci
45f08c3bdfSopenharmony_ci#define check_for_leaks(name, field)  \
46f08c3bdfSopenharmony_ci	do_check_for_leaks(name, field, sizeof(field))
47f08c3bdfSopenharmony_ci
48f08c3bdfSopenharmony_cistatic void validate_attr(const struct rtattr *rta)
49f08c3bdfSopenharmony_ci{
50f08c3bdfSopenharmony_ci	switch (rta->rta_type) {
51f08c3bdfSopenharmony_ci	case CRYPTOCFGA_REPORT_LARVAL: {
52f08c3bdfSopenharmony_ci		const struct crypto_report_larval *p = RTA_DATA(rta);
53f08c3bdfSopenharmony_ci
54f08c3bdfSopenharmony_ci		check_for_leaks("crypto_report_larval::type", p->type);
55f08c3bdfSopenharmony_ci		break;
56f08c3bdfSopenharmony_ci	}
57f08c3bdfSopenharmony_ci	case CRYPTOCFGA_REPORT_HASH: {
58f08c3bdfSopenharmony_ci		const struct crypto_report_hash *p = RTA_DATA(rta);
59f08c3bdfSopenharmony_ci
60f08c3bdfSopenharmony_ci		check_for_leaks("crypto_report_hash::type", p->type);
61f08c3bdfSopenharmony_ci		break;
62f08c3bdfSopenharmony_ci	}
63f08c3bdfSopenharmony_ci	case CRYPTOCFGA_REPORT_BLKCIPHER: {
64f08c3bdfSopenharmony_ci		const struct crypto_report_blkcipher *p = RTA_DATA(rta);
65f08c3bdfSopenharmony_ci
66f08c3bdfSopenharmony_ci		check_for_leaks("crypto_report_blkcipher::type", p->type);
67f08c3bdfSopenharmony_ci		check_for_leaks("crypto_report_blkcipher::geniv", p->geniv);
68f08c3bdfSopenharmony_ci		break;
69f08c3bdfSopenharmony_ci	}
70f08c3bdfSopenharmony_ci	case CRYPTOCFGA_REPORT_AEAD: {
71f08c3bdfSopenharmony_ci		const struct crypto_report_aead *p = RTA_DATA(rta);
72f08c3bdfSopenharmony_ci
73f08c3bdfSopenharmony_ci		check_for_leaks("crypto_report_aead::type", p->type);
74f08c3bdfSopenharmony_ci		check_for_leaks("crypto_report_aead::geniv", p->geniv);
75f08c3bdfSopenharmony_ci		break;
76f08c3bdfSopenharmony_ci	}
77f08c3bdfSopenharmony_ci	case CRYPTOCFGA_REPORT_COMPRESS: {
78f08c3bdfSopenharmony_ci		const struct crypto_report_comp *p = RTA_DATA(rta);
79f08c3bdfSopenharmony_ci
80f08c3bdfSopenharmony_ci		check_for_leaks("crypto_report_comp::type", p->type);
81f08c3bdfSopenharmony_ci		break;
82f08c3bdfSopenharmony_ci	}
83f08c3bdfSopenharmony_ci	case CRYPTOCFGA_REPORT_RNG: {
84f08c3bdfSopenharmony_ci		const struct crypto_report_rng *p = RTA_DATA(rta);
85f08c3bdfSopenharmony_ci
86f08c3bdfSopenharmony_ci		check_for_leaks("crypto_report_rng::type", p->type);
87f08c3bdfSopenharmony_ci		break;
88f08c3bdfSopenharmony_ci	}
89f08c3bdfSopenharmony_ci	case CRYPTOCFGA_REPORT_CIPHER: {
90f08c3bdfSopenharmony_ci		const struct crypto_report_cipher *p = RTA_DATA(rta);
91f08c3bdfSopenharmony_ci
92f08c3bdfSopenharmony_ci		check_for_leaks("crypto_report_cipher::type", p->type);
93f08c3bdfSopenharmony_ci		break;
94f08c3bdfSopenharmony_ci	}
95f08c3bdfSopenharmony_ci	case CRYPTOCFGA_REPORT_AKCIPHER: {
96f08c3bdfSopenharmony_ci		const struct crypto_report_akcipher *p = RTA_DATA(rta);
97f08c3bdfSopenharmony_ci
98f08c3bdfSopenharmony_ci		check_for_leaks("crypto_report_akcipher::type", p->type);
99f08c3bdfSopenharmony_ci		break;
100f08c3bdfSopenharmony_ci	}
101f08c3bdfSopenharmony_ci	case CRYPTOCFGA_REPORT_KPP: {
102f08c3bdfSopenharmony_ci		const struct crypto_report_kpp *p = RTA_DATA(rta);
103f08c3bdfSopenharmony_ci
104f08c3bdfSopenharmony_ci		check_for_leaks("crypto_report_kpp::type", p->type);
105f08c3bdfSopenharmony_ci		break;
106f08c3bdfSopenharmony_ci	}
107f08c3bdfSopenharmony_ci	case CRYPTOCFGA_REPORT_ACOMP: {
108f08c3bdfSopenharmony_ci		const struct crypto_report_acomp *p = RTA_DATA(rta);
109f08c3bdfSopenharmony_ci
110f08c3bdfSopenharmony_ci		check_for_leaks("crypto_report_acomp::type", p->type);
111f08c3bdfSopenharmony_ci		break;
112f08c3bdfSopenharmony_ci	}
113f08c3bdfSopenharmony_ci	} /* end switch */
114f08c3bdfSopenharmony_ci}
115f08c3bdfSopenharmony_ci
116f08c3bdfSopenharmony_cistatic void validate_one_alg(const struct nlmsghdr *nh)
117f08c3bdfSopenharmony_ci{
118f08c3bdfSopenharmony_ci	const struct crypto_user_alg *alg = NLMSG_DATA(nh);
119f08c3bdfSopenharmony_ci	const struct rtattr *rta = (void *)alg + NLMSG_ALIGN(sizeof(*alg));
120f08c3bdfSopenharmony_ci	size_t remaining = NLMSG_PAYLOAD(nh, sizeof(*alg));
121f08c3bdfSopenharmony_ci
122f08c3bdfSopenharmony_ci	check_for_leaks("crypto_user_alg::cru_name", alg->cru_name);
123f08c3bdfSopenharmony_ci	check_for_leaks("crypto_user_alg::cru_driver_name",
124f08c3bdfSopenharmony_ci			alg->cru_driver_name);
125f08c3bdfSopenharmony_ci	check_for_leaks("crypto_user_alg::cru_module_name",
126f08c3bdfSopenharmony_ci			alg->cru_module_name);
127f08c3bdfSopenharmony_ci
128f08c3bdfSopenharmony_ci	while (RTA_OK(rta, remaining)) {
129f08c3bdfSopenharmony_ci		validate_attr(rta);
130f08c3bdfSopenharmony_ci		rta = RTA_NEXT(rta, remaining);
131f08c3bdfSopenharmony_ci	}
132f08c3bdfSopenharmony_ci}
133f08c3bdfSopenharmony_ci
134f08c3bdfSopenharmony_cistatic void validate_alg_list(const void *buf, size_t remaining)
135f08c3bdfSopenharmony_ci{
136f08c3bdfSopenharmony_ci	const struct nlmsghdr *nh;
137f08c3bdfSopenharmony_ci
138f08c3bdfSopenharmony_ci	for (nh = buf; NLMSG_OK(nh, remaining);
139f08c3bdfSopenharmony_ci	     nh = NLMSG_NEXT(nh, remaining)) {
140f08c3bdfSopenharmony_ci		if (nh->nlmsg_seq != ses.seq_num) {
141f08c3bdfSopenharmony_ci			tst_brk(TBROK,
142f08c3bdfSopenharmony_ci				"Message out of sequence; type=0%hx, seq_num=%u (not %u)",
143f08c3bdfSopenharmony_ci				nh->nlmsg_type, nh->nlmsg_seq, ses.seq_num);
144f08c3bdfSopenharmony_ci		}
145f08c3bdfSopenharmony_ci		if (nh->nlmsg_type == NLMSG_DONE)
146f08c3bdfSopenharmony_ci			return;
147f08c3bdfSopenharmony_ci		if (nh->nlmsg_type != CRYPTO_MSG_GETALG) {
148f08c3bdfSopenharmony_ci			tst_brk(TBROK,
149f08c3bdfSopenharmony_ci				"Unexpected message type; type=0x%hx, seq_num=%u",
150f08c3bdfSopenharmony_ci				nh->nlmsg_type, nh->nlmsg_seq);
151f08c3bdfSopenharmony_ci		}
152f08c3bdfSopenharmony_ci		validate_one_alg(nh);
153f08c3bdfSopenharmony_ci	}
154f08c3bdfSopenharmony_ci}
155f08c3bdfSopenharmony_ci
156f08c3bdfSopenharmony_cistatic void run(void)
157f08c3bdfSopenharmony_ci{
158f08c3bdfSopenharmony_ci	struct crypto_user_alg payload = { 0 };
159f08c3bdfSopenharmony_ci	struct nlmsghdr nh = {
160f08c3bdfSopenharmony_ci		.nlmsg_len = sizeof(payload),
161f08c3bdfSopenharmony_ci		.nlmsg_type = CRYPTO_MSG_GETALG,
162f08c3bdfSopenharmony_ci		.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
163f08c3bdfSopenharmony_ci		.nlmsg_seq = ++(ses.seq_num),
164f08c3bdfSopenharmony_ci		.nlmsg_pid = 0,
165f08c3bdfSopenharmony_ci	};
166f08c3bdfSopenharmony_ci	/*
167f08c3bdfSopenharmony_ci	 * Due to an apparent kernel bug, this API cannot be used incrementally,
168f08c3bdfSopenharmony_ci	 * so we just use a large recvmsg() buffer.  This is good enough since
169f08c3bdfSopenharmony_ci	 * we don't necessarily have to check every algorithm for this test to
170f08c3bdfSopenharmony_ci	 * be effective...
171f08c3bdfSopenharmony_ci	 */
172f08c3bdfSopenharmony_ci	const size_t bufsize = 1048576;
173f08c3bdfSopenharmony_ci	void *buf = SAFE_MALLOC(bufsize);
174f08c3bdfSopenharmony_ci	size_t res;
175f08c3bdfSopenharmony_ci
176f08c3bdfSopenharmony_ci	SAFE_NETLINK_SEND(ses.fd, &nh, &payload);
177f08c3bdfSopenharmony_ci
178f08c3bdfSopenharmony_ci	res = SAFE_NETLINK_RECV(ses.fd, buf, bufsize);
179f08c3bdfSopenharmony_ci
180f08c3bdfSopenharmony_ci	validate_alg_list(buf, res);
181f08c3bdfSopenharmony_ci
182f08c3bdfSopenharmony_ci	free(buf);
183f08c3bdfSopenharmony_ci	tst_res(TPASS, "No information leaks found");
184f08c3bdfSopenharmony_ci}
185f08c3bdfSopenharmony_ci
186f08c3bdfSopenharmony_cistatic void cleanup(void)
187f08c3bdfSopenharmony_ci{
188f08c3bdfSopenharmony_ci	tst_crypto_close(&ses);
189f08c3bdfSopenharmony_ci}
190f08c3bdfSopenharmony_ci
191f08c3bdfSopenharmony_cistatic struct tst_test test = {
192f08c3bdfSopenharmony_ci	.setup = setup,
193f08c3bdfSopenharmony_ci	.test_all = run,
194f08c3bdfSopenharmony_ci	.cleanup = cleanup,
195f08c3bdfSopenharmony_ci	.tags = (const struct tst_tag[]) {
196f08c3bdfSopenharmony_ci		{"linux-git", "f43f39958beb"},
197f08c3bdfSopenharmony_ci		{"CVE", "2013-2547"},
198f08c3bdfSopenharmony_ci		{"CVE", "2018-19854"},
199f08c3bdfSopenharmony_ci		{}
200f08c3bdfSopenharmony_ci	}
201f08c3bdfSopenharmony_ci};
202