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.
Unified · Split
| @@ -1026,6 +1026,63 @@ The keyctl syscall functions are: · 1025 unmodified lines | ||
| 1026 | 1026 | written into the output buffer. Verification returns 0 on success. |
| 1027 | 1027 | |
| 1028 | 1028 | |
| 1029 | + * Watch a key or keyring for changes:: | |
| 1030 | + | |
| 1031 | + long keyctl(KEYCTL_WATCH_KEY, key_serial_t key, int queue_fd, | |
| 1032 | + const struct watch_notification_filter *filter); | |
| 1033 | + | |
| 1034 | + This will set or remove a watch for changes on the specified key or | |
| 1035 | + keyring. | |
| 1036 | + | |
| 1037 | + "key" is the ID of the key to be watched. | |
| 1038 | + | |
| 1039 | + "queue_fd" is a file descriptor referring to an open "/dev/watch_queue" | |
| 1040 | + which manages the buffer into which notifications will be delivered. | |
| 1041 | + | |
| 1042 | + "filter" is either NULL to remove a watch or a filter specification to | |
| 1043 | + indicate what events are required from the key. | |
| 1044 | + | |
| 1045 | + See Documentation/watch_queue.rst for more information. | |
| 1046 | + | |
| 1047 | + Note that only one watch may be emplaced for any particular { key, | |
| 1048 | + queue_fd } combination. | |
| 1049 | + | |
| 1050 | + Notification records look like:: | |
| 1051 | + | |
| 1052 | + struct key_notification { | |
| 1053 | + struct watch_notification watch; | |
| 1054 | + __u32 key_id; | |
| 1055 | + __u32 aux; | |
| 1056 | + }; | |
| 1057 | + | |
| 1058 | + In this, watch::type will be "WATCH_TYPE_KEY_NOTIFY" and subtype will be | |
| 1059 | + one of:: | |
| 1060 | + | |
| 1061 | + NOTIFY_KEY_INSTANTIATED | |
| 1062 | + NOTIFY_KEY_UPDATED | |
| 1063 | + NOTIFY_KEY_LINKED | |
| 1064 | + NOTIFY_KEY_UNLINKED | |
| 1065 | + NOTIFY_KEY_CLEARED | |
| 1066 | + NOTIFY_KEY_REVOKED | |
| 1067 | + NOTIFY_KEY_INVALIDATED | |
| 1068 | + NOTIFY_KEY_SETATTR | |
| 1069 | + | |
| 1070 | + Where these indicate a key being instantiated/rejected, updated, a link | |
| 1071 | + being made in a keyring, a link being removed from a keyring, a keyring | |
| 1072 | + being cleared, a key being revoked, a key being invalidated or a key | |
| 1073 | + having one of its attributes changed (user, group, perm, timeout, | |
| 1074 | + restriction). | |
| 1075 | + | |
| 1076 | + If a watched key is deleted, a basic watch_notification will be issued | |
| 1077 | + with "type" set to WATCH_TYPE_META and "subtype" set to | |
| 1078 | + watch_meta_removal_notification. The watchpoint ID will be set in the | |
| 1079 | + "info" field. | |
| 1080 | + | |
| 1081 | + This needs to be configured by enabling: | |
| 1082 | + | |
| 1083 | + "Provide key/keyring change notifications" (KEY_NOTIFICATIONS) | |
| 1084 | + | |
| 1085 | + | |
| 1029 | 1086 | Kernel Services |
| 1030 | 1087 | =============== |
| 1031 | 1088 | |
| @@ -176,6 +176,9 @@ struct key { · 175 unmodified lines | ||
| 176 | 176 | struct list_head graveyard_link; |
| 177 | 177 | struct rb_node serial_node; |
| 178 | 178 | }; |
| 179 | +#ifdef CONFIG_KEY_NOTIFICATIONS | |
| 180 | + struct watch_list *watchers; /* Entities watching this key for changes */ | |
| 181 | +#endif | |
| 179 | 182 | struct rw_semaphore sem; /* change vs change sem */ |
| 180 | 183 | struct key_user *user; /* owner of this key */ |
| 181 | 184 | void *security; /* security data for this key */ |
| @@ -69,6 +69,7 @@ · 68 unmodified lines | ||
| 69 | 69 | #define KEYCTL_RESTRICT_KEYRING 29 /* Restrict keys allowed to link to a keyring */ |
| 70 | 70 | #define KEYCTL_MOVE 30 /* Move keys between keyrings */ |
| 71 | 71 | #define KEYCTL_CAPABILITIES 31 /* Find capabilities of keyrings subsystem */ |
| 72 | +#define KEYCTL_WATCH_KEY 32 /* Watch a key or ring of keys for changes */ | |
| 72 | 73 | |
| 73 | 74 | /* keyctl structures */ |
| 74 | 75 | struct keyctl_dh_params { |
| @@ -130,5 +131,6 @@ struct keyctl_pkey_params { · 55 unmodified lines | ||
| 130 | 131 | #define KEYCTL_CAPS0_MOVE 0x80 /* KEYCTL_MOVE supported */ |
| 131 | 132 | #define KEYCTL_CAPS1_NS_KEYRING_NAME 0x01 /* Keyring names are per-user_namespace */ |
| 132 | 133 | #define KEYCTL_CAPS1_NS_KEY_TAG 0x02 /* Key indexing can include a namespace tag */ |
| 134 | +#define KEYCTL_CAPS1_NOTIFICATIONS 0x04 /* Keys generate watchable notifications */ | |
| 133 | 135 | |
| 134 | 136 | #endif /* _LINUX_KEYCTL_H */ |
| @@ -13,7 +13,8 @@ · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | enum watch_notification_type { |
| 15 | 15 | WATCH_TYPE_META = 0, /* Special record */ |
| 16 | − WATCH_TYPE__NR = 1 | |
| 16 | + WATCH_TYPE_KEY_NOTIFY = 1, /* Key change event notification */ | |
| 17 | + WATCH_TYPE__NR = 2 | |
| 17 | 18 | }; |
| 18 | 19 | |
| 19 | 20 | enum watch_meta_notification_subtype { |
| @@ -75,4 +76,29 @@ struct watch_notification_removal { · 55 unmodified lines | ||
| 75 | 76 | __u64 id; /* Type-dependent identifier */ |
| 76 | 77 | }; |
| 77 | 78 | |
| 79 | +/* | |
| 80 | + * Type of key/keyring change notification. | |
| 81 | + */ | |
| 82 | +enum key_notification_subtype { | |
| 83 | + NOTIFY_KEY_INSTANTIATED = 0, /* Key was instantiated (aux is error code) */ | |
| 84 | + NOTIFY_KEY_UPDATED = 1, /* Key was updated */ | |
| 85 | + NOTIFY_KEY_LINKED = 2, /* Key (aux) was added to watched keyring */ | |
| 86 | + NOTIFY_KEY_UNLINKED = 3, /* Key (aux) was removed from watched keyring */ | |
| 87 | + NOTIFY_KEY_CLEARED = 4, /* Keyring was cleared */ | |
| 88 | + NOTIFY_KEY_REVOKED = 5, /* Key was revoked */ | |
| 89 | + NOTIFY_KEY_INVALIDATED = 6, /* Key was invalidated */ | |
| 90 | + NOTIFY_KEY_SETATTR = 7, /* Key's attributes got changed */ | |
| 91 | +}; | |
| 92 | + | |
| 93 | +/* | |
| 94 | + * Key/keyring notification record. | |
| 95 | + * - watch.type = WATCH_TYPE_KEY_NOTIFY | |
| 96 | + * - watch.subtype = enum key_notification_type | |
| 97 | + */ | |
| 98 | +struct key_notification { | |
| 99 | + struct watch_notification watch; | |
| 100 | + __u32 key_id; /* The key/keyring affected */ | |
| 101 | + __u32 aux; /* Per-type auxiliary data */ | |
| 102 | +}; | |
| 103 | + | |
| 78 | 104 | #endif /* _UAPI_LINUX_WATCH_QUEUE_H */ |
| @@ -116,3 +116,12 @@ config KEY_DH_OPERATIONS · 115 unmodified lines | ||
| 116 | 116 | in the kernel. |
| 117 | 117 | |
| 118 | 118 | If you are unsure as to whether this is required, answer N. |
| 119 | + | |
| 120 | +config KEY_NOTIFICATIONS | |
| 121 | + bool "Provide key/keyring change notifications" | |
| 122 | + depends on KEYS && WATCH_QUEUE | |
| 123 | + help | |
| 124 | + This option provides support for getting change notifications on keys | |
| 125 | + and keyrings on which the caller has View permission. This makes use | |
| 126 | + of the /dev/watch_queue misc device to handle the notification | |
| 127 | + buffer and provides KEYCTL_WATCH_KEY to enable/disable watches. | |
| @@ -156,6 +156,9 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option, · 155 unmodified lines | ||
| 156 | 156 | case KEYCTL_CAPABILITIES: |
| 157 | 157 | return keyctl_capabilities(compat_ptr(arg2), arg3); |
| 158 | 158 | |
| 159 | + case KEYCTL_WATCH_KEY: | |
| 160 | + return keyctl_watch_key(arg2, arg3, arg4); | |
| 161 | + | |
| 159 | 162 | default: |
| 160 | 163 | return -EOPNOTSUPP; |
| 161 | 164 | } |
| @@ -131,6 +131,11 @@ static noinline void key_gc_unused_keys(struct list_head *keys) · 130 unmodified lines | ||
| 131 | 131 | kdebug("- %u", key->serial); |
| 132 | 132 | key_check(key); |
| 133 | 133 | |
| 134 | +#ifdef CONFIG_KEY_NOTIFICATIONS | |
| 135 | + remove_watch_list(key->watchers, key->serial); | |
| 136 | + key->watchers = NULL; | |
| 137 | +#endif | |
| 138 | + | |
| 134 | 139 | /* Throw away the key data if the key is instantiated */ |
| 135 | 140 | if (state == KEY_IS_POSITIVE && key->type->destroy) |
| 136 | 141 | key->type->destroy(key); |
| @@ -15,6 +15,7 @@ · 14 unmodified lines | ||
| 15 | 15 | #include <linux/task_work.h> |
| 16 | 16 | #include <linux/keyctl.h> |
| 17 | 17 | #include <linux/refcount.h> |
| 18 | +#include <linux/watch_queue.h> | |
| 18 | 19 | #include <linux/compat.h> |
| 19 | 20 | #include <linux/mm.h> |
| 20 | 21 | #include <linux/vmalloc.h> |
| @@ -99,7 +100,8 @@ extern int __key_link_begin(struct key *keyring, · 78 unmodified lines | ||
| 99 | 100 | const struct keyring_index_key *index_key, |
| 100 | 101 | struct assoc_array_edit **_edit); |
| 101 | 102 | extern int __key_link_check_live_key(struct key *keyring, struct key *key); |
| 102 | −extern void __key_link(struct key *key, struct assoc_array_edit **_edit); | |
| 103 | +extern void __key_link(struct key *keyring, struct key *key, | |
| 104 | + struct assoc_array_edit **_edit); | |
| 103 | 105 | extern void __key_link_end(struct key *keyring, |
| 104 | 106 | const struct keyring_index_key *index_key, |
| 105 | 107 | struct assoc_array_edit *edit); |
| @@ -183,6 +185,23 @@ extern int key_task_permission(const key_ref_t key_ref, · 77 unmodified lines | ||
| 183 | 185 | const struct cred *cred, |
| 184 | 186 | key_perm_t perm); |
| 185 | 187 | |
| 188 | +static inline void notify_key(struct key *key, | |
| 189 | + enum key_notification_subtype subtype, u32 aux) | |
| 190 | +{ | |
| 191 | +#ifdef CONFIG_KEY_NOTIFICATIONS | |
| 192 | + struct key_notification n = { | |
| 193 | + .watch.type = WATCH_TYPE_KEY_NOTIFY, | |
| 194 | + .watch.subtype = subtype, | |
| 195 | + .watch.info = watch_sizeof(n), | |
| 196 | + .key_id = key_serial(key), | |
| 197 | + .aux = aux, | |
| 198 | + }; | |
| 199 | + | |
| 200 | + post_watch_notification(key->watchers, &n.watch, current_cred(), | |
| 201 | + n.key_id); | |
| 202 | +#endif | |
| 203 | +} | |
| 204 | + | |
| 186 | 205 | /* |
| 187 | 206 | * Check to see whether permission is granted to use a key in the desired way. |
| 188 | 207 | */ |
| @@ -333,6 +352,15 @@ static inline long keyctl_pkey_e_d_s(int op, · 144 unmodified lines | ||
| 333 | 352 | |
| 334 | 353 | extern long keyctl_capabilities(unsigned char __user *_buffer, size_t buflen); |
| 335 | 354 | |
| 355 | +#ifdef CONFIG_KEY_NOTIFICATIONS | |
| 356 | +extern long keyctl_watch_key(key_serial_t, int, int); | |
| 357 | +#else | |
| 358 | +static inline long keyctl_watch_key(key_serial_t key_id, int watch_fd, int watch_id) | |
| 359 | +{ | |
| 360 | + return -EOPNOTSUPP; | |
| 361 | +} | |
| 362 | +#endif | |
| 363 | + | |
| 336 | 364 | /* |
| 337 | 365 | * Debugging key validation |
| 338 | 366 | */ |
| @@ -444,6 +444,7 @@ static int __key_instantiate_and_link(struct key *key, · 443 unmodified lines | ||
| 444 | 444 | /* mark the key as being instantiated */ |
| 445 | 445 | atomic_inc(&key->user->nikeys); |
| 446 | 446 | mark_key_instantiated(key, 0); |
| 447 | + notify_key(key, NOTIFY_KEY_INSTANTIATED, 0); | |
| 447 | 448 | |
| 448 | 449 | if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) |
| 449 | 450 | awaken = 1; |
| @@ -453,7 +454,7 @@ static int __key_instantiate_and_link(struct key *key, · 3 unmodified lines | ||
| 453 | 454 | if (test_bit(KEY_FLAG_KEEP, &keyring->flags)) |
| 454 | 455 | set_bit(KEY_FLAG_KEEP, &key->flags); |
| 455 | 456 | |
| 456 | − __key_link(key, _edit); | |
| 457 | + __key_link(keyring, key, _edit); | |
| 457 | 458 | } |
| 458 | 459 | |
| 459 | 460 | /* disable the authorisation key */ |
| @@ -601,6 +602,7 @@ int key_reject_and_link(struct key *key, · 141 unmodified lines | ||
| 601 | 602 | /* mark the key as being negatively instantiated */ |
| 602 | 603 | atomic_inc(&key->user->nikeys); |
| 603 | 604 | mark_key_instantiated(key, -error); |
| 605 | + notify_key(key, NOTIFY_KEY_INSTANTIATED, -error); | |
| 604 | 606 | key->expiry = ktime_get_real_seconds() + timeout; |
| 605 | 607 | key_schedule_gc(key->expiry + key_gc_delay); |
| 606 | 608 | |
| @@ -611,7 +613,7 @@ int key_reject_and_link(struct key *key, · 4 unmodified lines | ||
| 611 | 613 | |
| 612 | 614 | /* and link it into the destination keyring */ |
| 613 | 615 | if (keyring && link_ret == 0) |
| 614 | − __key_link(key, &edit); | |
| 616 | + __key_link(keyring, key, &edit); | |
| 615 | 617 | |
| 616 | 618 | /* disable the authorisation key */ |
| 617 | 619 | if (authkey) |
| @@ -764,9 +766,11 @@ static inline key_ref_t __key_update(key_ref_t key_ref, · 146 unmodified lines | ||
| 764 | 766 | down_write(&key->sem); |
| 765 | 767 | |
| 766 | 768 | ret = key->type->update(key, prep); |
| 767 | − if (ret == 0) | |
| 769 | + if (ret == 0) { | |
| 768 | 770 | /* Updating a negative key positively instantiates it */ |
| 769 | 771 | mark_key_instantiated(key, 0); |
| 772 | + notify_key(key, NOTIFY_KEY_UPDATED, 0); | |
| 773 | + } | |
| 770 | 774 | |
| 771 | 775 | up_write(&key->sem); |
| 772 | 776 | |
| @@ -1023,9 +1027,11 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) · 250 unmodified lines | ||
| 1023 | 1027 | down_write(&key->sem); |
| 1024 | 1028 | |
| 1025 | 1029 | ret = key->type->update(key, &prep); |
| 1026 | − if (ret == 0) | |
| 1030 | + if (ret == 0) { | |
| 1027 | 1031 | /* Updating a negative key positively instantiates it */ |
| 1028 | 1032 | mark_key_instantiated(key, 0); |
| 1033 | + notify_key(key, NOTIFY_KEY_UPDATED, 0); | |
| 1034 | + } | |
| 1029 | 1035 | |
| 1030 | 1036 | up_write(&key->sem); |
| 1031 | 1037 | |
| @@ -1057,15 +1063,17 @@ void key_revoke(struct key *key) · 25 unmodified lines | ||
| 1057 | 1063 | * instantiated |
| 1058 | 1064 | */ |
| 1059 | 1065 | down_write_nested(&key->sem, 1); |
| 1060 | − if (!test_and_set_bit(KEY_FLAG_REVOKED, &key->flags) && | |
| 1061 | − key->type->revoke) | |
| 1062 | − key->type->revoke(key); | |
| 1063 | − | |
| 1064 | − /* set the death time to no more than the expiry time */ | |
| 1065 | − time = ktime_get_real_seconds(); | |
| 1066 | − if (key->revoked_at == 0 || key->revoked_at > time) { | |
| 1067 | − key->revoked_at = time; | |
| 1068 | − key_schedule_gc(key->revoked_at + key_gc_delay); | |
| 1066 | + if (!test_and_set_bit(KEY_FLAG_REVOKED, &key->flags)) { | |
| 1067 | + notify_key(key, NOTIFY_KEY_REVOKED, 0); | |
| 1068 | + if (key->type->revoke) | |
| 1069 | + key->type->revoke(key); | |
| 1070 | + | |
| 1071 | + /* set the death time to no more than the expiry time */ | |
| 1072 | + time = ktime_get_real_seconds(); | |
| 1073 | + if (key->revoked_at == 0 || key->revoked_at > time) { | |
| 1074 | + key->revoked_at = time; | |
| 1075 | + key_schedule_gc(key->revoked_at + key_gc_delay); | |
| 1076 | + } | |
| 1069 | 1077 | } |
| 1070 | 1078 | |
| 1071 | 1079 | up_write(&key->sem); |
| @@ -1087,8 +1095,10 @@ void key_invalidate(struct key *key) · 15 unmodified lines | ||
| 1087 | 1095 | |
| 1088 | 1096 | if (!test_bit(KEY_FLAG_INVALIDATED, &key->flags)) { |
| 1089 | 1097 | down_write_nested(&key->sem, 1); |
| 1090 | − if (!test_and_set_bit(KEY_FLAG_INVALIDATED, &key->flags)) | |
| 1098 | + if (!test_and_set_bit(KEY_FLAG_INVALIDATED, &key->flags)) { | |
| 1099 | + notify_key(key, NOTIFY_KEY_INVALIDATED, 0); | |
| 1091 | 1100 | key_schedule_gc_links(); |
| 1101 | + } | |
| 1092 | 1102 | up_write(&key->sem); |
| 1093 | 1103 | } |
| 1094 | 1104 | } |
| @@ -37,7 +37,9 @@ static const unsigned char keyrings_capabilities[2] = { · 36 unmodified lines | ||
| 37 | 37 | KEYCTL_CAPS0_MOVE |
| 38 | 38 | ), |
| 39 | 39 | [1] = (KEYCTL_CAPS1_NS_KEYRING_NAME | |
| 40 | − KEYCTL_CAPS1_NS_KEY_TAG), | |
| 40 | + KEYCTL_CAPS1_NS_KEY_TAG | | |
| 41 | + (IS_ENABLED(CONFIG_KEY_NOTIFICATIONS) ? KEYCTL_CAPS1_NOTIFICATIONS : 0) | |
| 42 | + ), | |
| 41 | 43 | }; |
| 42 | 44 | |
| 43 | 45 | static int key_get_type_from_user(char *type, |
| @@ -1039,6 +1041,7 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group) · 995 unmodified lines | ||
| 1039 | 1041 | if (group != (gid_t) -1) |
| 1040 | 1042 | key->gid = gid; |
| 1041 | 1043 | |
| 1044 | + notify_key(key, NOTIFY_KEY_SETATTR, 0); | |
| 1042 | 1045 | ret = 0; |
| 1043 | 1046 | |
| 1044 | 1047 | error_put: |
| @@ -1089,6 +1092,7 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm) · 44 unmodified lines | ||
| 1089 | 1092 | /* if we're not the sysadmin, we can only change a key that we own */ |
| 1090 | 1093 | if (capable(CAP_SYS_ADMIN) || uid_eq(key->uid, current_fsuid())) { |
| 1091 | 1094 | key->perm = perm; |
| 1095 | + notify_key(key, NOTIFY_KEY_SETATTR, 0); | |
| 1092 | 1096 | ret = 0; |
| 1093 | 1097 | } |
| 1094 | 1098 | |
| @@ -1480,10 +1484,12 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout) · 385 unmodified lines | ||
| 1480 | 1484 | okay: |
| 1481 | 1485 | key = key_ref_to_ptr(key_ref); |
| 1482 | 1486 | ret = 0; |
| 1483 | − if (test_bit(KEY_FLAG_KEEP, &key->flags)) | |
| 1487 | + if (test_bit(KEY_FLAG_KEEP, &key->flags)) { | |
| 1484 | 1488 | ret = -EPERM; |
| 1485 | − else | |
| 1489 | + } else { | |
| 1486 | 1490 | key_set_timeout(key, timeout); |
| 1491 | + notify_key(key, NOTIFY_KEY_SETATTR, 0); | |
| 1492 | + } | |
| 1487 | 1493 | key_put(key); |
| 1488 | 1494 | |
| 1489 | 1495 | error: |
| @@ -1757,6 +1763,90 @@ error: · 267 unmodified lines | ||
| 1757 | 1763 | return ret; |
| 1758 | 1764 | } |
| 1759 | 1765 | |
| 1766 | +#ifdef CONFIG_KEY_NOTIFICATIONS | |
| 1767 | +/* | |
| 1768 | + * Watch for changes to a key. | |
| 1769 | + * | |
| 1770 | + * The caller must have View permission to watch a key or keyring. | |
| 1771 | + */ | |
| 1772 | +long keyctl_watch_key(key_serial_t id, int watch_queue_fd, int watch_id) | |
| 1773 | +{ | |
| 1774 | + struct watch_queue *wqueue; | |
| 1775 | + struct watch_list *wlist = NULL; | |
| 1776 | + struct watch *watch = NULL; | |
| 1777 | + struct key *key; | |
| 1778 | + key_ref_t key_ref; | |
| 1779 | + long ret; | |
| 1780 | + | |
| 1781 | + if (watch_id < -1 || watch_id > 0xff) | |
| 1782 | + return -EINVAL; | |
| 1783 | + | |
| 1784 | + key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_NEED_VIEW); | |
| 1785 | + if (IS_ERR(key_ref)) | |
| 1786 | + return PTR_ERR(key_ref); | |
| 1787 | + key = key_ref_to_ptr(key_ref); | |
| 1788 | + | |
| 1789 | + wqueue = get_watch_queue(watch_queue_fd); | |
| 1790 | + if (IS_ERR(wqueue)) { | |
| 1791 | + ret = PTR_ERR(wqueue); | |
| 1792 | + goto err_key; | |
| 1793 | + } | |
| 1794 | + | |
| 1795 | + if (watch_id >= 0) { | |
| 1796 | + ret = -ENOMEM; | |
| 1797 | + if (!key->watchers) { | |
| 1798 | + wlist = kzalloc(sizeof(*wlist), GFP_KERNEL); | |
| 1799 | + if (!wlist) | |
| 1800 | + goto err_wqueue; | |
| 1801 | + init_watch_list(wlist, NULL); | |
| 1802 | + } | |
| 1803 | + | |
| 1804 | + watch = kzalloc(sizeof(*watch), GFP_KERNEL); | |
| 1805 | + if (!watch) | |
| 1806 | + goto err_wlist; | |
| 1807 | + | |
| 1808 | + init_watch(watch, wqueue); | |
| 1809 | + watch->id = key->serial; | |
| 1810 | + watch->info_id = (u32)watch_id << WATCH_INFO_ID__SHIFT; | |
| 1811 | + | |
| 1812 | + ret = security_watch_key(key); | |
| 1813 | + if (ret < 0) | |
| 1814 | + goto err_watch; | |
| 1815 | + | |
| 1816 | + down_write(&key->sem); | |
| 1817 | + if (!key->watchers) { | |
| 1818 | + key->watchers = wlist; | |
| 1819 | + wlist = NULL; | |
| 1820 | + } | |
| 1821 | + | |
| 1822 | + ret = add_watch_to_object(watch, key->watchers); | |
| 1823 | + up_write(&key->sem); | |
| 1824 | + | |
| 1825 | + if (ret == 0) | |
| 1826 | + watch = NULL; | |
| 1827 | + } else { | |
| 1828 | + ret = -EBADSLT; | |
| 1829 | + if (key->watchers) { | |
| 1830 | + down_write(&key->sem); | |
| 1831 | + ret = remove_watch_from_object(key->watchers, | |
| 1832 | + wqueue, key_serial(key), | |
| 1833 | + false); | |
| 1834 | + up_write(&key->sem); | |
| 1835 | + } | |
| 1836 | + } | |
| 1837 | + | |
| 1838 | +err_watch: | |
| 1839 | + kfree(watch); | |
| 1840 | +err_wlist: | |
| 1841 | + kfree(wlist); | |
| 1842 | +err_wqueue: | |
| 1843 | + put_watch_queue(wqueue); | |
| 1844 | +err_key: | |
| 1845 | + key_put(key); | |
| 1846 | + return ret; | |
| 1847 | +} | |
| 1848 | +#endif /* CONFIG_KEY_NOTIFICATIONS */ | |
| 1849 | + | |
| 1760 | 1850 | /* |
| 1761 | 1851 | * Get keyrings subsystem capabilities. |
| 1762 | 1852 | */ |
| @@ -1926,6 +2016,9 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, · 163 unmodified lines | ||
| 1926 | 2016 | case KEYCTL_CAPABILITIES: |
| 1927 | 2017 | return keyctl_capabilities((unsigned char __user *)arg2, (size_t)arg3); |
| 1928 | 2018 | |
| 2019 | + case KEYCTL_WATCH_KEY: | |
| 2020 | + return keyctl_watch_key((key_serial_t)arg2, (int)arg3, (int)arg4); | |
| 2021 | + | |
| 1929 | 2022 | default: |
| 1930 | 2023 | return -EOPNOTSUPP; |
| 1931 | 2024 | } |
| @@ -1056,12 +1056,14 @@ int keyring_restrict(key_ref_t keyring_ref, const char *type, · 1055 unmodified lines | ||
| 1056 | 1056 | down_write(&keyring->sem); |
| 1057 | 1057 | down_write(&keyring_serialise_restrict_sem); |
| 1058 | 1058 | |
| 1059 | − if (keyring->restrict_link) | |
| 1059 | + if (keyring->restrict_link) { | |
| 1060 | 1060 | ret = -EEXIST; |
| 1061 | − else if (keyring_detect_restriction_cycle(keyring, restrict_link)) | |
| 1061 | + } else if (keyring_detect_restriction_cycle(keyring, restrict_link)) { | |
| 1062 | 1062 | ret = -EDEADLK; |
| 1063 | − else | |
| 1063 | + } else { | |
| 1064 | 1064 | keyring->restrict_link = restrict_link; |
| 1065 | + notify_key(keyring, NOTIFY_KEY_SETATTR, 0); | |
| 1066 | + } | |
| 1065 | 1067 | |
| 1066 | 1068 | up_write(&keyring_serialise_restrict_sem); |
| 1067 | 1069 | up_write(&keyring->sem); |
| @@ -1362,12 +1364,14 @@ int __key_link_check_live_key(struct key *keyring, struct key *key) · 294 unmodified lines | ||
| 1362 | 1364 | * holds at most one link to any given key of a particular type+description |
| 1363 | 1365 | * combination. |
| 1364 | 1366 | */ |
| 1365 | −void __key_link(struct key *key, struct assoc_array_edit **_edit) | |
| 1367 | +void __key_link(struct key *keyring, struct key *key, | |
| 1368 | + struct assoc_array_edit **_edit) | |
| 1366 | 1369 | { |
| 1367 | 1370 | __key_get(key); |
| 1368 | 1371 | assoc_array_insert_set_object(*_edit, keyring_key_to_ptr(key)); |
| 1369 | 1372 | assoc_array_apply_edit(*_edit); |
| 1370 | 1373 | *_edit = NULL; |
| 1374 | + notify_key(keyring, NOTIFY_KEY_LINKED, key_serial(key)); | |
| 1371 | 1375 | } |
| 1372 | 1376 | |
| 1373 | 1377 | /* |
| @@ -1451,7 +1455,7 @@ int key_link(struct key *keyring, struct key *key) · 77 unmodified lines | ||
| 1451 | 1455 | if (ret == 0) |
| 1452 | 1456 | ret = __key_link_check_live_key(keyring, key); |
| 1453 | 1457 | if (ret == 0) |
| 1454 | − __key_link(key, &edit); | |
| 1458 | + __key_link(keyring, key, &edit); | |
| 1455 | 1459 | |
| 1456 | 1460 | error_end: |
| 1457 | 1461 | __key_link_end(keyring, &key->index_key, edit); |
| @@ -1483,7 +1487,7 @@ static int __key_unlink_begin(struct key *keyring, struct key *key, · 25 unmodified lines | ||
| 1483 | 1487 | struct assoc_array_edit *edit; |
| 1484 | 1488 | |
| 1485 | 1489 | BUG_ON(*_edit != NULL); |
| 1486 | − | |
| 1490 | + | |
| 1487 | 1491 | edit = assoc_array_delete(&keyring->keys, &keyring_assoc_array_ops, |
| 1488 | 1492 | &key->index_key); |
| 1489 | 1493 | if (IS_ERR(edit)) |
| @@ -1503,6 +1507,7 @@ static void __key_unlink(struct key *keyring, struct key *key, · 13 unmodified lines | ||
| 1503 | 1507 | struct assoc_array_edit **_edit) |
| 1504 | 1508 | { |
| 1505 | 1509 | assoc_array_apply_edit(*_edit); |
| 1510 | + notify_key(keyring, NOTIFY_KEY_UNLINKED, key_serial(key)); | |
| 1506 | 1511 | *_edit = NULL; |
| 1507 | 1512 | key_payload_reserve(keyring, keyring->datalen - KEYQUOTA_LINK_BYTES); |
| 1508 | 1513 | } |
| @@ -1621,7 +1626,7 @@ int key_move(struct key *key, · 112 unmodified lines | ||
| 1621 | 1626 | goto error; |
| 1622 | 1627 | |
| 1623 | 1628 | __key_unlink(from_keyring, key, &from_edit); |
| 1624 | − __key_link(key, &to_edit); | |
| 1629 | + __key_link(to_keyring, key, &to_edit); | |
| 1625 | 1630 | error: |
| 1626 | 1631 | __key_link_end(to_keyring, &key->index_key, to_edit); |
| 1627 | 1632 | __key_unlink_end(from_keyring, key, from_edit); |
| @@ -1655,6 +1660,7 @@ int keyring_clear(struct key *keyring) · 27 unmodified lines | ||
| 1655 | 1660 | } else { |
| 1656 | 1661 | if (edit) |
| 1657 | 1662 | assoc_array_apply_edit(edit); |
| 1663 | + notify_key(keyring, NOTIFY_KEY_CLEARED, 0); | |
| 1658 | 1664 | key_payload_reserve(keyring, 0); |
| 1659 | 1665 | ret = 0; |
| 1660 | 1666 | } |
| @@ -418,7 +418,7 @@ static int construct_alloc_key(struct keyring_search_context *ctx, · 417 unmodified lines | ||
| 418 | 418 | goto key_already_present; |
| 419 | 419 | |
| 420 | 420 | if (dest_keyring) |
| 421 | − __key_link(key, &edit); | |
| 421 | + __key_link(dest_keyring, key, &edit); | |
| 422 | 422 | |
| 423 | 423 | mutex_unlock(&key_construction_mutex); |
| 424 | 424 | if (dest_keyring) |
| @@ -437,7 +437,7 @@ key_already_present: · 12 unmodified lines | ||
| 437 | 437 | if (dest_keyring) { |
| 438 | 438 | ret = __key_link_check_live_key(dest_keyring, key); |
| 439 | 439 | if (ret == 0) |
| 440 | − __key_link(key, &edit); | |
| 440 | + __key_link(dest_keyring, key, &edit); | |
| 441 | 441 | __key_link_end(dest_keyring, &ctx->index_key, edit); |
| 442 | 442 | if (ret < 0) |
| 443 | 443 | goto link_check_failed; |