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