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

watch_test.c (3943B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* Use watch_queue API to watch for notifications.
      3 *
      4 * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved.
      5 * Written by David Howells (dhowells@redhat.com)
      6 */
      7
      8#define _GNU_SOURCE
      9#include <stdbool.h>
     10#include <stdarg.h>
     11#include <stdio.h>
     12#include <stdlib.h>
     13#include <string.h>
     14#include <signal.h>
     15#include <unistd.h>
     16#include <errno.h>
     17#include <sys/ioctl.h>
     18#include <limits.h>
     19#include <linux/watch_queue.h>
     20#include <linux/unistd.h>
     21#include <linux/keyctl.h>
     22
     23#ifndef KEYCTL_WATCH_KEY
     24#define KEYCTL_WATCH_KEY -1
     25#endif
     26#ifndef __NR_keyctl
     27#define __NR_keyctl -1
     28#endif
     29
     30#define BUF_SIZE 256
     31
     32static long keyctl_watch_key(int key, int watch_fd, int watch_id)
     33{
     34	return syscall(__NR_keyctl, KEYCTL_WATCH_KEY, key, watch_fd, watch_id);
     35}
     36
     37static const char *key_subtypes[256] = {
     38	[NOTIFY_KEY_INSTANTIATED]	= "instantiated",
     39	[NOTIFY_KEY_UPDATED]		= "updated",
     40	[NOTIFY_KEY_LINKED]		= "linked",
     41	[NOTIFY_KEY_UNLINKED]		= "unlinked",
     42	[NOTIFY_KEY_CLEARED]		= "cleared",
     43	[NOTIFY_KEY_REVOKED]		= "revoked",
     44	[NOTIFY_KEY_INVALIDATED]	= "invalidated",
     45	[NOTIFY_KEY_SETATTR]		= "setattr",
     46};
     47
     48static void saw_key_change(struct watch_notification *n, size_t len)
     49{
     50	struct key_notification *k = (struct key_notification *)n;
     51
     52	if (len != sizeof(struct key_notification)) {
     53		fprintf(stderr, "Incorrect key message length\n");
     54		return;
     55	}
     56
     57	printf("KEY %08x change=%u[%s] aux=%u\n",
     58	       k->key_id, n->subtype, key_subtypes[n->subtype], k->aux);
     59}
     60
     61/*
     62 * Consume and display events.
     63 */
     64static void consumer(int fd)
     65{
     66	unsigned char buffer[433], *p, *end;
     67	union {
     68		struct watch_notification n;
     69		unsigned char buf1[128];
     70	} n;
     71	ssize_t buf_len;
     72
     73	for (;;) {
     74		buf_len = read(fd, buffer, sizeof(buffer));
     75		if (buf_len == -1) {
     76			perror("read");
     77			exit(1);
     78		}
     79
     80		if (buf_len == 0) {
     81			printf("-- END --\n");
     82			return;
     83		}
     84
     85		if (buf_len > sizeof(buffer)) {
     86			fprintf(stderr, "Read buffer overrun: %zd\n", buf_len);
     87			return;
     88		}
     89
     90		printf("read() = %zd\n", buf_len);
     91
     92		p = buffer;
     93		end = buffer + buf_len;
     94		while (p < end) {
     95			size_t largest, len;
     96
     97			largest = end - p;
     98			if (largest > 128)
     99				largest = 128;
    100			if (largest < sizeof(struct watch_notification)) {
    101				fprintf(stderr, "Short message header: %zu\n", largest);
    102				return;
    103			}
    104			memcpy(&n, p, largest);
    105
    106			printf("NOTIFY[%03zx]: ty=%06x sy=%02x i=%08x\n",
    107			       p - buffer, n.n.type, n.n.subtype, n.n.info);
    108
    109			len = n.n.info & WATCH_INFO_LENGTH;
    110			if (len < sizeof(n.n) || len > largest) {
    111				fprintf(stderr, "Bad message length: %zu/%zu\n", len, largest);
    112				exit(1);
    113			}
    114
    115			switch (n.n.type) {
    116			case WATCH_TYPE_META:
    117				switch (n.n.subtype) {
    118				case WATCH_META_REMOVAL_NOTIFICATION:
    119					printf("REMOVAL of watchpoint %08x\n",
    120					       (n.n.info & WATCH_INFO_ID) >>
    121					       WATCH_INFO_ID__SHIFT);
    122					break;
    123				case WATCH_META_LOSS_NOTIFICATION:
    124					printf("-- LOSS --\n");
    125					break;
    126				default:
    127					printf("other meta record\n");
    128					break;
    129				}
    130				break;
    131			case WATCH_TYPE_KEY_NOTIFY:
    132				saw_key_change(&n.n, len);
    133				break;
    134			default:
    135				printf("other type\n");
    136				break;
    137			}
    138
    139			p += len;
    140		}
    141	}
    142}
    143
    144static struct watch_notification_filter filter = {
    145	.nr_filters	= 1,
    146	.filters = {
    147		[0]	= {
    148			.type			= WATCH_TYPE_KEY_NOTIFY,
    149			.subtype_filter[0]	= UINT_MAX,
    150		},
    151	},
    152};
    153
    154int main(int argc, char **argv)
    155{
    156	int pipefd[2], fd;
    157
    158	if (pipe2(pipefd, O_NOTIFICATION_PIPE) == -1) {
    159		perror("pipe2");
    160		exit(1);
    161	}
    162	fd = pipefd[0];
    163
    164	if (ioctl(fd, IOC_WATCH_QUEUE_SET_SIZE, BUF_SIZE) == -1) {
    165		perror("watch_queue(size)");
    166		exit(1);
    167	}
    168
    169	if (ioctl(fd, IOC_WATCH_QUEUE_SET_FILTER, &filter) == -1) {
    170		perror("watch_queue(filter)");
    171		exit(1);
    172	}
    173
    174	if (keyctl_watch_key(KEY_SPEC_SESSION_KEYRING, fd, 0x01) == -1) {
    175		perror("keyctl");
    176		exit(1);
    177	}
    178
    179	if (keyctl_watch_key(KEY_SPEC_USER_KEYRING, fd, 0x02) == -1) {
    180		perror("keyctl");
    181		exit(1);
    182	}
    183
    184	consumer(fd);
    185	exit(0);
    186}