public inbox for ltp@lists.linux.it
 help / color / mirror / Atom feed
From: Richard Palethorpe <rpalethorpe@suse.de>
To: Cyril Hrubis <chrubis@suse.cz>
Cc: ltp@lists.linux.it
Subject: Re: [LTP] [PATCH] Add setsockopt10 TLS ULP UAF CVE-2023-0461
Date: Fri, 13 Oct 2023 08:45:08 +0100	[thread overview]
Message-ID: <87y1g6ylc9.fsf@suse.de> (raw)
In-Reply-To: <ZSgIrcu2A5eC_OvZ@yuki>

Hello,

Cyril Hrubis <chrubis@suse.cz> writes:

> Hi!
>> +#include "tst_test.h"
>> +
>> +#ifdef HAVE_LINUX_TLS_H
>> +
>> +#include <linux/tls.h>
>> +#include "netinet/in.h"
>> +#include "netinet/tcp.h"
>> +#include "tst_checkpoint.h"
>> +#include "tst_net.h"
>> +#include "tst_safe_net.h"
>> +#include "tst_taint.h"
>> +
>> +static struct tls12_crypto_info_aes_gcm_128 opts = {
>> +	.info = {
>> +		.version = TLS_1_2_VERSION,
>> +		.cipher_type = TLS_CIPHER_AES_GCM_128,
>> +	},
>> +	.iv = { 'i', 'v' },
>> +	.key = { 'k', 'e', 'y' },
>> +	.salt = { 's', 'a', 'l', 't' },
>> +	.rec_seq = { 'r', 'e', 'c', 's' },
>> +};
>> +
>> +static struct sockaddr_in tcp0_addr, tcp1_addr;
>> +static const struct sockaddr unspec_addr = {
>> +	.sa_family = AF_UNSPEC
>> +};
>> +
>> +static int tcp0_sk, tcp1_sk, tcp2_sk, tcp3_sk;
>> +
>> +static void setup(void)
>> +{
>> +	tst_init_sockaddr_inet(&tcp0_addr, "127.0.0.1", 0x7c90);
>> +	tst_init_sockaddr_inet(&tcp1_addr, "127.0.0.1", 0x7c91);
>> +}
>> +
>> +static void cleanup(void)
>> +{
>> +	if (tcp0_sk > 0)
>> +		SAFE_CLOSE(tcp0_sk);
>> +	if (tcp1_sk > 0)
>> +		SAFE_CLOSE(tcp1_sk);
>> +	if (tcp2_sk > 0)
>> +		SAFE_CLOSE(tcp2_sk);
>> +	if (tcp3_sk > 0)
>> +		SAFE_CLOSE(tcp3_sk);
>> +}
>> +
>> +static void child(void)
>> +{
>> +	tst_res(TINFO, "child: Listen for tcp1 connection");
>> +	tcp0_sk = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0);
>> +	SAFE_BIND(tcp0_sk, (struct sockaddr *)&tcp0_addr, sizeof(tcp0_addr));
>> +	SAFE_LISTEN(tcp0_sk, 1);
>> +	TST_CHECKPOINT_WAKE(0);
>> +
>> +	tcp3_sk = SAFE_ACCEPT(tcp0_sk, NULL, 0);
>> +	TST_CHECKPOINT_WAIT(1);
>> +	SAFE_CLOSE(tcp3_sk);
>> +	SAFE_CLOSE(tcp0_sk);
>> +
>> +	tcp3_sk = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0);
>> +	TST_CHECKPOINT_WAIT(2);
>> +
>> +	tst_res(TINFO, "child: connect for tcp2 connection");
>> +	TEST(connect(tcp3_sk, (struct sockaddr *)&tcp1_addr, sizeof(tcp1_addr)));
>> +
>> +	if (TST_RET == -1) {
>> +		tst_res(TINFO | TTERRNO, "child: could not connect to tcp1");
>> +		return;
>> +	}
>> +
>> +	TST_CHECKPOINT_WAIT(3);
>> +}
>> +
>> +static void run(void)
>> +{
>> +	const pid_t child_pid = SAFE_FORK();
>> +
>> +	if (child_pid == 0) {
>> +		child();
>> +		return;
>> +	}
>> +
>> +	tcp1_sk = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0);
>> +	TST_CHECKPOINT_WAIT(0);
>> +
>> +	tst_res(TINFO, "parent: Connect for tcp0 connection");
>> +	SAFE_CONNECT(tcp1_sk, (struct sockaddr *)&tcp0_addr, sizeof(tcp0_addr));
>> +	TEST(setsockopt(tcp1_sk, SOL_TCP, TCP_ULP, "tls", 3));
>> +
>> +	if (TST_RET == -1 && TST_ERR == ENOENT)
>> +		tst_brk(TCONF | TTERRNO, "parent: setsockopt failed: The TLS module is probably not loaded");
>
> Should we set .needs_drivers for the test so that it only attempts to
> run either if TLS is compiled in or could be modprobed as a module?

Yes if it worked :-D, although I would still want to keep the above check. I
tried it and noticed a number of problems.

On NixOS:

