diff options
Diffstat (limited to 'security/keys/process_keys.c')
| -rw-r--r-- | security/keys/process_keys.c | 90 | 
1 files changed, 38 insertions, 52 deletions
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 86468f385fc..58dfe089094 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -45,10 +45,12 @@ int install_user_keyrings(void)  	struct user_struct *user;  	const struct cred *cred;  	struct key *uid_keyring, *session_keyring; +	key_perm_t user_keyring_perm;  	char buf[20];  	int ret;  	uid_t uid; +	user_keyring_perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL;  	cred = current_cred();  	user = cred->user;  	uid = from_kuid(cred->user_ns, user->uid); @@ -73,8 +75,8 @@ int install_user_keyrings(void)  		uid_keyring = find_keyring_by_name(buf, true);  		if (IS_ERR(uid_keyring)) {  			uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID, -						    cred, KEY_ALLOC_IN_QUOTA, -						    NULL); +						    cred, user_keyring_perm, +						    KEY_ALLOC_IN_QUOTA, NULL);  			if (IS_ERR(uid_keyring)) {  				ret = PTR_ERR(uid_keyring);  				goto error; @@ -89,7 +91,8 @@ int install_user_keyrings(void)  		if (IS_ERR(session_keyring)) {  			session_keyring =  				keyring_alloc(buf, user->uid, INVALID_GID, -					      cred, KEY_ALLOC_IN_QUOTA, NULL); +					      cred, user_keyring_perm, +					      KEY_ALLOC_IN_QUOTA, NULL);  			if (IS_ERR(session_keyring)) {  				ret = PTR_ERR(session_keyring);  				goto error_release; @@ -130,6 +133,7 @@ int install_thread_keyring_to_cred(struct cred *new)  	struct key *keyring;  	keyring = keyring_alloc("_tid", new->uid, new->gid, new, +				KEY_POS_ALL | KEY_USR_VIEW,  				KEY_ALLOC_QUOTA_OVERRUN, NULL);  	if (IS_ERR(keyring))  		return PTR_ERR(keyring); @@ -170,27 +174,18 @@ static int install_thread_keyring(void)  int install_process_keyring_to_cred(struct cred *new)  {  	struct key *keyring; -	int ret; -	if (new->tgcred->process_keyring) +	if (new->process_keyring)  		return -EEXIST; -	keyring = keyring_alloc("_pid", new->uid, new->gid, -				new, KEY_ALLOC_QUOTA_OVERRUN, NULL); +	keyring = keyring_alloc("_pid", new->uid, new->gid, new, +				KEY_POS_ALL | KEY_USR_VIEW, +				KEY_ALLOC_QUOTA_OVERRUN, NULL);  	if (IS_ERR(keyring))  		return PTR_ERR(keyring); -	spin_lock_irq(&new->tgcred->lock); -	if (!new->tgcred->process_keyring) { -		new->tgcred->process_keyring = keyring; -		keyring = NULL; -		ret = 0; -	} else { -		ret = -EEXIST; -	} -	spin_unlock_irq(&new->tgcred->lock); -	key_put(keyring); -	return ret; +	new->process_keyring = keyring; +	return 0;  }  /* @@ -231,11 +226,12 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)  	/* create an empty session keyring */  	if (!keyring) {  		flags = KEY_ALLOC_QUOTA_OVERRUN; -		if (cred->tgcred->session_keyring) +		if (cred->session_keyring)  			flags = KEY_ALLOC_IN_QUOTA; -		keyring = keyring_alloc("_ses", cred->uid, cred->gid, -					cred, flags, NULL); +		keyring = keyring_alloc("_ses", cred->uid, cred->gid, cred, +					KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ, +					flags, NULL);  		if (IS_ERR(keyring))  			return PTR_ERR(keyring);  	} else { @@ -243,17 +239,11 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)  	}  	/* install the keyring */ -	spin_lock_irq(&cred->tgcred->lock); -	old = cred->tgcred->session_keyring; -	rcu_assign_pointer(cred->tgcred->session_keyring, keyring); -	spin_unlock_irq(&cred->tgcred->lock); +	old = cred->session_keyring; +	rcu_assign_pointer(cred->session_keyring, keyring); -	/* we're using RCU on the pointer, but there's no point synchronising -	 * on it if it didn't previously point to anything */ -	if (old) { -		synchronize_rcu(); +	if (old)  		key_put(old); -	}  	return 0;  } @@ -368,9 +358,9 @@ key_ref_t search_my_process_keyrings(struct key_type *type,  	}  	/* search the process keyring second */ -	if (cred->tgcred->process_keyring) { +	if (cred->process_keyring) {  		key_ref = keyring_search_aux( -			make_key_ref(cred->tgcred->process_keyring, 1), +			make_key_ref(cred->process_keyring, 1),  			cred, type, description, match, no_state_check);  		if (!IS_ERR(key_ref))  			goto found; @@ -389,12 +379,10 @@ key_ref_t search_my_process_keyrings(struct key_type *type,  	}  	/* search the session keyring */ -	if (cred->tgcred->session_keyring) { +	if (cred->session_keyring) {  		rcu_read_lock();  		key_ref = keyring_search_aux( -			make_key_ref(rcu_dereference( -					     cred->tgcred->session_keyring), -				     1), +			make_key_ref(rcu_dereference(cred->session_keyring), 1),  			cred, type, description, match, no_state_check);  		rcu_read_unlock(); @@ -564,7 +552,7 @@ try_again:  		break;  	case KEY_SPEC_PROCESS_KEYRING: -		if (!cred->tgcred->process_keyring) { +		if (!cred->process_keyring) {  			if (!(lflags & KEY_LOOKUP_CREATE))  				goto error; @@ -576,13 +564,13 @@ try_again:  			goto reget_creds;  		} -		key = cred->tgcred->process_keyring; +		key = cred->process_keyring;  		atomic_inc(&key->usage);  		key_ref = make_key_ref(key, 1);  		break;  	case KEY_SPEC_SESSION_KEYRING: -		if (!cred->tgcred->session_keyring) { +		if (!cred->session_keyring) {  			/* always install a session keyring upon access if one  			 * doesn't exist yet */  			ret = install_user_keyrings(); @@ -597,7 +585,7 @@ try_again:  			if (ret < 0)  				goto error;  			goto reget_creds; -		} else if (cred->tgcred->session_keyring == +		} else if (cred->session_keyring ==  			   cred->user->session_keyring &&  			   lflags & KEY_LOOKUP_CREATE) {  			ret = join_session_keyring(NULL); @@ -607,7 +595,7 @@ try_again:  		}  		rcu_read_lock(); -		key = rcu_dereference(cred->tgcred->session_keyring); +		key = rcu_dereference(cred->session_keyring);  		atomic_inc(&key->usage);  		rcu_read_unlock();  		key_ref = make_key_ref(key, 1); @@ -767,12 +755,6 @@ long join_session_keyring(const char *name)  	struct key *keyring;  	long ret, serial; -	/* only permit this if there's a single thread in the thread group - -	 * this avoids us having to adjust the creds on all threads and risking -	 * ENOMEM */ -	if (!current_is_single_threaded()) -		return -EMLINK; -  	new = prepare_creds();  	if (!new)  		return -ENOMEM; @@ -784,7 +766,7 @@ long join_session_keyring(const char *name)  		if (ret < 0)  			goto error; -		serial = new->tgcred->session_keyring->serial; +		serial = new->session_keyring->serial;  		ret = commit_creds(new);  		if (ret == 0)  			ret = serial; @@ -798,8 +780,10 @@ long join_session_keyring(const char *name)  	keyring = find_keyring_by_name(name, false);  	if (PTR_ERR(keyring) == -ENOKEY) {  		/* not found - try and create a new one */ -		keyring = keyring_alloc(name, old->uid, old->gid, old, -					KEY_ALLOC_IN_QUOTA, NULL); +		keyring = keyring_alloc( +			name, old->uid, old->gid, old, +			KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_LINK, +			KEY_ALLOC_IN_QUOTA, NULL);  		if (IS_ERR(keyring)) {  			ret = PTR_ERR(keyring);  			goto error2; @@ -807,6 +791,9 @@ long join_session_keyring(const char *name)  	} else if (IS_ERR(keyring)) {  		ret = PTR_ERR(keyring);  		goto error2; +	} else if (keyring == new->session_keyring) { +		ret = 0; +		goto error2;  	}  	/* we've got a keyring - now to install it */ @@ -863,8 +850,7 @@ void key_change_session_keyring(struct callback_head *twork)  	new->jit_keyring	= old->jit_keyring;  	new->thread_keyring	= key_get(old->thread_keyring); -	new->tgcred->tgid	= old->tgcred->tgid; -	new->tgcred->process_keyring = key_get(old->tgcred->process_keyring); +	new->process_keyring	= key_get(old->process_keyring);  	security_transfer_creds(new, old);  |