.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* Userspace key control operations |
---|
2 | 3 | * |
---|
3 | 4 | * Copyright (C) 2004-5 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> |
---|
13 | 8 | #include <linux/init.h> |
---|
14 | 9 | #include <linux/sched.h> |
---|
15 | 10 | #include <linux/sched/task.h> |
---|
.. | .. |
---|
30 | 25 | #include "internal.h" |
---|
31 | 26 | |
---|
32 | 27 | #define KEY_MAX_DESC_SIZE 4096 |
---|
| 28 | + |
---|
| 29 | +static const unsigned char keyrings_capabilities[2] = { |
---|
| 30 | + [0] = (KEYCTL_CAPS0_CAPABILITIES | |
---|
| 31 | + (IS_ENABLED(CONFIG_PERSISTENT_KEYRINGS) ? KEYCTL_CAPS0_PERSISTENT_KEYRINGS : 0) | |
---|
| 32 | + (IS_ENABLED(CONFIG_KEY_DH_OPERATIONS) ? KEYCTL_CAPS0_DIFFIE_HELLMAN : 0) | |
---|
| 33 | + (IS_ENABLED(CONFIG_ASYMMETRIC_KEY_TYPE) ? KEYCTL_CAPS0_PUBLIC_KEY : 0) | |
---|
| 34 | + (IS_ENABLED(CONFIG_BIG_KEYS) ? KEYCTL_CAPS0_BIG_KEY : 0) | |
---|
| 35 | + KEYCTL_CAPS0_INVALIDATE | |
---|
| 36 | + KEYCTL_CAPS0_RESTRICT_KEYRING | |
---|
| 37 | + KEYCTL_CAPS0_MOVE |
---|
| 38 | + ), |
---|
| 39 | + [1] = (KEYCTL_CAPS1_NS_KEYRING_NAME | |
---|
| 40 | + KEYCTL_CAPS1_NS_KEY_TAG | |
---|
| 41 | + (IS_ENABLED(CONFIG_KEY_NOTIFICATIONS) ? KEYCTL_CAPS1_NOTIFICATIONS : 0) |
---|
| 42 | + ), |
---|
| 43 | +}; |
---|
33 | 44 | |
---|
34 | 45 | static int key_get_type_from_user(char *type, |
---|
35 | 46 | const char __user *_type, |
---|
.. | .. |
---|
208 | 219 | } |
---|
209 | 220 | |
---|
210 | 221 | /* do the search */ |
---|
211 | | - key = request_key_and_link(ktype, description, callout_info, |
---|
| 222 | + key = request_key_and_link(ktype, description, NULL, callout_info, |
---|
212 | 223 | callout_len, NULL, key_ref_to_ptr(dest_ref), |
---|
213 | 224 | KEY_ALLOC_IN_QUOTA); |
---|
214 | 225 | if (IS_ERR(key)) { |
---|
.. | .. |
---|
420 | 431 | |
---|
421 | 432 | /* Root is permitted to invalidate certain special keys */ |
---|
422 | 433 | if (capable(CAP_SYS_ADMIN)) { |
---|
423 | | - key_ref = lookup_user_key(id, 0, 0); |
---|
| 434 | + key_ref = lookup_user_key(id, 0, KEY_SYSADMIN_OVERRIDE); |
---|
424 | 435 | if (IS_ERR(key_ref)) |
---|
425 | 436 | goto error; |
---|
426 | 437 | if (test_bit(KEY_FLAG_ROOT_CAN_INVAL, |
---|
.. | .. |
---|
465 | 476 | |
---|
466 | 477 | /* Root is permitted to invalidate certain special keyrings */ |
---|
467 | 478 | if (capable(CAP_SYS_ADMIN)) { |
---|
468 | | - keyring_ref = lookup_user_key(ringid, 0, 0); |
---|
| 479 | + keyring_ref = lookup_user_key(ringid, 0, |
---|
| 480 | + KEY_SYSADMIN_OVERRIDE); |
---|
469 | 481 | if (IS_ERR(keyring_ref)) |
---|
470 | 482 | goto error; |
---|
471 | 483 | if (test_bit(KEY_FLAG_ROOT_CAN_CLEAR, |
---|
.. | .. |
---|
549 | 561 | goto error; |
---|
550 | 562 | } |
---|
551 | 563 | |
---|
552 | | - key_ref = lookup_user_key(id, KEY_LOOKUP_FOR_UNLINK, 0); |
---|
| 564 | + key_ref = lookup_user_key(id, KEY_LOOKUP_PARTIAL, KEY_NEED_UNLINK); |
---|
553 | 565 | if (IS_ERR(key_ref)) { |
---|
554 | 566 | ret = PTR_ERR(key_ref); |
---|
555 | 567 | goto error2; |
---|
.. | .. |
---|
567 | 579 | error2: |
---|
568 | 580 | key_ref_put(keyring_ref); |
---|
569 | 581 | error: |
---|
| 582 | + return ret; |
---|
| 583 | +} |
---|
| 584 | + |
---|
| 585 | +/* |
---|
| 586 | + * Move a link to a key from one keyring to another, displacing any matching |
---|
| 587 | + * key from the destination keyring. |
---|
| 588 | + * |
---|
| 589 | + * The key must grant the caller Link permission and both keyrings must grant |
---|
| 590 | + * the caller Write permission. There must also be a link in the from keyring |
---|
| 591 | + * to the key. If both keyrings are the same, nothing is done. |
---|
| 592 | + * |
---|
| 593 | + * If successful, 0 will be returned. |
---|
| 594 | + */ |
---|
| 595 | +long keyctl_keyring_move(key_serial_t id, key_serial_t from_ringid, |
---|
| 596 | + key_serial_t to_ringid, unsigned int flags) |
---|
| 597 | +{ |
---|
| 598 | + key_ref_t key_ref, from_ref, to_ref; |
---|
| 599 | + long ret; |
---|
| 600 | + |
---|
| 601 | + if (flags & ~KEYCTL_MOVE_EXCL) |
---|
| 602 | + return -EINVAL; |
---|
| 603 | + |
---|
| 604 | + key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_NEED_LINK); |
---|
| 605 | + if (IS_ERR(key_ref)) |
---|
| 606 | + return PTR_ERR(key_ref); |
---|
| 607 | + |
---|
| 608 | + from_ref = lookup_user_key(from_ringid, 0, KEY_NEED_WRITE); |
---|
| 609 | + if (IS_ERR(from_ref)) { |
---|
| 610 | + ret = PTR_ERR(from_ref); |
---|
| 611 | + goto error2; |
---|
| 612 | + } |
---|
| 613 | + |
---|
| 614 | + to_ref = lookup_user_key(to_ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE); |
---|
| 615 | + if (IS_ERR(to_ref)) { |
---|
| 616 | + ret = PTR_ERR(to_ref); |
---|
| 617 | + goto error3; |
---|
| 618 | + } |
---|
| 619 | + |
---|
| 620 | + ret = key_move(key_ref_to_ptr(key_ref), key_ref_to_ptr(from_ref), |
---|
| 621 | + key_ref_to_ptr(to_ref), flags); |
---|
| 622 | + |
---|
| 623 | + key_ref_put(to_ref); |
---|
| 624 | +error3: |
---|
| 625 | + key_ref_put(from_ref); |
---|
| 626 | +error2: |
---|
| 627 | + key_ref_put(key_ref); |
---|
570 | 628 | return ret; |
---|
571 | 629 | } |
---|
572 | 630 | |
---|
.. | .. |
---|
603 | 661 | key_put(instkey); |
---|
604 | 662 | key_ref = lookup_user_key(keyid, |
---|
605 | 663 | KEY_LOOKUP_PARTIAL, |
---|
606 | | - 0); |
---|
| 664 | + KEY_AUTHTOKEN_OVERRIDE); |
---|
607 | 665 | if (!IS_ERR(key_ref)) |
---|
608 | 666 | goto okay; |
---|
609 | 667 | } |
---|
.. | .. |
---|
702 | 760 | } |
---|
703 | 761 | |
---|
704 | 762 | /* do the search */ |
---|
705 | | - key_ref = keyring_search(keyring_ref, ktype, description); |
---|
| 763 | + key_ref = keyring_search(keyring_ref, ktype, description, true); |
---|
706 | 764 | if (IS_ERR(key_ref)) { |
---|
707 | 765 | ret = PTR_ERR(key_ref); |
---|
708 | 766 | |
---|
.. | .. |
---|
773 | 831 | size_t key_data_len; |
---|
774 | 832 | |
---|
775 | 833 | /* find the key first */ |
---|
776 | | - key_ref = lookup_user_key(keyid, 0, 0); |
---|
| 834 | + key_ref = lookup_user_key(keyid, 0, KEY_DEFER_PERM_CHECK); |
---|
777 | 835 | if (IS_ERR(key_ref)) { |
---|
778 | 836 | ret = -ENOKEY; |
---|
779 | 837 | goto out; |
---|
.. | .. |
---|
820 | 878 | * |
---|
821 | 879 | * Allocating a temporary buffer to hold the keys before |
---|
822 | 880 | * transferring them to user buffer to avoid potential |
---|
823 | | - * deadlock involving page fault and mmap_sem. |
---|
| 881 | + * deadlock involving page fault and mmap_lock. |
---|
824 | 882 | * |
---|
825 | 883 | * key_data_len = (buflen <= PAGE_SIZE) |
---|
826 | 884 | * ? buflen : actual length of key data |
---|
.. | .. |
---|
922 | 980 | ret = -EACCES; |
---|
923 | 981 | down_write(&key->sem); |
---|
924 | 982 | |
---|
925 | | - if (!capable(CAP_SYS_ADMIN)) { |
---|
| 983 | + { |
---|
| 984 | + bool is_privileged_op = false; |
---|
| 985 | + |
---|
926 | 986 | /* only the sysadmin can chown a key to some other UID */ |
---|
927 | 987 | if (user != (uid_t) -1 && !uid_eq(key->uid, uid)) |
---|
928 | | - goto error_put; |
---|
| 988 | + is_privileged_op = true; |
---|
929 | 989 | |
---|
930 | 990 | /* only the sysadmin can set the key's GID to a group other |
---|
931 | 991 | * than one of those that the current process subscribes to */ |
---|
932 | 992 | if (group != (gid_t) -1 && !gid_eq(gid, key->gid) && !in_group_p(gid)) |
---|
| 993 | + is_privileged_op = true; |
---|
| 994 | + |
---|
| 995 | + if (is_privileged_op && !capable(CAP_SYS_ADMIN)) |
---|
933 | 996 | goto error_put; |
---|
934 | 997 | } |
---|
935 | 998 | |
---|
.. | .. |
---|
981 | 1044 | if (group != (gid_t) -1) |
---|
982 | 1045 | key->gid = gid; |
---|
983 | 1046 | |
---|
| 1047 | + notify_key(key, NOTIFY_KEY_SETATTR, 0); |
---|
984 | 1048 | ret = 0; |
---|
985 | 1049 | |
---|
986 | 1050 | error_put: |
---|
.. | .. |
---|
1029 | 1093 | down_write(&key->sem); |
---|
1030 | 1094 | |
---|
1031 | 1095 | /* if we're not the sysadmin, we can only change a key that we own */ |
---|
1032 | | - if (capable(CAP_SYS_ADMIN) || uid_eq(key->uid, current_fsuid())) { |
---|
| 1096 | + if (uid_eq(key->uid, current_fsuid()) || capable(CAP_SYS_ADMIN)) { |
---|
1033 | 1097 | key->perm = perm; |
---|
| 1098 | + notify_key(key, NOTIFY_KEY_SETATTR, 0); |
---|
1034 | 1099 | ret = 0; |
---|
1035 | 1100 | } |
---|
1036 | 1101 | |
---|
.. | .. |
---|
1104 | 1169 | * |
---|
1105 | 1170 | * If successful, 0 will be returned. |
---|
1106 | 1171 | */ |
---|
1107 | | -long keyctl_instantiate_key_common(key_serial_t id, |
---|
| 1172 | +static long keyctl_instantiate_key_common(key_serial_t id, |
---|
1108 | 1173 | struct iov_iter *from, |
---|
1109 | 1174 | key_serial_t ringid) |
---|
1110 | 1175 | { |
---|
.. | .. |
---|
1406 | 1471 | key_put(instkey); |
---|
1407 | 1472 | key_ref = lookup_user_key(id, |
---|
1408 | 1473 | KEY_LOOKUP_PARTIAL, |
---|
1409 | | - 0); |
---|
| 1474 | + KEY_AUTHTOKEN_OVERRIDE); |
---|
1410 | 1475 | if (!IS_ERR(key_ref)) |
---|
1411 | 1476 | goto okay; |
---|
1412 | 1477 | } |
---|
.. | .. |
---|
1419 | 1484 | okay: |
---|
1420 | 1485 | key = key_ref_to_ptr(key_ref); |
---|
1421 | 1486 | ret = 0; |
---|
1422 | | - if (test_bit(KEY_FLAG_KEEP, &key->flags)) |
---|
| 1487 | + if (test_bit(KEY_FLAG_KEEP, &key->flags)) { |
---|
1423 | 1488 | ret = -EPERM; |
---|
1424 | | - else |
---|
| 1489 | + } else { |
---|
1425 | 1490 | key_set_timeout(key, timeout); |
---|
| 1491 | + notify_key(key, NOTIFY_KEY_SETATTR, 0); |
---|
| 1492 | + } |
---|
1426 | 1493 | key_put(key); |
---|
1427 | 1494 | |
---|
1428 | 1495 | error: |
---|
.. | .. |
---|
1512 | 1579 | return PTR_ERR(instkey); |
---|
1513 | 1580 | key_put(instkey); |
---|
1514 | 1581 | |
---|
1515 | | - key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, 0); |
---|
| 1582 | + key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, |
---|
| 1583 | + KEY_AUTHTOKEN_OVERRIDE); |
---|
1516 | 1584 | if (IS_ERR(key_ref)) |
---|
1517 | 1585 | return PTR_ERR(key_ref); |
---|
1518 | 1586 | } |
---|
.. | .. |
---|
1588 | 1656 | |
---|
1589 | 1657 | ret = -EPERM; |
---|
1590 | 1658 | oldwork = NULL; |
---|
1591 | | - parent = me->real_parent; |
---|
| 1659 | + parent = rcu_dereference_protected(me->real_parent, |
---|
| 1660 | + lockdep_is_held(&tasklist_lock)); |
---|
1592 | 1661 | |
---|
1593 | 1662 | /* the parent mustn't be init and mustn't be a kernel thread */ |
---|
1594 | 1663 | if (parent->pid <= 1 || !parent->mm) |
---|
.. | .. |
---|
1629 | 1698 | |
---|
1630 | 1699 | /* the replacement session keyring is applied just prior to userspace |
---|
1631 | 1700 | * restarting */ |
---|
1632 | | - ret = task_work_add(parent, newwork, true); |
---|
| 1701 | + ret = task_work_add(parent, newwork, TWA_RESUME); |
---|
1633 | 1702 | if (!ret) |
---|
1634 | 1703 | newwork = NULL; |
---|
1635 | 1704 | unlock: |
---|
.. | .. |
---|
1693 | 1762 | error: |
---|
1694 | 1763 | key_ref_put(key_ref); |
---|
1695 | 1764 | return ret; |
---|
| 1765 | +} |
---|
| 1766 | + |
---|
| 1767 | +#ifdef CONFIG_KEY_NOTIFICATIONS |
---|
| 1768 | +/* |
---|
| 1769 | + * Watch for changes to a key. |
---|
| 1770 | + * |
---|
| 1771 | + * The caller must have View permission to watch a key or keyring. |
---|
| 1772 | + */ |
---|
| 1773 | +long keyctl_watch_key(key_serial_t id, int watch_queue_fd, int watch_id) |
---|
| 1774 | +{ |
---|
| 1775 | + struct watch_queue *wqueue; |
---|
| 1776 | + struct watch_list *wlist = NULL; |
---|
| 1777 | + struct watch *watch = NULL; |
---|
| 1778 | + struct key *key; |
---|
| 1779 | + key_ref_t key_ref; |
---|
| 1780 | + long ret; |
---|
| 1781 | + |
---|
| 1782 | + if (watch_id < -1 || watch_id > 0xff) |
---|
| 1783 | + return -EINVAL; |
---|
| 1784 | + |
---|
| 1785 | + key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_NEED_VIEW); |
---|
| 1786 | + if (IS_ERR(key_ref)) |
---|
| 1787 | + return PTR_ERR(key_ref); |
---|
| 1788 | + key = key_ref_to_ptr(key_ref); |
---|
| 1789 | + |
---|
| 1790 | + wqueue = get_watch_queue(watch_queue_fd); |
---|
| 1791 | + if (IS_ERR(wqueue)) { |
---|
| 1792 | + ret = PTR_ERR(wqueue); |
---|
| 1793 | + goto err_key; |
---|
| 1794 | + } |
---|
| 1795 | + |
---|
| 1796 | + if (watch_id >= 0) { |
---|
| 1797 | + ret = -ENOMEM; |
---|
| 1798 | + if (!key->watchers) { |
---|
| 1799 | + wlist = kzalloc(sizeof(*wlist), GFP_KERNEL); |
---|
| 1800 | + if (!wlist) |
---|
| 1801 | + goto err_wqueue; |
---|
| 1802 | + init_watch_list(wlist, NULL); |
---|
| 1803 | + } |
---|
| 1804 | + |
---|
| 1805 | + watch = kzalloc(sizeof(*watch), GFP_KERNEL); |
---|
| 1806 | + if (!watch) |
---|
| 1807 | + goto err_wlist; |
---|
| 1808 | + |
---|
| 1809 | + init_watch(watch, wqueue); |
---|
| 1810 | + watch->id = key->serial; |
---|
| 1811 | + watch->info_id = (u32)watch_id << WATCH_INFO_ID__SHIFT; |
---|
| 1812 | + |
---|
| 1813 | + ret = security_watch_key(key); |
---|
| 1814 | + if (ret < 0) |
---|
| 1815 | + goto err_watch; |
---|
| 1816 | + |
---|
| 1817 | + down_write(&key->sem); |
---|
| 1818 | + if (!key->watchers) { |
---|
| 1819 | + key->watchers = wlist; |
---|
| 1820 | + wlist = NULL; |
---|
| 1821 | + } |
---|
| 1822 | + |
---|
| 1823 | + ret = add_watch_to_object(watch, key->watchers); |
---|
| 1824 | + up_write(&key->sem); |
---|
| 1825 | + |
---|
| 1826 | + if (ret == 0) |
---|
| 1827 | + watch = NULL; |
---|
| 1828 | + } else { |
---|
| 1829 | + ret = -EBADSLT; |
---|
| 1830 | + if (key->watchers) { |
---|
| 1831 | + down_write(&key->sem); |
---|
| 1832 | + ret = remove_watch_from_object(key->watchers, |
---|
| 1833 | + wqueue, key_serial(key), |
---|
| 1834 | + false); |
---|
| 1835 | + up_write(&key->sem); |
---|
| 1836 | + } |
---|
| 1837 | + } |
---|
| 1838 | + |
---|
| 1839 | +err_watch: |
---|
| 1840 | + kfree(watch); |
---|
| 1841 | +err_wlist: |
---|
| 1842 | + kfree(wlist); |
---|
| 1843 | +err_wqueue: |
---|
| 1844 | + put_watch_queue(wqueue); |
---|
| 1845 | +err_key: |
---|
| 1846 | + key_put(key); |
---|
| 1847 | + return ret; |
---|
| 1848 | +} |
---|
| 1849 | +#endif /* CONFIG_KEY_NOTIFICATIONS */ |
---|
| 1850 | + |
---|
| 1851 | +/* |
---|
| 1852 | + * Get keyrings subsystem capabilities. |
---|
| 1853 | + */ |
---|
| 1854 | +long keyctl_capabilities(unsigned char __user *_buffer, size_t buflen) |
---|
| 1855 | +{ |
---|
| 1856 | + size_t size = buflen; |
---|
| 1857 | + |
---|
| 1858 | + if (size > 0) { |
---|
| 1859 | + if (size > sizeof(keyrings_capabilities)) |
---|
| 1860 | + size = sizeof(keyrings_capabilities); |
---|
| 1861 | + if (copy_to_user(_buffer, keyrings_capabilities, size) != 0) |
---|
| 1862 | + return -EFAULT; |
---|
| 1863 | + if (size < buflen && |
---|
| 1864 | + clear_user(_buffer + size, buflen - size) != 0) |
---|
| 1865 | + return -EFAULT; |
---|
| 1866 | + } |
---|
| 1867 | + |
---|
| 1868 | + return sizeof(keyrings_capabilities); |
---|
1696 | 1869 | } |
---|
1697 | 1870 | |
---|
1698 | 1871 | /* |
---|
.. | .. |
---|
1811 | 1984 | (const char __user *) arg3, |
---|
1812 | 1985 | (const char __user *) arg4); |
---|
1813 | 1986 | |
---|
| 1987 | + case KEYCTL_PKEY_QUERY: |
---|
| 1988 | + if (arg3 != 0) |
---|
| 1989 | + return -EINVAL; |
---|
| 1990 | + return keyctl_pkey_query((key_serial_t)arg2, |
---|
| 1991 | + (const char __user *)arg4, |
---|
| 1992 | + (struct keyctl_pkey_query __user *)arg5); |
---|
| 1993 | + |
---|
| 1994 | + case KEYCTL_PKEY_ENCRYPT: |
---|
| 1995 | + case KEYCTL_PKEY_DECRYPT: |
---|
| 1996 | + case KEYCTL_PKEY_SIGN: |
---|
| 1997 | + return keyctl_pkey_e_d_s( |
---|
| 1998 | + option, |
---|
| 1999 | + (const struct keyctl_pkey_params __user *)arg2, |
---|
| 2000 | + (const char __user *)arg3, |
---|
| 2001 | + (const void __user *)arg4, |
---|
| 2002 | + (void __user *)arg5); |
---|
| 2003 | + |
---|
| 2004 | + case KEYCTL_PKEY_VERIFY: |
---|
| 2005 | + return keyctl_pkey_verify( |
---|
| 2006 | + (const struct keyctl_pkey_params __user *)arg2, |
---|
| 2007 | + (const char __user *)arg3, |
---|
| 2008 | + (const void __user *)arg4, |
---|
| 2009 | + (const void __user *)arg5); |
---|
| 2010 | + |
---|
| 2011 | + case KEYCTL_MOVE: |
---|
| 2012 | + return keyctl_keyring_move((key_serial_t)arg2, |
---|
| 2013 | + (key_serial_t)arg3, |
---|
| 2014 | + (key_serial_t)arg4, |
---|
| 2015 | + (unsigned int)arg5); |
---|
| 2016 | + |
---|
| 2017 | + case KEYCTL_CAPABILITIES: |
---|
| 2018 | + return keyctl_capabilities((unsigned char __user *)arg2, (size_t)arg3); |
---|
| 2019 | + |
---|
| 2020 | + case KEYCTL_WATCH_KEY: |
---|
| 2021 | + return keyctl_watch_key((key_serial_t)arg2, (int)arg3, (int)arg4); |
---|
| 2022 | + |
---|
1814 | 2023 | default: |
---|
1815 | 2024 | return -EOPNOTSUPP; |
---|
1816 | 2025 | } |
---|