cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

test_unix_oob.c (9249B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2#include <stdio.h>
      3#include <stdlib.h>
      4#include <sys/socket.h>
      5#include <arpa/inet.h>
      6#include <unistd.h>
      7#include <string.h>
      8#include <fcntl.h>
      9#include <sys/ioctl.h>
     10#include <errno.h>
     11#include <netinet/tcp.h>
     12#include <sys/un.h>
     13#include <sys/signal.h>
     14#include <sys/poll.h>
     15
     16static int pipefd[2];
     17static int signal_recvd;
     18static pid_t producer_id;
     19static char sock_name[32];
     20
     21static void sig_hand(int sn, siginfo_t *si, void *p)
     22{
     23	signal_recvd = sn;
     24}
     25
     26static int set_sig_handler(int signal)
     27{
     28	struct sigaction sa;
     29
     30	sa.sa_sigaction = sig_hand;
     31	sigemptyset(&sa.sa_mask);
     32	sa.sa_flags = SA_SIGINFO | SA_RESTART;
     33
     34	return sigaction(signal, &sa, NULL);
     35}
     36
     37static void set_filemode(int fd, int set)
     38{
     39	int flags = fcntl(fd, F_GETFL, 0);
     40
     41	if (set)
     42		flags &= ~O_NONBLOCK;
     43	else
     44		flags |= O_NONBLOCK;
     45	fcntl(fd, F_SETFL, flags);
     46}
     47
     48static void signal_producer(int fd)
     49{
     50	char cmd;
     51
     52	cmd = 'S';
     53	write(fd, &cmd, sizeof(cmd));
     54}
     55
     56static void wait_for_signal(int fd)
     57{
     58	char buf[5];
     59
     60	read(fd, buf, 5);
     61}
     62
     63static void die(int status)
     64{
     65	fflush(NULL);
     66	unlink(sock_name);
     67	kill(producer_id, SIGTERM);
     68	exit(status);
     69}
     70
     71int is_sioctatmark(int fd)
     72{
     73	int ans = -1;
     74
     75	if (ioctl(fd, SIOCATMARK, &ans, sizeof(ans)) < 0) {
     76#ifdef DEBUG
     77		perror("SIOCATMARK Failed");
     78#endif
     79	}
     80	return ans;
     81}
     82
     83void read_oob(int fd, char *c)
     84{
     85
     86	*c = ' ';
     87	if (recv(fd, c, sizeof(*c), MSG_OOB) < 0) {
     88#ifdef DEBUG
     89		perror("Reading MSG_OOB Failed");
     90#endif
     91	}
     92}
     93
     94int read_data(int pfd, char *buf, int size)
     95{
     96	int len = 0;
     97
     98	memset(buf, size, '0');
     99	len = read(pfd, buf, size);
    100#ifdef DEBUG
    101	if (len < 0)
    102		perror("read failed");
    103#endif
    104	return len;
    105}
    106
    107static void wait_for_data(int pfd, int event)
    108{
    109	struct pollfd pfds[1];
    110
    111	pfds[0].fd = pfd;
    112	pfds[0].events = event;
    113	poll(pfds, 1, -1);
    114}
    115
    116void producer(struct sockaddr_un *consumer_addr)
    117{
    118	int cfd;
    119	char buf[64];
    120	int i;
    121
    122	memset(buf, 'x', sizeof(buf));
    123	cfd = socket(AF_UNIX, SOCK_STREAM, 0);
    124
    125	wait_for_signal(pipefd[0]);
    126	if (connect(cfd, (struct sockaddr *)consumer_addr,
    127		     sizeof(struct sockaddr)) != 0) {
    128		perror("Connect failed");
    129		kill(0, SIGTERM);
    130		exit(1);
    131	}
    132
    133	for (i = 0; i < 2; i++) {
    134		/* Test 1: Test for SIGURG and OOB */
    135		wait_for_signal(pipefd[0]);
    136		memset(buf, 'x', sizeof(buf));
    137		buf[63] = '@';
    138		send(cfd, buf, sizeof(buf), MSG_OOB);
    139
    140		wait_for_signal(pipefd[0]);
    141
    142		/* Test 2: Test for OOB being overwitten */
    143		memset(buf, 'x', sizeof(buf));
    144		buf[63] = '%';
    145		send(cfd, buf, sizeof(buf), MSG_OOB);
    146
    147		memset(buf, 'x', sizeof(buf));
    148		buf[63] = '#';
    149		send(cfd, buf, sizeof(buf), MSG_OOB);
    150
    151		wait_for_signal(pipefd[0]);
    152
    153		/* Test 3: Test for SIOCATMARK */
    154		memset(buf, 'x', sizeof(buf));
    155		buf[63] = '@';
    156		send(cfd, buf, sizeof(buf), MSG_OOB);
    157
    158		memset(buf, 'x', sizeof(buf));
    159		buf[63] = '%';
    160		send(cfd, buf, sizeof(buf), MSG_OOB);
    161
    162		memset(buf, 'x', sizeof(buf));
    163		send(cfd, buf, sizeof(buf), 0);
    164
    165		wait_for_signal(pipefd[0]);
    166
    167		/* Test 4: Test for 1byte OOB msg */
    168		memset(buf, 'x', sizeof(buf));
    169		buf[0] = '@';
    170		send(cfd, buf, 1, MSG_OOB);
    171	}
    172}
    173
    174int
    175main(int argc, char **argv)
    176{
    177	int lfd, pfd;
    178	struct sockaddr_un consumer_addr, paddr;
    179	socklen_t len = sizeof(consumer_addr);
    180	char buf[1024];
    181	int on = 0;
    182	char oob;
    183	int flags;
    184	int atmark;
    185	char *tmp_file;
    186
    187	lfd = socket(AF_UNIX, SOCK_STREAM, 0);
    188	memset(&consumer_addr, 0, sizeof(consumer_addr));
    189	consumer_addr.sun_family = AF_UNIX;
    190	sprintf(sock_name, "unix_oob_%d", getpid());
    191	unlink(sock_name);
    192	strcpy(consumer_addr.sun_path, sock_name);
    193
    194	if ((bind(lfd, (struct sockaddr *)&consumer_addr,
    195		  sizeof(consumer_addr))) != 0) {
    196		perror("socket bind failed");
    197		exit(1);
    198	}
    199
    200	pipe(pipefd);
    201
    202	listen(lfd, 1);
    203
    204	producer_id = fork();
    205	if (producer_id == 0) {
    206		producer(&consumer_addr);
    207		exit(0);
    208	}
    209
    210	set_sig_handler(SIGURG);
    211	signal_producer(pipefd[1]);
    212
    213	pfd = accept(lfd, (struct sockaddr *) &paddr, &len);
    214	fcntl(pfd, F_SETOWN, getpid());
    215
    216	signal_recvd = 0;
    217	signal_producer(pipefd[1]);
    218
    219	/* Test 1:
    220	 * veriyf that SIGURG is
    221	 * delivered, 63 bytes are
    222	 * read, oob is '@', and POLLPRI works.
    223	 */
    224	wait_for_data(pfd, POLLPRI);
    225	read_oob(pfd, &oob);
    226	len = read_data(pfd, buf, 1024);
    227	if (!signal_recvd || len != 63 || oob != '@') {
    228		fprintf(stderr, "Test 1 failed sigurg %d len %d %c\n",
    229			 signal_recvd, len, oob);
    230			die(1);
    231	}
    232
    233	signal_recvd = 0;
    234	signal_producer(pipefd[1]);
    235
    236	/* Test 2:
    237	 * Verify that the first OOB is over written by
    238	 * the 2nd one and the first OOB is returned as
    239	 * part of the read, and sigurg is received.
    240	 */
    241	wait_for_data(pfd, POLLIN | POLLPRI);
    242	len = 0;
    243	while (len < 70)
    244		len = recv(pfd, buf, 1024, MSG_PEEK);
    245	len = read_data(pfd, buf, 1024);
    246	read_oob(pfd, &oob);
    247	if (!signal_recvd || len != 127 || oob != '#') {
    248		fprintf(stderr, "Test 2 failed, sigurg %d len %d OOB %c\n",
    249		signal_recvd, len, oob);
    250		die(1);
    251	}
    252
    253	signal_recvd = 0;
    254	signal_producer(pipefd[1]);
    255
    256	/* Test 3:
    257	 * verify that 2nd oob over writes
    258	 * the first one and read breaks at
    259	 * oob boundary returning 127 bytes
    260	 * and sigurg is received and atmark
    261	 * is set.
    262	 * oob is '%' and second read returns
    263	 * 64 bytes.
    264	 */
    265	len = 0;
    266	wait_for_data(pfd, POLLIN | POLLPRI);
    267	while (len < 150)
    268		len = recv(pfd, buf, 1024, MSG_PEEK);
    269	len = read_data(pfd, buf, 1024);
    270	atmark = is_sioctatmark(pfd);
    271	read_oob(pfd, &oob);
    272
    273	if (!signal_recvd || len != 127 || oob != '%' || atmark != 1) {
    274		fprintf(stderr,
    275			"Test 3 failed, sigurg %d len %d OOB %c atmark %d\n",
    276			signal_recvd, len, oob, atmark);
    277		die(1);
    278	}
    279
    280	signal_recvd = 0;
    281
    282	len = read_data(pfd, buf, 1024);
    283	if (len != 64) {
    284		fprintf(stderr, "Test 3.1 failed, sigurg %d len %d OOB %c\n",
    285			signal_recvd, len, oob);
    286		die(1);
    287	}
    288
    289	signal_recvd = 0;
    290	signal_producer(pipefd[1]);
    291
    292	/* Test 4:
    293	 * verify that a single byte
    294	 * oob message is delivered.
    295	 * set non blocking mode and
    296	 * check proper error is
    297	 * returned and sigurg is
    298	 * received and correct
    299	 * oob is read.
    300	 */
    301
    302	set_filemode(pfd, 0);
    303
    304	wait_for_data(pfd, POLLIN | POLLPRI);
    305	len = read_data(pfd, buf, 1024);
    306	if ((len == -1) && (errno == 11))
    307		len = 0;
    308
    309	read_oob(pfd, &oob);
    310
    311	if (!signal_recvd || len != 0 || oob != '@') {
    312		fprintf(stderr, "Test 4 failed, sigurg %d len %d OOB %c\n",
    313			 signal_recvd, len, oob);
    314		die(1);
    315	}
    316
    317	set_filemode(pfd, 1);
    318
    319	/* Inline Testing */
    320
    321	on = 1;
    322	if (setsockopt(pfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on))) {
    323		perror("SO_OOBINLINE");
    324		die(1);
    325	}
    326
    327	signal_recvd = 0;
    328	signal_producer(pipefd[1]);
    329
    330	/* Test 1 -- Inline:
    331	 * Check that SIGURG is
    332	 * delivered and 63 bytes are
    333	 * read and oob is '@'
    334	 */
    335
    336	wait_for_data(pfd, POLLIN | POLLPRI);
    337	len = read_data(pfd, buf, 1024);
    338
    339	if (!signal_recvd || len != 63) {
    340		fprintf(stderr, "Test 1 Inline failed, sigurg %d len %d\n",
    341			signal_recvd, len);
    342		die(1);
    343	}
    344
    345	len = read_data(pfd, buf, 1024);
    346
    347	if (len != 1) {
    348		fprintf(stderr,
    349			 "Test 1.1 Inline failed, sigurg %d len %d oob %c\n",
    350			 signal_recvd, len, oob);
    351		die(1);
    352	}
    353
    354	signal_recvd = 0;
    355	signal_producer(pipefd[1]);
    356
    357	/* Test 2 -- Inline:
    358	 * Verify that the first OOB is over written by
    359	 * the 2nd one and read breaks correctly on
    360	 * 2nd OOB boundary with the first OOB returned as
    361	 * part of the read, and sigurg is delivered and
    362	 * siocatmark returns true.
    363	 * next read returns one byte, the oob byte
    364	 * and siocatmark returns false.
    365	 */
    366	len = 0;
    367	wait_for_data(pfd, POLLIN | POLLPRI);
    368	while (len < 70)
    369		len = recv(pfd, buf, 1024, MSG_PEEK);
    370	len = read_data(pfd, buf, 1024);
    371	atmark = is_sioctatmark(pfd);
    372	if (len != 127 || atmark != 1 || !signal_recvd) {
    373		fprintf(stderr, "Test 2 Inline failed, len %d atmark %d\n",
    374			 len, atmark);
    375		die(1);
    376	}
    377
    378	len = read_data(pfd, buf, 1024);
    379	atmark = is_sioctatmark(pfd);
    380	if (len != 1 || buf[0] != '#' || atmark == 1) {
    381		fprintf(stderr, "Test 2.1 Inline failed, len %d data %c atmark %d\n",
    382			len, buf[0], atmark);
    383		die(1);
    384	}
    385
    386	signal_recvd = 0;
    387	signal_producer(pipefd[1]);
    388
    389	/* Test 3 -- Inline:
    390	 * verify that 2nd oob over writes
    391	 * the first one and read breaks at
    392	 * oob boundary returning 127 bytes
    393	 * and sigurg is received and siocatmark
    394	 * is true after the read.
    395	 * subsequent read returns 65 bytes
    396	 * because of oob which should be '%'.
    397	 */
    398	len = 0;
    399	wait_for_data(pfd, POLLIN | POLLPRI);
    400	while (len < 126)
    401		len = recv(pfd, buf, 1024, MSG_PEEK);
    402	len = read_data(pfd, buf, 1024);
    403	atmark = is_sioctatmark(pfd);
    404	if (!signal_recvd || len != 127 || !atmark) {
    405		fprintf(stderr,
    406			 "Test 3 Inline failed, sigurg %d len %d data %c\n",
    407			 signal_recvd, len, buf[0]);
    408		die(1);
    409	}
    410
    411	len = read_data(pfd, buf, 1024);
    412	atmark = is_sioctatmark(pfd);
    413	if (len != 65 || buf[0] != '%' || atmark != 0) {
    414		fprintf(stderr,
    415			 "Test 3.1 Inline failed, len %d oob %c atmark %d\n",
    416			 len, buf[0], atmark);
    417		die(1);
    418	}
    419
    420	signal_recvd = 0;
    421	signal_producer(pipefd[1]);
    422
    423	/* Test 4 -- Inline:
    424	 * verify that a single
    425	 * byte oob message is delivered
    426	 * and read returns one byte, the oob
    427	 * byte and sigurg is received
    428	 */
    429	wait_for_data(pfd, POLLIN | POLLPRI);
    430	len = read_data(pfd, buf, 1024);
    431	if (!signal_recvd || len != 1 || buf[0] != '@') {
    432		fprintf(stderr,
    433			"Test 4 Inline failed, signal %d len %d data %c\n",
    434		signal_recvd, len, buf[0]);
    435		die(1);
    436	}
    437	die(0);
    438}