aboutsummaryrefslogtreecommitdiffstats
path: root/security/keys/keyctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/keys/keyctl.c')
-rw-r--r--security/keys/keyctl.c77
1 files changed, 37 insertions, 40 deletions
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index b61c063888b9..3bdc419b272f 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/*