security: don't use RCU accessors for cred->session_keyring
sparse complains that a bunch of places in kernel/cred.c access cred->session_keyring without the RCU helpers required by the __rcu annotation. cred->session_keyring is written in the following places: - prepare_kernel_cred() [in a new cred struct] - keyctl_session_to_parent() [in a new cred struct] - prepare_creds [in a new cred struct, via memcpy] - install_session_keyring_to_cred() - from install_session_keyring() on new creds - from join_session_keyring() on new creds [twice] - from umh_keys_init() - from call_usermodehelper_exec_async() on new creds All of these writes are before the creds are committed; therefore, cred->session_keyring doesn't need RCU protection. Remove the __rcu annotation and fix up all existing users that use __rcu. Signed-off-by: Jann Horn <jannh@google.com> Signed-off-by: James Morris <james.morris@microsoft.com>
This commit is contained in:
@@ -138,7 +138,7 @@ struct cred {
|
|||||||
#ifdef CONFIG_KEYS
|
#ifdef CONFIG_KEYS
|
||||||
unsigned char jit_keyring; /* default keyring to attach requested
|
unsigned char jit_keyring; /* default keyring to attach requested
|
||||||
* keys to */
|
* keys to */
|
||||||
struct key __rcu *session_keyring; /* keyring inherited over fork */
|
struct key *session_keyring; /* keyring inherited over fork */
|
||||||
struct key *process_keyring; /* keyring private to this process */
|
struct key *process_keyring; /* keyring private to this process */
|
||||||
struct key *thread_keyring; /* keyring private to this thread */
|
struct key *thread_keyring; /* keyring private to this thread */
|
||||||
struct key *request_key_auth; /* assumed request_key authority */
|
struct key *request_key_auth; /* assumed request_key authority */
|
||||||
|
|||||||
@@ -227,6 +227,7 @@ static int install_process_keyring(void)
|
|||||||
* Install the given keyring as the session keyring of the given credentials
|
* 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,
|
* struct, replacing the existing one if any. If the given keyring is NULL,
|
||||||
* then install a new anonymous session keyring.
|
* then install a new anonymous session keyring.
|
||||||
|
* @cred can not be in use by any task yet.
|
||||||
*
|
*
|
||||||
* Return: 0 on success; -errno on failure.
|
* Return: 0 on success; -errno on failure.
|
||||||
*/
|
*/
|
||||||
@@ -254,7 +255,7 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
|
|||||||
|
|
||||||
/* install the keyring */
|
/* install the keyring */
|
||||||
old = cred->session_keyring;
|
old = cred->session_keyring;
|
||||||
rcu_assign_pointer(cred->session_keyring, keyring);
|
cred->session_keyring = keyring;
|
||||||
|
|
||||||
if (old)
|
if (old)
|
||||||
key_put(old);
|
key_put(old);
|
||||||
@@ -392,11 +393,8 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
|
|||||||
|
|
||||||
/* search the session keyring */
|
/* search the session keyring */
|
||||||
if (ctx->cred->session_keyring) {
|
if (ctx->cred->session_keyring) {
|
||||||
rcu_read_lock();
|
|
||||||
key_ref = keyring_search_aux(
|
key_ref = keyring_search_aux(
|
||||||
make_key_ref(rcu_dereference(ctx->cred->session_keyring), 1),
|
make_key_ref(ctx->cred->session_keyring, 1), ctx);
|
||||||
ctx);
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
if (!IS_ERR(key_ref))
|
if (!IS_ERR(key_ref))
|
||||||
goto found;
|
goto found;
|
||||||
@@ -612,10 +610,8 @@ try_again:
|
|||||||
goto reget_creds;
|
goto reget_creds;
|
||||||
}
|
}
|
||||||
|
|
||||||
rcu_read_lock();
|
key = ctx.cred->session_keyring;
|
||||||
key = rcu_dereference(ctx.cred->session_keyring);
|
|
||||||
__key_get(key);
|
__key_get(key);
|
||||||
rcu_read_unlock();
|
|
||||||
key_ref = make_key_ref(key, 1);
|
key_ref = make_key_ref(key, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -142,12 +142,10 @@ static int call_sbin_request_key(struct key *authkey, void *aux)
|
|||||||
prkey = cred->process_keyring->serial;
|
prkey = cred->process_keyring->serial;
|
||||||
sprintf(keyring_str[1], "%d", prkey);
|
sprintf(keyring_str[1], "%d", prkey);
|
||||||
|
|
||||||
rcu_read_lock();
|
session = cred->session_keyring;
|
||||||
session = rcu_dereference(cred->session_keyring);
|
|
||||||
if (!session)
|
if (!session)
|
||||||
session = cred->user->session_keyring;
|
session = cred->user->session_keyring;
|
||||||
sskey = session->serial;
|
sskey = session->serial;
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
sprintf(keyring_str[2], "%d", sskey);
|
sprintf(keyring_str[2], "%d", sskey);
|
||||||
|
|
||||||
@@ -287,10 +285,7 @@ static int construct_get_dest_keyring(struct key **_dest_keyring)
|
|||||||
|
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case KEY_REQKEY_DEFL_SESSION_KEYRING:
|
case KEY_REQKEY_DEFL_SESSION_KEYRING:
|
||||||
rcu_read_lock();
|
dest_keyring = key_get(cred->session_keyring);
|
||||||
dest_keyring = key_get(
|
|
||||||
rcu_dereference(cred->session_keyring));
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
if (dest_keyring)
|
if (dest_keyring)
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user