Skip to content

Commit

Permalink
CRED: Separate per-task-group keyrings from signal_struct
Browse files Browse the repository at this point in the history
Separate per-task-group keyrings from signal_struct and dangle their anchor
from the cred struct rather than the signal_struct.

Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: James Morris <jmorris@namei.org>
Signed-off-by: James Morris <jmorris@namei.org>
  • Loading branch information
dhowells authored and James Morris committed Nov 13, 2008
1 parent 275bb41 commit bb952bb
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 99 deletions.
16 changes: 16 additions & 0 deletions include/linux/cred.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -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 */
Expand Down
8 changes: 2 additions & 6 deletions include/linux/key.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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; \
})

Expand All @@ -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)
Expand Down
6 changes: 0 additions & 6 deletions include/linux/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
63 changes: 63 additions & 0 deletions kernel/cred.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand All @@ -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
*/
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down
7 changes: 0 additions & 7 deletions kernel/fork.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
Expand Down
Loading

0 comments on commit bb952bb

Please sign in to comment.