aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/keys/compat.c2
-rw-r--r--security/keys/internal.h2
-rw-r--r--security/keys/keyctl.c77
-rw-r--r--security/keys/process_keys.c20
-rw-r--r--security/keys/request_key.c13
5 files changed, 50 insertions, 64 deletions
diff --git a/security/keys/compat.c b/security/keys/compat.c
index fab4f8dda6c6..c92d42b021aa 100644
--- a/security/keys/compat.c
+++ b/security/keys/compat.c
@@ -38,7 +38,7 @@ long compat_keyctl_instantiate_key_iov(
38 38
39 ret = compat_rw_copy_check_uvector(WRITE, _payload_iov, ioc, 39 ret = compat_rw_copy_check_uvector(WRITE, _payload_iov, ioc,
40 ARRAY_SIZE(iovstack), 40 ARRAY_SIZE(iovstack),
41 iovstack, &iov, 1); 41 iovstack, &iov);
42 if (ret < 0) 42 if (ret < 0)
43 return ret; 43 return ret;
44 if (ret == 0) 44 if (ret == 0)
diff --git a/security/keys/internal.h b/security/keys/internal.h
index f711b094ed41..3dcbf86b0d31 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -14,6 +14,7 @@
14 14
15#include <linux/sched.h> 15#include <linux/sched.h>
16#include <linux/key-type.h> 16#include <linux/key-type.h>
17#include <linux/task_work.h>
17 18
18#ifdef __KDEBUG 19#ifdef __KDEBUG
19#define kenter(FMT, ...) \ 20#define kenter(FMT, ...) \
@@ -148,6 +149,7 @@ extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
148#define KEY_LOOKUP_FOR_UNLINK 0x04 149#define KEY_LOOKUP_FOR_UNLINK 0x04
149 150
150extern long join_session_keyring(const char *name); 151extern long join_session_keyring(const char *name);
152extern void key_change_session_keyring(struct task_work *twork);
151 153
152extern struct work_struct key_gc_work; 154extern struct work_struct key_gc_work;
153extern unsigned key_gc_delay; 155extern unsigned key_gc_delay;
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index ddb3e05bc5fc..0f5b3f027299 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -84,7 +84,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
84 vm = false; 84 vm = false;
85 if (_payload) { 85 if (_payload) {
86 ret = -ENOMEM; 86 ret = -ENOMEM;
87 payload = kmalloc(plen, GFP_KERNEL); 87 payload = kmalloc(plen, GFP_KERNEL | __GFP_NOWARN);
88 if (!payload) { 88 if (!payload) {
89 if (plen <= PAGE_SIZE) 89 if (plen <= PAGE_SIZE)
90 goto error2; 90 goto error2;
@@ -1110,7 +1110,7 @@ long keyctl_instantiate_key_iov(key_serial_t id,
1110 goto no_payload; 1110 goto no_payload;
1111 1111
1112 ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc, 1112 ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc,
1113 ARRAY_SIZE(iovstack), iovstack, &iov, 1); 1113 ARRAY_SIZE(iovstack), iovstack, &iov);
1114 if (ret < 0) 1114 if (ret < 0)
1115 return ret; 1115 return ret;
1116 if (ret == 0) 1116 if (ret == 0)
@@ -1454,50 +1454,57 @@ long keyctl_get_security(key_serial_t keyid,
1454 */ 1454 */
1455long keyctl_session_to_parent(void) 1455long keyctl_session_to_parent(void)
1456{ 1456{
1457#ifdef TIF_NOTIFY_RESUME
1458 struct task_struct *me, *parent; 1457 struct task_struct *me, *parent;
1459 const struct cred *mycred, *pcred; 1458 const struct cred *mycred, *pcred;
1460 struct cred *cred, *oldcred; 1459 struct task_work *newwork, *oldwork;
1461 key_ref_t keyring_r; 1460 key_ref_t keyring_r;
1461 struct cred *cred;
1462 int ret; 1462 int ret;
1463 1463
1464 keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK); 1464 keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK);
1465 if (IS_ERR(keyring_r)) 1465 if (IS_ERR(keyring_r))
1466 return PTR_ERR(keyring_r); 1466 return PTR_ERR(keyring_r);
1467 1467
1468 ret = -ENOMEM;
1469 newwork = kmalloc(sizeof(struct task_work), GFP_KERNEL);
1470 if (!newwork)
1471 goto error_keyring;
1472
1468 /* our parent is going to need a new cred struct, a new tgcred struct 1473 /* our parent is going to need a new cred struct, a new tgcred struct
1469 * and new security data, so we allocate them here to prevent ENOMEM in 1474 * and new security data, so we allocate them here to prevent ENOMEM in
1470 * our parent */ 1475 * our parent */
1471 ret = -ENOMEM;
1472 cred = cred_alloc_blank(); 1476 cred = cred_alloc_blank();
1473 if (!cred) 1477 if (!cred)
1474 goto error_keyring; 1478 goto error_newwork;
1475 1479
1476 cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); 1480 cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r);
1477 keyring_r = NULL; 1481 init_task_work(newwork, key_change_session_keyring, cred);
1478 1482
1479 me = current; 1483 me = current;
1480 rcu_read_lock(); 1484 rcu_read_lock();
1481 write_lock_irq(&tasklist_lock); 1485 write_lock_irq(&tasklist_lock);
1482 1486
1483 parent = me->real_parent;
1484 ret = -EPERM; 1487 ret = -EPERM;
1488 oldwork = NULL;
1489 parent = me->real_parent;
1485 1490
1486 /* the parent mustn't be init and mustn't be a kernel thread */ 1491 /* the parent mustn't be init and mustn't be a kernel thread */
1487 if (parent->pid <= 1 || !parent->mm) 1492 if (parent->pid <= 1 || !parent->mm)
1488 goto not_permitted; 1493 goto unlock;
1489 1494
1490 /* the parent must be single threaded */ 1495 /* the parent must be single threaded */
1491 if (!thread_group_empty(parent)) 1496 if (!thread_group_empty(parent))
1492 goto not_permitted; 1497 goto unlock;
1493 1498
1494 /* the parent and the child must have different session keyrings or 1499 /* the parent and the child must have different session keyrings or
1495 * there's no point */ 1500 * there's no point */
1496 mycred = current_cred(); 1501 mycred = current_cred();
1497 pcred = __task_cred(parent); 1502 pcred = __task_cred(parent);
1498 if (mycred == pcred || 1503 if (mycred == pcred ||
1499 mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) 1504 mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) {
1500 goto already_same; 1505 ret = 0;
1506 goto unlock;
1507 }
1501 1508
1502 /* the parent must have the same effective ownership and mustn't be 1509 /* the parent must have the same effective ownership and mustn't be
1503 * SUID/SGID */ 1510 * SUID/SGID */
@@ -1507,50 +1514,40 @@ long keyctl_session_to_parent(void)
1507 pcred->gid != mycred->egid || 1514 pcred->gid != mycred->egid ||
1508 pcred->egid != mycred->egid || 1515 pcred->egid != mycred->egid ||
1509 pcred->sgid != mycred->egid) 1516 pcred->sgid != mycred->egid)
1510 goto not_permitted; 1517 goto unlock;
1511 1518
1512 /* the keyrings must have the same UID */ 1519 /* the keyrings must have the same UID */
1513 if ((pcred->tgcred->session_keyring && 1520 if ((pcred->tgcred->session_keyring &&
1514 pcred->tgcred->session_keyring->uid != mycred->euid) || 1521 pcred->tgcred->session_keyring->uid != mycred->euid) ||
1515 mycred->tgcred->session_keyring->uid != mycred->euid) 1522 mycred->tgcred->session_keyring->uid != mycred->euid)
1516 goto not_permitted; 1523 goto unlock;
1517 1524
1518 /* if there's an already pending keyring replacement, then we replace 1525 /* cancel an already pending keyring replacement */
1519 * that */ 1526 oldwork = task_work_cancel(parent, key_change_session_keyring);
1520 oldcred = parent->replacement_session_keyring;
1521 1527
1522 /* the replacement session keyring is applied just prior to userspace 1528 /* the replacement session keyring is applied just prior to userspace
1523 * restarting */ 1529 * restarting */
1524 parent->replacement_session_keyring = cred; 1530 ret = task_work_add(parent, newwork, true);
1525 cred = NULL; 1531 if (!ret)
1526 set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME); 1532 newwork = NULL;
1527 1533unlock:
1528 write_unlock_irq(&tasklist_lock);
1529 rcu_read_unlock();
1530 if (oldcred)
1531 put_cred(oldcred);
1532 return 0;
1533
1534already_same:
1535 ret = 0;
1536not_permitted:
1537 write_unlock_irq(&tasklist_lock); 1534 write_unlock_irq(&tasklist_lock);
1538 rcu_read_unlock(); 1535 rcu_read_unlock();
1539 put_cred(cred); 1536 if (oldwork) {
1537 put_cred(oldwork->data);
1538 kfree(oldwork);
1539 }
1540 if (newwork) {
1541 put_cred(newwork->data);
1542 kfree(newwork);
1543 }
1540 return ret; 1544 return ret;
1541 1545
1546error_newwork:
1547 kfree(newwork);
1542error_keyring: 1548error_keyring:
1543 key_ref_put(keyring_r); 1549 key_ref_put(keyring_r);
1544 return ret; 1550 return ret;
1545
1546#else /* !TIF_NOTIFY_RESUME */
1547 /*
1548 * To be removed when TIF_NOTIFY_RESUME has been implemented on
1549 * m68k/xtensa
1550 */
1551#warning TIF_NOTIFY_RESUME not implemented
1552 return -EOPNOTSUPP;
1553#endif /* !TIF_NOTIFY_RESUME */
1554} 1551}
1555 1552
1556/* 1553/*
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index d71056db7b67..4ad54eea1ea4 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -834,23 +834,17 @@ error:
834 * Replace a process's session keyring on behalf of one of its children when 834 * Replace a process's session keyring on behalf of one of its children when
835 * the target process is about to resume userspace execution. 835 * the target process is about to resume userspace execution.
836 */ 836 */
837void key_replace_session_keyring(void) 837void key_change_session_keyring(struct task_work *twork)
838{ 838{
839 const struct cred *old; 839 const struct cred *old = current_cred();
840 struct cred *new; 840 struct cred *new = twork->data;
841
842 if (!current->replacement_session_keyring)
843 return;
844 841
845 write_lock_irq(&tasklist_lock); 842 kfree(twork);
846 new = current->replacement_session_keyring; 843 if (unlikely(current->flags & PF_EXITING)) {
847 current->replacement_session_keyring = NULL; 844 put_cred(new);
848 write_unlock_irq(&tasklist_lock);
849
850 if (!new)
851 return; 845 return;
846 }
852 847
853 old = current_cred();
854 new-> uid = old-> uid; 848 new-> uid = old-> uid;
855 new-> euid = old-> euid; 849 new-> euid = old-> euid;
856 new-> suid = old-> suid; 850 new-> suid = old-> suid;
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index cc3790315d2f..000e75017520 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -93,16 +93,9 @@ static void umh_keys_cleanup(struct subprocess_info *info)
93static int call_usermodehelper_keys(char *path, char **argv, char **envp, 93static int call_usermodehelper_keys(char *path, char **argv, char **envp,
94 struct key *session_keyring, int wait) 94 struct key *session_keyring, int wait)
95{ 95{
96 gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL; 96 return call_usermodehelper_fns(path, argv, envp, wait,
97 struct subprocess_info *info = 97 umh_keys_init, umh_keys_cleanup,
98 call_usermodehelper_setup(path, argv, envp, gfp_mask); 98 key_get(session_keyring));
99
100 if (!info)
101 return -ENOMEM;
102
103 call_usermodehelper_setfns(info, umh_keys_init, umh_keys_cleanup,
104 key_get(session_keyring));
105 return call_usermodehelper_exec(info, wait);
106} 99}
107 100
108/* 101/*