watch_queue: Add a key/keyring notification facility

Add a key/keyring change notification facility whereby notifications about
changes in key and keyring content and attributes can be received.

Firstly, an event queue needs to be created:

	pipe2(fds, O_NOTIFICATION_PIPE);
	ioctl(fds[1], IOC_WATCH_QUEUE_SET_SIZE, 256);

then a notification can be set up to report notifications via that queue:

	struct watch_notification_filter filter = {
		.nr_filters = 1,
		.filters = {
			[0] = {
				.type = WATCH_TYPE_KEY_NOTIFY,
				.subtype_filter[0] = UINT_MAX,
			},
		},
	};
	ioctl(fds[1], IOC_WATCH_QUEUE_SET_FILTER, &filter);
	keyctl_watch_key(KEY_SPEC_SESSION_KEYRING, fds[1], 0x01);

After that, records will be placed into the queue when events occur in
which keys are changed in some way.  Records are of the following format:

	struct key_notification {
		struct watch_notification watch;
		__u32	key_id;
		__u32	aux;
	} *n;

Where:

	n->watch.type will be WATCH_TYPE_KEY_NOTIFY.

	n->watch.subtype will indicate the type of event, such as
	NOTIFY_KEY_REVOKED.

	n->watch.info & WATCH_INFO_LENGTH will indicate the length of the
	record.

	n->watch.info & WATCH_INFO_ID will be the second argument to
	keyctl_watch_key(), shifted.

	n->key will be the ID of the affected key.

	n->aux will hold subtype-dependent information, such as the key
	being linked into the keyring specified by n->key in the case of
	NOTIFY_KEY_LINKED.

Note that it is permissible for event records to be of variable length -
or, at least, the length may be dependent on the subtype.  Note also that
the queue can be shared between multiple notifications of various types.

Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: James Morris <jamorris@linux.microsoft.com>
This commit is contained in:
David Howells
2020-01-14 17:07:11 +00:00
parent 998f50407f
commit f7e47677e3
12 changed files with 269 additions and 27 deletions

View File

@@ -13,7 +13,8 @@
enum watch_notification_type {
WATCH_TYPE_META = 0, /* Special record */
WATCH_TYPE__NR = 1
WATCH_TYPE_KEY_NOTIFY = 1, /* Key change event notification */
WATCH_TYPE__NR = 2
};
enum watch_meta_notification_subtype {
@@ -75,4 +76,29 @@ struct watch_notification_removal {
__u64 id; /* Type-dependent identifier */
};
/*
* Type of key/keyring change notification.
*/
enum key_notification_subtype {
NOTIFY_KEY_INSTANTIATED = 0, /* Key was instantiated (aux is error code) */
NOTIFY_KEY_UPDATED = 1, /* Key was updated */
NOTIFY_KEY_LINKED = 2, /* Key (aux) was added to watched keyring */
NOTIFY_KEY_UNLINKED = 3, /* Key (aux) was removed from watched keyring */
NOTIFY_KEY_CLEARED = 4, /* Keyring was cleared */
NOTIFY_KEY_REVOKED = 5, /* Key was revoked */
NOTIFY_KEY_INVALIDATED = 6, /* Key was invalidated */
NOTIFY_KEY_SETATTR = 7, /* Key's attributes got changed */
};
/*
* Key/keyring notification record.
* - watch.type = WATCH_TYPE_KEY_NOTIFY
* - watch.subtype = enum key_notification_type
*/
struct key_notification {
struct watch_notification watch;
__u32 key_id; /* The key/keyring affected */
__u32 aux; /* Per-type auxiliary data */
};
#endif /* _UAPI_LINUX_WATCH_QUEUE_H */