lkml.org 
[lkml]   [2017]   [Apr]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.9 03/21] KEYS: fix keyctl_set_reqkey_keyring() to not leak thread keyrings
    Date
    4.9-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Eric Biggers <ebiggers@google.com>

    commit c9f838d104fed6f2f61d68164712e3204bf5271b upstream.

    This fixes CVE-2017-7472.

    Running the following program as an unprivileged user exhausts kernel
    memory by leaking thread keyrings:

    #include <keyutils.h>

    int main()
    {
    for (;;)
    keyctl_set_reqkey_keyring(KEY_REQKEY_DEFL_THREAD_KEYRING);
    }

    Fix it by only creating a new thread keyring if there wasn't one before.
    To make things more consistent, make install_thread_keyring_to_cred()
    and install_process_keyring_to_cred() both return 0 if the corresponding
    keyring is already present.

    Fixes: d84f4f992cbd ("CRED: Inaugurate COW credentials")
    Signed-off-by: Eric Biggers <ebiggers@google.com>
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    security/keys/keyctl.c | 11 +++-------
    security/keys/process_keys.c | 44 ++++++++++++++++++++++++++-----------------
    2 files changed, 31 insertions(+), 24 deletions(-)

    --- a/security/keys/keyctl.c
    +++ b/security/keys/keyctl.c
    @@ -1256,8 +1256,8 @@ error:
    * Read or set the default keyring in which request_key() will cache keys and
    * return the old setting.
    *
    - * If a process keyring is specified then this will be created if it doesn't
    - * yet exist. The old setting will be returned if successful.
    + * If a thread or process keyring is specified then it will be created if it
    + * doesn't yet exist. The old setting will be returned if successful.
    */
    long keyctl_set_reqkey_keyring(int reqkey_defl)
    {
    @@ -1282,11 +1282,8 @@ long keyctl_set_reqkey_keyring(int reqke

    case KEY_REQKEY_DEFL_PROCESS_KEYRING:
    ret = install_process_keyring_to_cred(new);
    - if (ret < 0) {
    - if (ret != -EEXIST)
    - goto error;
    - ret = 0;
    - }
    + if (ret < 0)
    + goto error;
    goto set;

    case KEY_REQKEY_DEFL_DEFAULT:
    --- a/security/keys/process_keys.c
    +++ b/security/keys/process_keys.c
    @@ -127,13 +127,18 @@ error:
    }

    /*
    - * Install a fresh thread keyring directly to new credentials. This keyring is
    - * allowed to overrun the quota.
    + * Install a thread keyring to the given credentials struct if it didn't have
    + * one already. This is allowed to overrun the quota.
    + *
    + * Return: 0 if a thread keyring is now present; -errno on failure.
    */
    int install_thread_keyring_to_cred(struct cred *new)
    {
    struct key *keyring;

    + if (new->thread_keyring)
    + return 0;
    +
    keyring = keyring_alloc("_tid", new->uid, new->gid, new,
    KEY_POS_ALL | KEY_USR_VIEW,
    KEY_ALLOC_QUOTA_OVERRUN,
    @@ -146,7 +151,9 @@ int install_thread_keyring_to_cred(struc
    }

    /*
    - * Install a fresh thread keyring, discarding the old one.
    + * Install a thread keyring to the current task if it didn't have one already.
    + *
    + * Return: 0 if a thread keyring is now present; -errno on failure.
    */
    static int install_thread_keyring(void)
    {
    @@ -157,8 +164,6 @@ static int install_thread_keyring(void)
    if (!new)
    return -ENOMEM;

    - BUG_ON(new->thread_keyring);
    -
    ret = install_thread_keyring_to_cred(new);
    if (ret < 0) {
    abort_creds(new);
    @@ -169,17 +174,17 @@ static int install_thread_keyring(void)
    }

    /*
    - * Install a process keyring directly to a credentials struct.
    + * Install a process keyring to the given credentials struct if it didn't have
    + * one already. This is allowed to overrun the quota.
    *
    - * Returns -EEXIST if there was already a process keyring, 0 if one installed,
    - * and other value on any other error
    + * Return: 0 if a process keyring is now present; -errno on failure.
    */
    int install_process_keyring_to_cred(struct cred *new)
    {
    struct key *keyring;

    if (new->process_keyring)
    - return -EEXIST;
    + return 0;

    keyring = keyring_alloc("_pid", new->uid, new->gid, new,
    KEY_POS_ALL | KEY_USR_VIEW,
    @@ -193,11 +198,9 @@ int install_process_keyring_to_cred(stru
    }

    /*
    - * Make sure a process keyring is installed for the current process. The
    - * existing process keyring is not replaced.
    + * Install a process keyring to the current task if it didn't have one already.
    *
    - * Returns 0 if there is a process keyring by the end of this function, some
    - * error otherwise.
    + * Return: 0 if a process keyring is now present; -errno on failure.
    */
    static int install_process_keyring(void)
    {
    @@ -211,14 +214,18 @@ static int install_process_keyring(void)
    ret = install_process_keyring_to_cred(new);
    if (ret < 0) {
    abort_creds(new);
    - return ret != -EEXIST ? ret : 0;
    + return ret;
    }

    return commit_creds(new);
    }

    /*
    - * Install a session keyring directly to a credentials struct.
    + * Install the given keyring as the session keyring of the given credentials
    + * struct, replacing the existing one if any. If the given keyring is NULL,
    + * then install a new anonymous session keyring.
    + *
    + * Return: 0 on success; -errno on failure.
    */
    int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
    {
    @@ -253,8 +260,11 @@ int install_session_keyring_to_cred(stru
    }

    /*
    - * Install a session keyring, discarding the old one. If a keyring is not
    - * supplied, an empty one is invented.
    + * Install the given keyring as the session keyring of the current task,
    + * replacing the existing one if any. If the given keyring is NULL, then
    + * install a new anonymous session keyring.
    + *
    + * Return: 0 on success; -errno on failure.
    */
    static int install_session_keyring(struct key *keyring)
    {

    \
     
     \ /
      Last update: 2017-04-25 17:28    [W:4.624 / U:0.008 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site