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