$ ./setsockopt10
tst_kconfig.c:87: TINFO: Parsing kernel config '/proc/config.gz'
tst_kernel.c:110: TWARN: expected file /lib/modules/6.5.5/modules.dep does not exist or not a file
tst_kernel.c:110: TWARN: expected file /lib/modules/6.5.5/modules.builtin does not exist or not a file
tst_test.c:1195: TCONF: tls driver not available
$ lsmod | grep tls
tls                   151552  0

We have a special switch for Android which disables the check, but it is
not just Android. Granted NixOS is really wierd by desktop standards,
but we have ALP and embedded systems to think about.

AFAICT the test library does not do a modprobe if the driver is
missing. Some tests (e.g. zram, CAN) do that and then claim to require
modprobe. This is not good, those tests do not need modprobe if the
module is loaded or compiled in.

Perhaps if the check in tst_kernel fails for any reason we could just do
a modprobe (or use the configured kernel usermode helper if it is
set). If that fails we just carry on, like for Android. That's a
seperate patch though IMO. Once we have a solution for that, this test
can have needs_drivers added.

>
>> +	else if (TST_RET == -1)
>> +		tst_brk(TBROK | TTERRNO, "parent: setsockopt failed");
>> +
>> +	SAFE_SETSOCKOPT(tcp1_sk, SOL_TLS, TLS_TX, &opts, sizeof(opts));
>> +	TST_CHECKPOINT_WAKE(1);
>> +
>> +	tst_res(TINFO, "parent: Disconnect by setting unspec address");
>> +	SAFE_CONNECT(tcp1_sk, &unspec_addr, sizeof(unspec_addr));
>> +	SAFE_BIND(tcp1_sk, (struct sockaddr *)&tcp1_addr, sizeof(tcp1_addr));
>> +
>> +	TEST(listen(tcp1_sk, 1));
>> +
>> +	if (TST_RET == -1) {
>> +		if (TST_ERR == EINVAL)
>> +			tst_res(TPASS | TTERRNO, "parent: Can't listen on disconnected TLS socket");
>> +		else
>> + tst_res(TCONF | TTERRNO, "parent: Can't listen on disconnected TLS
>> socket, but the errno is not EINVAL as expected");
>> +
>> +		TST_CHECKPOINT_WAKE(2);
>> +		goto out;
>> +	}
>> +
>> +	tst_res(TINFO, "parent: Can listen on disconnected TLS socket");
>> +	TST_CHECKPOINT_WAKE(2);
>> +
>> +	tcp2_sk = SAFE_ACCEPT(tcp1_sk, NULL, 0);
>> +	SAFE_CLOSE(tcp2_sk);
>> +
>> + tst_res(TINFO, "parent: Attempting double free, because we set
>> cipher options this should result in an crash");
>> +	SAFE_CLOSE(tcp1_sk);
>> +
>> +	TST_CHECKPOINT_WAKE(3);
>> +	usleep(0);
>
> Did you forget this here?

It's supposed to give the kernel chance to propagate the taint or
panic. Which stops it from printing there was no kernel taint in
parallel with the kernel splat. It appears to work on my test system.

>
>> +	if (tst_taint_check())
>> +		tst_res(TFAIL, "Kernel is tainted");
>> +	else
>> +		tst_res(TCONF, "No kernel taint or crash, maybe the kernel can clone the TLS-ULP context now?");
>
> If you set up .taint_check this is going to be redundant since we print
> TFAIL in the test library in that case.

In that case we can unconditionally do TCONF and it'll be overridden by
fail and the resulting panic. Or it will be prevented by the panic.

>
>> +out:
>> +	tst_reap_children();
>> +}
>> +
>> +static struct tst_test test = {
>> +	.setup = setup,
>> +	.cleanup = cleanup,
>> +	.test_all = run,
>> +	.forks_child = 1,
>> +	.needs_checkpoints = 1,
>> +	.taint_check = TST_TAINT_W | TST_TAINT_D,
>> +	.needs_kconfigs = (const char *[]) {
>> +		"CONFIG_TLS",
>> +		NULL
>> +	},
>> +	.tags = (const struct tst_tag[]) {
>> +		{"linux-git", "2c02d41d71f90"},
>> +		{"CVE", "2023-0461"},
>> +		{}
>> +	}
>> +};
>> +
>> +#else
>> +
>> +TST_TEST_TCONF("linux/tls.h missing, we assume your system is too old");
>> +
>> +#endif
>> -- 
>> 2.40.1
>> 
>> 
>> -- 
>> Mailing list info: https://lists.linux.it/listinfo/ltp


-- 
Thank you,
Richard.

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

  reply	other threads:[~2023-10-13  8:32 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-10-12 10:39 [LTP] [PATCH] Add setsockopt10 TLS ULP UAF CVE-2023-0461 Richard Palethorpe via ltp
2023-10-12 14:54 ` Cyril Hrubis
2023-10-13  7:45   ` Richard Palethorpe [this message]
2023-10-13  9:29     ` Cyril Hrubis
2023-10-13  9:37       ` Richard Palethorpe
2023-10-13 12:13         ` Petr Vorel
2023-10-16  7:23           ` Richard Palethorpe
2023-10-16 19:57             ` Petr Vorel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87y1g6ylc9.fsf@suse.de \
    --to=rpalethorpe@suse.de \
    --cc=chrubis@suse.cz \
    --cc=ltp@lists.linux.it \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox