Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bb952bb9 authored by David Howells's avatar David Howells Committed by James Morris
Browse files

CRED: Separate per-task-group keyrings from signal_struct



Separate per-task-group keyrings from signal_struct and dangle their anchor
from the cred struct rather than the signal_struct.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Reviewed-by: default avatarJames Morris <jmorris@namei.org>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent 275bb41e
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -71,6 +71,21 @@ extern int groups_search(const struct group_info *, gid_t);
extern int in_group_p(gid_t);
extern int in_egroup_p(gid_t);

/*
 * The common credentials for a thread group
 * - shared by CLONE_THREAD
 */
#ifdef CONFIG_KEYS
struct thread_group_cred {
	atomic_t	usage;
	pid_t		tgid;			/* thread group process ID */
	spinlock_t	lock;
	struct key	*session_keyring;	/* keyring inherited over fork */
	struct key	*process_keyring;	/* keyring private to this process */
	struct rcu_head	rcu;			/* RCU deletion hook */
};
#endif

/*
 * The security context of a task
 *
@@ -114,6 +129,7 @@ struct cred {
					 * keys to */
	struct key	*thread_keyring; /* keyring private to this thread */
	struct key	*request_key_auth; /* assumed request_key authority */
	struct thread_group_cred *tgcred; /* thread-group shared credentials */
#endif
#ifdef CONFIG_SECURITY
	void		*security;	/* subjective LSM security */
+2 −6
Original line number Diff line number Diff line
@@ -278,9 +278,7 @@ extern ctl_table key_sysctls[];
 */
extern void switch_uid_keyring(struct user_struct *new_user);
extern int copy_keys(unsigned long clone_flags, struct task_struct *tsk);
extern int copy_thread_group_keys(struct task_struct *tsk);
extern void exit_keys(struct task_struct *tsk);
extern void exit_thread_group_keys(struct signal_struct *tg);
extern int suid_keys(struct task_struct *tsk);
extern int exec_keys(struct task_struct *tsk);
extern void key_fsuid_changed(struct task_struct *tsk);
@@ -289,8 +287,8 @@ extern void key_init(void);

#define __install_session_keyring(keyring)				\
({									\
	struct key *old_session = current->signal->session_keyring;	\
	current->signal->session_keyring = keyring;			\
	struct key *old_session = current->cred->tgcred->session_keyring; \
	current->cred->tgcred->session_keyring = keyring;		\
	old_session;							\
})

@@ -308,9 +306,7 @@ extern void key_init(void);
#define switch_uid_keyring(u)		do { } while(0)
#define __install_session_keyring(k)	({ NULL; })
#define copy_keys(f,t)			0
#define copy_thread_group_keys(t)	0
#define exit_keys(t)			do { } while(0)
#define exit_thread_group_keys(tg)	do { } while(0)
#define suid_keys(t)			do { } while(0)
#define exec_keys(t)			do { } while(0)
#define key_fsuid_changed(t)		do { } while(0)
+0 −6
Original line number Diff line number Diff line
@@ -571,12 +571,6 @@ struct signal_struct {
	 */
	struct rlimit rlim[RLIM_NLIMITS];

	/* keep the process-shared keyrings here so that they do the right
	 * thing in threads created with CLONE_THREAD */
#ifdef CONFIG_KEYS
	struct key *session_keyring;	/* keyring inherited over fork */
	struct key *process_keyring;	/* keyring private to this process */
#endif
#ifdef CONFIG_BSD_PROCESS_ACCT
	struct pacct_struct pacct;	/* per-process accounting information */
#endif
+63 −0
Original line number Diff line number Diff line
@@ -16,6 +16,17 @@
#include <linux/init_task.h>
#include <linux/security.h>

/*
 * The common credentials for the initial task's thread group
 */
#ifdef CONFIG_KEYS
static struct thread_group_cred init_tgcred = {
	.usage	= ATOMIC_INIT(2),
	.tgid	= 0,
	.lock	= SPIN_LOCK_UNLOCKED,
};
#endif

/*
 * The initial credentials for the initial task
 */
@@ -28,8 +39,41 @@ struct cred init_cred = {
	.cap_bset		= CAP_INIT_BSET,
	.user			= INIT_USER,
	.group_info		= &init_groups,
#ifdef CONFIG_KEYS
	.tgcred			= &init_tgcred,
#endif
};

/*
 * Dispose of the shared task group credentials
 */
#ifdef CONFIG_KEYS
static void release_tgcred_rcu(struct rcu_head *rcu)
{
	struct thread_group_cred *tgcred =
		container_of(rcu, struct thread_group_cred, rcu);

	BUG_ON(atomic_read(&tgcred->usage) != 0);

	key_put(tgcred->session_keyring);
	key_put(tgcred->process_keyring);
	kfree(tgcred);
}
#endif

/*
 * Release a set of thread group credentials.
 */
static void release_tgcred(struct cred *cred)
{
#ifdef CONFIG_KEYS
	struct thread_group_cred *tgcred = cred->tgcred;

	if (atomic_dec_and_test(&tgcred->usage))
		call_rcu(&tgcred->rcu, release_tgcred_rcu);
#endif
}

/*
 * The RCU callback to actually dispose of a set of credentials
 */
@@ -41,6 +85,7 @@ static void put_cred_rcu(struct rcu_head *rcu)

	key_put(cred->thread_keyring);
	key_put(cred->request_key_auth);
	release_tgcred(cred);
	put_group_info(cred->group_info);
	free_uid(cred->user);
	security_cred_free(cred);
@@ -71,12 +116,30 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
	if (!pcred)
		return -ENOMEM;

#ifdef CONFIG_KEYS
	if (clone_flags & CLONE_THREAD) {
		atomic_inc(&pcred->tgcred->usage);
	} else {
		pcred->tgcred = kmalloc(sizeof(struct cred), GFP_KERNEL);
		if (!pcred->tgcred) {
			kfree(pcred);
			return -ENOMEM;
		}
		atomic_set(&pcred->tgcred->usage, 1);
		spin_lock_init(&pcred->tgcred->lock);
		pcred->tgcred->process_keyring = NULL;
		pcred->tgcred->session_keyring =
			key_get(p->cred->tgcred->session_keyring);
	}
#endif

#ifdef CONFIG_SECURITY
	pcred->security = NULL;
#endif

	ret = security_cred_alloc(pcred);
	if (ret < 0) {
		release_tgcred(pcred);
		kfree(pcred);
		return ret;
	}
+0 −7
Original line number Diff line number Diff line
@@ -802,12 +802,6 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
	if (!sig)
		return -ENOMEM;

	ret = copy_thread_group_keys(tsk);
	if (ret < 0) {
		kmem_cache_free(signal_cachep, sig);
		return ret;
	}

	atomic_set(&sig->count, 1);
	atomic_set(&sig->live, 1);
	init_waitqueue_head(&sig->wait_chldexit);
@@ -852,7 +846,6 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
void __cleanup_signal(struct signal_struct *sig)
{
	thread_group_cputime_free(sig);
	exit_thread_group_keys(sig);
	tty_kref_put(sig->tty);
	kmem_cache_free(signal_cachep, sig);
}
Loading