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