| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* Basic authentication token and access key management |
|---|
| 2 | 3 | * |
|---|
| 3 | 4 | * Copyright (C) 2004-2008 Red Hat, Inc. All Rights Reserved. |
|---|
| 4 | 5 | * Written by David Howells (dhowells@redhat.com) |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or |
|---|
| 7 | | - * modify it under the terms of the GNU General Public License |
|---|
| 8 | | - * as published by the Free Software Foundation; either version |
|---|
| 9 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 10 | 6 | */ |
|---|
| 11 | 7 | |
|---|
| 12 | | -#include <linux/module.h> |
|---|
| 8 | +#include <linux/export.h> |
|---|
| 13 | 9 | #include <linux/init.h> |
|---|
| 14 | 10 | #include <linux/poison.h> |
|---|
| 15 | 11 | #include <linux/sched.h> |
|---|
| .. | .. |
|---|
| 17 | 13 | #include <linux/security.h> |
|---|
| 18 | 14 | #include <linux/workqueue.h> |
|---|
| 19 | 15 | #include <linux/random.h> |
|---|
| 16 | +#include <linux/ima.h> |
|---|
| 20 | 17 | #include <linux/err.h> |
|---|
| 21 | 18 | #include "internal.h" |
|---|
| 22 | 19 | |
|---|
| .. | .. |
|---|
| 285 | 282 | key->index_key.description = kmemdup(desc, desclen + 1, GFP_KERNEL); |
|---|
| 286 | 283 | if (!key->index_key.description) |
|---|
| 287 | 284 | goto no_memory_3; |
|---|
| 285 | + key->index_key.type = type; |
|---|
| 286 | + key_set_index_key(&key->index_key); |
|---|
| 288 | 287 | |
|---|
| 289 | 288 | refcount_set(&key->usage, 1); |
|---|
| 290 | 289 | init_rwsem(&key->sem); |
|---|
| 291 | 290 | lockdep_set_class(&key->sem, &type->lock_class); |
|---|
| 292 | | - key->index_key.type = type; |
|---|
| 293 | 291 | key->user = user; |
|---|
| 294 | 292 | key->quotalen = quotalen; |
|---|
| 295 | 293 | key->datalen = type->def_datalen; |
|---|
| .. | .. |
|---|
| 318 | 316 | goto security_error; |
|---|
| 319 | 317 | |
|---|
| 320 | 318 | /* publish the key by giving it a serial number */ |
|---|
| 319 | + refcount_inc(&key->domain_tag->usage); |
|---|
| 321 | 320 | atomic_inc(&user->nkeys); |
|---|
| 322 | 321 | key_alloc_serial(key); |
|---|
| 323 | 322 | |
|---|
| .. | .. |
|---|
| 447 | 446 | /* mark the key as being instantiated */ |
|---|
| 448 | 447 | atomic_inc(&key->user->nikeys); |
|---|
| 449 | 448 | mark_key_instantiated(key, 0); |
|---|
| 449 | + notify_key(key, NOTIFY_KEY_INSTANTIATED, 0); |
|---|
| 450 | 450 | |
|---|
| 451 | 451 | if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) |
|---|
| 452 | 452 | awaken = 1; |
|---|
| .. | .. |
|---|
| 456 | 456 | if (test_bit(KEY_FLAG_KEEP, &keyring->flags)) |
|---|
| 457 | 457 | set_bit(KEY_FLAG_KEEP, &key->flags); |
|---|
| 458 | 458 | |
|---|
| 459 | | - __key_link(key, _edit); |
|---|
| 459 | + __key_link(keyring, key, _edit); |
|---|
| 460 | 460 | } |
|---|
| 461 | 461 | |
|---|
| 462 | 462 | /* disable the authorisation key */ |
|---|
| 463 | 463 | if (authkey) |
|---|
| 464 | | - key_revoke(authkey); |
|---|
| 464 | + key_invalidate(authkey); |
|---|
| 465 | 465 | |
|---|
| 466 | 466 | if (prep->expiry != TIME64_MAX) { |
|---|
| 467 | 467 | key->expiry = prep->expiry; |
|---|
| .. | .. |
|---|
| 502 | 502 | struct key *authkey) |
|---|
| 503 | 503 | { |
|---|
| 504 | 504 | struct key_preparsed_payload prep; |
|---|
| 505 | | - struct assoc_array_edit *edit; |
|---|
| 505 | + struct assoc_array_edit *edit = NULL; |
|---|
| 506 | 506 | int ret; |
|---|
| 507 | 507 | |
|---|
| 508 | 508 | memset(&prep, 0, sizeof(prep)); |
|---|
| .. | .. |
|---|
| 517 | 517 | } |
|---|
| 518 | 518 | |
|---|
| 519 | 519 | if (keyring) { |
|---|
| 520 | | - ret = __key_link_begin(keyring, &key->index_key, &edit); |
|---|
| 520 | + ret = __key_link_lock(keyring, &key->index_key); |
|---|
| 521 | 521 | if (ret < 0) |
|---|
| 522 | 522 | goto error; |
|---|
| 523 | + |
|---|
| 524 | + ret = __key_link_begin(keyring, &key->index_key, &edit); |
|---|
| 525 | + if (ret < 0) |
|---|
| 526 | + goto error_link_end; |
|---|
| 523 | 527 | |
|---|
| 524 | 528 | if (keyring->restrict_link && keyring->restrict_link->check) { |
|---|
| 525 | 529 | struct key_restriction *keyres = keyring->restrict_link; |
|---|
| .. | .. |
|---|
| 572 | 576 | struct key *keyring, |
|---|
| 573 | 577 | struct key *authkey) |
|---|
| 574 | 578 | { |
|---|
| 575 | | - struct assoc_array_edit *edit; |
|---|
| 579 | + struct assoc_array_edit *edit = NULL; |
|---|
| 576 | 580 | int ret, awaken, link_ret = 0; |
|---|
| 577 | 581 | |
|---|
| 578 | 582 | key_check(key); |
|---|
| .. | .. |
|---|
| 585 | 589 | if (keyring->restrict_link) |
|---|
| 586 | 590 | return -EPERM; |
|---|
| 587 | 591 | |
|---|
| 588 | | - link_ret = __key_link_begin(keyring, &key->index_key, &edit); |
|---|
| 592 | + link_ret = __key_link_lock(keyring, &key->index_key); |
|---|
| 593 | + if (link_ret == 0) { |
|---|
| 594 | + link_ret = __key_link_begin(keyring, &key->index_key, &edit); |
|---|
| 595 | + if (link_ret < 0) |
|---|
| 596 | + __key_link_end(keyring, &key->index_key, edit); |
|---|
| 597 | + } |
|---|
| 589 | 598 | } |
|---|
| 590 | 599 | |
|---|
| 591 | 600 | mutex_lock(&key_construction_mutex); |
|---|
| .. | .. |
|---|
| 595 | 604 | /* mark the key as being negatively instantiated */ |
|---|
| 596 | 605 | atomic_inc(&key->user->nikeys); |
|---|
| 597 | 606 | mark_key_instantiated(key, -error); |
|---|
| 607 | + notify_key(key, NOTIFY_KEY_INSTANTIATED, -error); |
|---|
| 598 | 608 | key->expiry = ktime_get_real_seconds() + timeout; |
|---|
| 599 | 609 | key_schedule_gc(key->expiry + key_gc_delay); |
|---|
| 600 | 610 | |
|---|
| .. | .. |
|---|
| 605 | 615 | |
|---|
| 606 | 616 | /* and link it into the destination keyring */ |
|---|
| 607 | 617 | if (keyring && link_ret == 0) |
|---|
| 608 | | - __key_link(key, &edit); |
|---|
| 618 | + __key_link(keyring, key, &edit); |
|---|
| 609 | 619 | |
|---|
| 610 | 620 | /* disable the authorisation key */ |
|---|
| 611 | 621 | if (authkey) |
|---|
| 612 | | - key_revoke(authkey); |
|---|
| 622 | + key_invalidate(authkey); |
|---|
| 613 | 623 | } |
|---|
| 614 | 624 | |
|---|
| 615 | 625 | mutex_unlock(&key_construction_mutex); |
|---|
| .. | .. |
|---|
| 758 | 768 | down_write(&key->sem); |
|---|
| 759 | 769 | |
|---|
| 760 | 770 | ret = key->type->update(key, prep); |
|---|
| 761 | | - if (ret == 0) |
|---|
| 771 | + if (ret == 0) { |
|---|
| 762 | 772 | /* Updating a negative key positively instantiates it */ |
|---|
| 763 | 773 | mark_key_instantiated(key, 0); |
|---|
| 774 | + notify_key(key, NOTIFY_KEY_UPDATED, 0); |
|---|
| 775 | + } |
|---|
| 764 | 776 | |
|---|
| 765 | 777 | up_write(&key->sem); |
|---|
| 766 | 778 | |
|---|
| .. | .. |
|---|
| 812 | 824 | .description = description, |
|---|
| 813 | 825 | }; |
|---|
| 814 | 826 | struct key_preparsed_payload prep; |
|---|
| 815 | | - struct assoc_array_edit *edit; |
|---|
| 827 | + struct assoc_array_edit *edit = NULL; |
|---|
| 816 | 828 | const struct cred *cred = current_cred(); |
|---|
| 817 | 829 | struct key *keyring, *key = NULL; |
|---|
| 818 | 830 | key_ref_t key_ref; |
|---|
| .. | .. |
|---|
| 861 | 873 | goto error_free_prep; |
|---|
| 862 | 874 | } |
|---|
| 863 | 875 | index_key.desc_len = strlen(index_key.description); |
|---|
| 876 | + key_set_index_key(&index_key); |
|---|
| 877 | + |
|---|
| 878 | + ret = __key_link_lock(keyring, &index_key); |
|---|
| 879 | + if (ret < 0) { |
|---|
| 880 | + key_ref = ERR_PTR(ret); |
|---|
| 881 | + goto error_free_prep; |
|---|
| 882 | + } |
|---|
| 864 | 883 | |
|---|
| 865 | 884 | ret = __key_link_begin(keyring, &index_key, &edit); |
|---|
| 866 | 885 | if (ret < 0) { |
|---|
| 867 | 886 | key_ref = ERR_PTR(ret); |
|---|
| 868 | | - goto error_free_prep; |
|---|
| 887 | + goto error_link_end; |
|---|
| 869 | 888 | } |
|---|
| 870 | 889 | |
|---|
| 871 | 890 | if (restrict_link && restrict_link->check) { |
|---|
| .. | .. |
|---|
| 924 | 943 | goto error_link_end; |
|---|
| 925 | 944 | } |
|---|
| 926 | 945 | |
|---|
| 946 | + ima_post_key_create_or_update(keyring, key, payload, plen, |
|---|
| 947 | + flags, true); |
|---|
| 948 | + |
|---|
| 927 | 949 | key_ref = make_key_ref(key, is_key_possessed(keyring_ref)); |
|---|
| 928 | 950 | |
|---|
| 929 | 951 | error_link_end: |
|---|
| .. | .. |
|---|
| 953 | 975 | } |
|---|
| 954 | 976 | |
|---|
| 955 | 977 | key_ref = __key_update(key_ref, &prep); |
|---|
| 978 | + |
|---|
| 979 | + if (!IS_ERR(key_ref)) |
|---|
| 980 | + ima_post_key_create_or_update(keyring, key, |
|---|
| 981 | + payload, plen, |
|---|
| 982 | + flags, false); |
|---|
| 983 | + |
|---|
| 956 | 984 | goto error_free_prep; |
|---|
| 957 | 985 | } |
|---|
| 958 | 986 | EXPORT_SYMBOL(key_create_or_update); |
|---|
| .. | .. |
|---|
| 1001 | 1029 | down_write(&key->sem); |
|---|
| 1002 | 1030 | |
|---|
| 1003 | 1031 | ret = key->type->update(key, &prep); |
|---|
| 1004 | | - if (ret == 0) |
|---|
| 1032 | + if (ret == 0) { |
|---|
| 1005 | 1033 | /* Updating a negative key positively instantiates it */ |
|---|
| 1006 | 1034 | mark_key_instantiated(key, 0); |
|---|
| 1035 | + notify_key(key, NOTIFY_KEY_UPDATED, 0); |
|---|
| 1036 | + } |
|---|
| 1007 | 1037 | |
|---|
| 1008 | 1038 | up_write(&key->sem); |
|---|
| 1009 | 1039 | |
|---|
| .. | .. |
|---|
| 1035 | 1065 | * instantiated |
|---|
| 1036 | 1066 | */ |
|---|
| 1037 | 1067 | down_write_nested(&key->sem, 1); |
|---|
| 1038 | | - if (!test_and_set_bit(KEY_FLAG_REVOKED, &key->flags) && |
|---|
| 1039 | | - key->type->revoke) |
|---|
| 1040 | | - key->type->revoke(key); |
|---|
| 1068 | + if (!test_and_set_bit(KEY_FLAG_REVOKED, &key->flags)) { |
|---|
| 1069 | + notify_key(key, NOTIFY_KEY_REVOKED, 0); |
|---|
| 1070 | + if (key->type->revoke) |
|---|
| 1071 | + key->type->revoke(key); |
|---|
| 1041 | 1072 | |
|---|
| 1042 | | - /* set the death time to no more than the expiry time */ |
|---|
| 1043 | | - time = ktime_get_real_seconds(); |
|---|
| 1044 | | - if (key->revoked_at == 0 || key->revoked_at > time) { |
|---|
| 1045 | | - key->revoked_at = time; |
|---|
| 1046 | | - key_schedule_gc(key->revoked_at + key_gc_delay); |
|---|
| 1073 | + /* set the death time to no more than the expiry time */ |
|---|
| 1074 | + time = ktime_get_real_seconds(); |
|---|
| 1075 | + if (key->revoked_at == 0 || key->revoked_at > time) { |
|---|
| 1076 | + key->revoked_at = time; |
|---|
| 1077 | + key_schedule_gc(key->revoked_at + key_gc_delay); |
|---|
| 1078 | + } |
|---|
| 1047 | 1079 | } |
|---|
| 1048 | 1080 | |
|---|
| 1049 | 1081 | up_write(&key->sem); |
|---|
| .. | .. |
|---|
| 1065 | 1097 | |
|---|
| 1066 | 1098 | if (!test_bit(KEY_FLAG_INVALIDATED, &key->flags)) { |
|---|
| 1067 | 1099 | down_write_nested(&key->sem, 1); |
|---|
| 1068 | | - if (!test_and_set_bit(KEY_FLAG_INVALIDATED, &key->flags)) |
|---|
| 1100 | + if (!test_and_set_bit(KEY_FLAG_INVALIDATED, &key->flags)) { |
|---|
| 1101 | + notify_key(key, NOTIFY_KEY_INVALIDATED, 0); |
|---|
| 1069 | 1102 | key_schedule_gc_links(); |
|---|
| 1103 | + } |
|---|
| 1070 | 1104 | up_write(&key->sem); |
|---|
| 1071 | 1105 | } |
|---|
| 1072 | 1106 | } |
|---|