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