| .. | .. |
|---|
| 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 |
|---|
| .. | .. |
|---|
| 981 | 1039 | if (group != (gid_t) -1) |
|---|
| 982 | 1040 | key->gid = gid; |
|---|
| 983 | 1041 | |
|---|
| 1042 | + notify_key(key, NOTIFY_KEY_SETATTR, 0); |
|---|
| 984 | 1043 | ret = 0; |
|---|
| 985 | 1044 | |
|---|
| 986 | 1045 | error_put: |
|---|
| .. | .. |
|---|
| 1031 | 1090 | /* if we're not the sysadmin, we can only change a key that we own */ |
|---|
| 1032 | 1091 | if (capable(CAP_SYS_ADMIN) || uid_eq(key->uid, current_fsuid())) { |
|---|
| 1033 | 1092 | key->perm = perm; |
|---|
| 1093 | + notify_key(key, NOTIFY_KEY_SETATTR, 0); |
|---|
| 1034 | 1094 | ret = 0; |
|---|
| 1035 | 1095 | } |
|---|
| 1036 | 1096 | |
|---|
| .. | .. |
|---|
| 1104 | 1164 | * |
|---|
| 1105 | 1165 | * If successful, 0 will be returned. |
|---|
| 1106 | 1166 | */ |
|---|
| 1107 | | -long keyctl_instantiate_key_common(key_serial_t id, |
|---|
| 1167 | +static long keyctl_instantiate_key_common(key_serial_t id, |
|---|
| 1108 | 1168 | struct iov_iter *from, |
|---|
| 1109 | 1169 | key_serial_t ringid) |
|---|
| 1110 | 1170 | { |
|---|
| .. | .. |
|---|
| 1406 | 1466 | key_put(instkey); |
|---|
| 1407 | 1467 | key_ref = lookup_user_key(id, |
|---|
| 1408 | 1468 | KEY_LOOKUP_PARTIAL, |
|---|
| 1409 | | - 0); |
|---|
| 1469 | + KEY_AUTHTOKEN_OVERRIDE); |
|---|
| 1410 | 1470 | if (!IS_ERR(key_ref)) |
|---|
| 1411 | 1471 | goto okay; |
|---|
| 1412 | 1472 | } |
|---|
| .. | .. |
|---|
| 1419 | 1479 | okay: |
|---|
| 1420 | 1480 | key = key_ref_to_ptr(key_ref); |
|---|
| 1421 | 1481 | ret = 0; |
|---|
| 1422 | | - if (test_bit(KEY_FLAG_KEEP, &key->flags)) |
|---|
| 1482 | + if (test_bit(KEY_FLAG_KEEP, &key->flags)) { |
|---|
| 1423 | 1483 | ret = -EPERM; |
|---|
| 1424 | | - else |
|---|
| 1484 | + } else { |
|---|
| 1425 | 1485 | key_set_timeout(key, timeout); |
|---|
| 1486 | + notify_key(key, NOTIFY_KEY_SETATTR, 0); |
|---|
| 1487 | + } |
|---|
| 1426 | 1488 | key_put(key); |
|---|
| 1427 | 1489 | |
|---|
| 1428 | 1490 | error: |
|---|
| .. | .. |
|---|
| 1512 | 1574 | return PTR_ERR(instkey); |
|---|
| 1513 | 1575 | key_put(instkey); |
|---|
| 1514 | 1576 | |
|---|
| 1515 | | - key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, 0); |
|---|
| 1577 | + key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, |
|---|
| 1578 | + KEY_AUTHTOKEN_OVERRIDE); |
|---|
| 1516 | 1579 | if (IS_ERR(key_ref)) |
|---|
| 1517 | 1580 | return PTR_ERR(key_ref); |
|---|
| 1518 | 1581 | } |
|---|
| .. | .. |
|---|
| 1588 | 1651 | |
|---|
| 1589 | 1652 | ret = -EPERM; |
|---|
| 1590 | 1653 | oldwork = NULL; |
|---|
| 1591 | | - parent = me->real_parent; |
|---|
| 1654 | + parent = rcu_dereference_protected(me->real_parent, |
|---|
| 1655 | + lockdep_is_held(&tasklist_lock)); |
|---|
| 1592 | 1656 | |
|---|
| 1593 | 1657 | /* the parent mustn't be init and mustn't be a kernel thread */ |
|---|
| 1594 | 1658 | if (parent->pid <= 1 || !parent->mm) |
|---|
| .. | .. |
|---|
| 1629 | 1693 | |
|---|
| 1630 | 1694 | /* the replacement session keyring is applied just prior to userspace |
|---|
| 1631 | 1695 | * restarting */ |
|---|
| 1632 | | - ret = task_work_add(parent, newwork, true); |
|---|
| 1696 | + ret = task_work_add(parent, newwork, TWA_RESUME); |
|---|
| 1633 | 1697 | if (!ret) |
|---|
| 1634 | 1698 | newwork = NULL; |
|---|
| 1635 | 1699 | unlock: |
|---|
| .. | .. |
|---|
| 1693 | 1757 | error: |
|---|
| 1694 | 1758 | key_ref_put(key_ref); |
|---|
| 1695 | 1759 | return ret; |
|---|
| 1760 | +} |
|---|
| 1761 | + |
|---|
| 1762 | +#ifdef CONFIG_KEY_NOTIFICATIONS |
|---|
| 1763 | +/* |
|---|
| 1764 | + * Watch for changes to a key. |
|---|
| 1765 | + * |
|---|
| 1766 | + * The caller must have View permission to watch a key or keyring. |
|---|
| 1767 | + */ |
|---|
| 1768 | +long keyctl_watch_key(key_serial_t id, int watch_queue_fd, int watch_id) |
|---|
| 1769 | +{ |
|---|
| 1770 | + struct watch_queue *wqueue; |
|---|
| 1771 | + struct watch_list *wlist = NULL; |
|---|
| 1772 | + struct watch *watch = NULL; |
|---|
| 1773 | + struct key *key; |
|---|
| 1774 | + key_ref_t key_ref; |
|---|
| 1775 | + long ret; |
|---|
| 1776 | + |
|---|
| 1777 | + if (watch_id < -1 || watch_id > 0xff) |
|---|
| 1778 | + return -EINVAL; |
|---|
| 1779 | + |
|---|
| 1780 | + key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_NEED_VIEW); |
|---|
| 1781 | + if (IS_ERR(key_ref)) |
|---|
| 1782 | + return PTR_ERR(key_ref); |
|---|
| 1783 | + key = key_ref_to_ptr(key_ref); |
|---|
| 1784 | + |
|---|
| 1785 | + wqueue = get_watch_queue(watch_queue_fd); |
|---|
| 1786 | + if (IS_ERR(wqueue)) { |
|---|
| 1787 | + ret = PTR_ERR(wqueue); |
|---|
| 1788 | + goto err_key; |
|---|
| 1789 | + } |
|---|
| 1790 | + |
|---|
| 1791 | + if (watch_id >= 0) { |
|---|
| 1792 | + ret = -ENOMEM; |
|---|
| 1793 | + if (!key->watchers) { |
|---|
| 1794 | + wlist = kzalloc(sizeof(*wlist), GFP_KERNEL); |
|---|
| 1795 | + if (!wlist) |
|---|
| 1796 | + goto err_wqueue; |
|---|
| 1797 | + init_watch_list(wlist, NULL); |
|---|
| 1798 | + } |
|---|
| 1799 | + |
|---|
| 1800 | + watch = kzalloc(sizeof(*watch), GFP_KERNEL); |
|---|
| 1801 | + if (!watch) |
|---|
| 1802 | + goto err_wlist; |
|---|
| 1803 | + |
|---|
| 1804 | + init_watch(watch, wqueue); |
|---|
| 1805 | + watch->id = key->serial; |
|---|
| 1806 | + watch->info_id = (u32)watch_id << WATCH_INFO_ID__SHIFT; |
|---|
| 1807 | + |
|---|
| 1808 | + ret = security_watch_key(key); |
|---|
| 1809 | + if (ret < 0) |
|---|
| 1810 | + goto err_watch; |
|---|
| 1811 | + |
|---|
| 1812 | + down_write(&key->sem); |
|---|
| 1813 | + if (!key->watchers) { |
|---|
| 1814 | + key->watchers = wlist; |
|---|
| 1815 | + wlist = NULL; |
|---|
| 1816 | + } |
|---|
| 1817 | + |
|---|
| 1818 | + ret = add_watch_to_object(watch, key->watchers); |
|---|
| 1819 | + up_write(&key->sem); |
|---|
| 1820 | + |
|---|
| 1821 | + if (ret == 0) |
|---|
| 1822 | + watch = NULL; |
|---|
| 1823 | + } else { |
|---|
| 1824 | + ret = -EBADSLT; |
|---|
| 1825 | + if (key->watchers) { |
|---|
| 1826 | + down_write(&key->sem); |
|---|
| 1827 | + ret = remove_watch_from_object(key->watchers, |
|---|
| 1828 | + wqueue, key_serial(key), |
|---|
| 1829 | + false); |
|---|
| 1830 | + up_write(&key->sem); |
|---|
| 1831 | + } |
|---|
| 1832 | + } |
|---|
| 1833 | + |
|---|
| 1834 | +err_watch: |
|---|
| 1835 | + kfree(watch); |
|---|
| 1836 | +err_wlist: |
|---|
| 1837 | + kfree(wlist); |
|---|
| 1838 | +err_wqueue: |
|---|
| 1839 | + put_watch_queue(wqueue); |
|---|
| 1840 | +err_key: |
|---|
| 1841 | + key_put(key); |
|---|
| 1842 | + return ret; |
|---|
| 1843 | +} |
|---|
| 1844 | +#endif /* CONFIG_KEY_NOTIFICATIONS */ |
|---|
| 1845 | + |
|---|
| 1846 | +/* |
|---|
| 1847 | + * Get keyrings subsystem capabilities. |
|---|
| 1848 | + */ |
|---|
| 1849 | +long keyctl_capabilities(unsigned char __user *_buffer, size_t buflen) |
|---|
| 1850 | +{ |
|---|
| 1851 | + size_t size = buflen; |
|---|
| 1852 | + |
|---|
| 1853 | + if (size > 0) { |
|---|
| 1854 | + if (size > sizeof(keyrings_capabilities)) |
|---|
| 1855 | + size = sizeof(keyrings_capabilities); |
|---|
| 1856 | + if (copy_to_user(_buffer, keyrings_capabilities, size) != 0) |
|---|
| 1857 | + return -EFAULT; |
|---|
| 1858 | + if (size < buflen && |
|---|
| 1859 | + clear_user(_buffer + size, buflen - size) != 0) |
|---|
| 1860 | + return -EFAULT; |
|---|
| 1861 | + } |
|---|
| 1862 | + |
|---|
| 1863 | + return sizeof(keyrings_capabilities); |
|---|
| 1696 | 1864 | } |
|---|
| 1697 | 1865 | |
|---|
| 1698 | 1866 | /* |
|---|
| .. | .. |
|---|
| 1811 | 1979 | (const char __user *) arg3, |
|---|
| 1812 | 1980 | (const char __user *) arg4); |
|---|
| 1813 | 1981 | |
|---|
| 1982 | + case KEYCTL_PKEY_QUERY: |
|---|
| 1983 | + if (arg3 != 0) |
|---|
| 1984 | + return -EINVAL; |
|---|
| 1985 | + return keyctl_pkey_query((key_serial_t)arg2, |
|---|
| 1986 | + (const char __user *)arg4, |
|---|
| 1987 | + (struct keyctl_pkey_query __user *)arg5); |
|---|
| 1988 | + |
|---|
| 1989 | + case KEYCTL_PKEY_ENCRYPT: |
|---|
| 1990 | + case KEYCTL_PKEY_DECRYPT: |
|---|
| 1991 | + case KEYCTL_PKEY_SIGN: |
|---|
| 1992 | + return keyctl_pkey_e_d_s( |
|---|
| 1993 | + option, |
|---|
| 1994 | + (const struct keyctl_pkey_params __user *)arg2, |
|---|
| 1995 | + (const char __user *)arg3, |
|---|
| 1996 | + (const void __user *)arg4, |
|---|
| 1997 | + (void __user *)arg5); |
|---|
| 1998 | + |
|---|
| 1999 | + case KEYCTL_PKEY_VERIFY: |
|---|
| 2000 | + return keyctl_pkey_verify( |
|---|
| 2001 | + (const struct keyctl_pkey_params __user *)arg2, |
|---|
| 2002 | + (const char __user *)arg3, |
|---|
| 2003 | + (const void __user *)arg4, |
|---|
| 2004 | + (const void __user *)arg5); |
|---|
| 2005 | + |
|---|
| 2006 | + case KEYCTL_MOVE: |
|---|
| 2007 | + return keyctl_keyring_move((key_serial_t)arg2, |
|---|
| 2008 | + (key_serial_t)arg3, |
|---|
| 2009 | + (key_serial_t)arg4, |
|---|
| 2010 | + (unsigned int)arg5); |
|---|
| 2011 | + |
|---|
| 2012 | + case KEYCTL_CAPABILITIES: |
|---|
| 2013 | + return keyctl_capabilities((unsigned char __user *)arg2, (size_t)arg3); |
|---|
| 2014 | + |
|---|
| 2015 | + case KEYCTL_WATCH_KEY: |
|---|
| 2016 | + return keyctl_watch_key((key_serial_t)arg2, (int)arg3, (int)arg4); |
|---|
| 2017 | + |
|---|
| 1814 | 2018 | default: |
|---|
| 1815 | 2019 | return -EOPNOTSUPP; |
|---|
| 1816 | 2020 | } |
|---|