/*****************************************************************************/
/*
- * install a fresh process keyring, discarding the old one
+ * make sure a process keyring is installed
*/
static int install_process_keyring(struct task_struct *tsk)
{
- struct key *keyring, *old;
+ unsigned long flags;
+ struct key *keyring;
char buf[20];
int ret;
- sprintf(buf, "_pid.%u", tsk->tgid);
+ if (!tsk->signal->process_keyring) {
+ sprintf(buf, "_pid.%u", tsk->tgid);
- keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
- if (IS_ERR(keyring)) {
- ret = PTR_ERR(keyring);
- goto error;
- }
+ keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
+ if (IS_ERR(keyring)) {
+ ret = PTR_ERR(keyring);
+ goto error;
+ }
- task_lock(tsk);
- old = tsk->process_keyring;
- tsk->process_keyring = keyring;
- task_unlock(tsk);
+ /* attach or swap keyrings */
+ spin_lock_irqsave(&tsk->sighand->siglock, flags);
+ if (!tsk->signal->process_keyring) {
+ tsk->signal->process_keyring = keyring;
+ keyring = NULL;
+ }
+ spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
- ret = 0;
+ key_put(keyring);
+ }
- key_put(old);
+ ret = 0;
error:
return ret;
static int install_session_keyring(struct task_struct *tsk,
struct key *keyring)
{
+ unsigned long flags;
struct key *old;
char buf[20];
int ret;
}
/* install the keyring */
- task_lock(tsk);
- old = tsk->session_keyring;
- tsk->session_keyring = keyring;
- task_unlock(tsk);
+ spin_lock_irqsave(&tsk->sighand->siglock, flags);
+ old = tsk->signal->session_keyring;
+ tsk->signal->session_keyring = keyring;
+ spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
ret = 0;
/*****************************************************************************/
/*
- * copy the keys for fork
+ * copy the keys in a thread group for fork without CLONE_THREAD
*/
-int copy_keys(unsigned long clone_flags, struct task_struct *tsk)
+int copy_thread_group_keys(struct task_struct *tsk)
{
- int ret = 0;
+ unsigned long flags;
- key_check(tsk->session_keyring);
- key_check(tsk->process_keyring);
- key_check(tsk->thread_keyring);
+ key_check(current->thread_group->session_keyring);
+ key_check(current->thread_group->process_keyring);
- if (tsk->session_keyring)
- atomic_inc(&tsk->session_keyring->usage);
+ /* no process keyring yet */
+ tsk->signal->process_keyring = NULL;
- if (tsk->process_keyring) {
- if (clone_flags & CLONE_THREAD) {
- atomic_inc(&tsk->process_keyring->usage);
- }
- else {
- tsk->process_keyring = NULL;
- ret = install_process_keyring(tsk);
- }
- }
+ /* same session keyring */
+ spin_lock_irqsave(¤t->sighand->siglock, flags);
+ tsk->signal->session_keyring =
+ key_get(current->signal->session_keyring);
+ spin_unlock_irqrestore(¤t->sighand->siglock, flags);
+
+ return 0;
+} /* end copy_thread_group_keys() */
+
+/*****************************************************************************/
+/*
+ * copy the keys for fork
+ */
+int copy_keys(unsigned long clone_flags, struct task_struct *tsk)
+{
+ key_check(tsk->thread_keyring);
+
+ /* no thread keyring yet */
tsk->thread_keyring = NULL;
- return ret;
+ return 0;
} /* end copy_keys() */
/*****************************************************************************/
/*
- * dispose of keys upon exit
+ * dispose of thread group keys upon thread group destruction
+ */
+void exit_thread_group_keys(struct signal_struct *tg)
+{
+ key_put(tg->session_keyring);
+ key_put(tg->process_keyring);
+
+} /* end exit_thread_group_keys() */
+
+/*****************************************************************************/
+/*
+ * dispose of keys upon thread exit
*/
void exit_keys(struct task_struct *tsk)
{
- key_put(tsk->session_keyring);
- key_put(tsk->process_keyring);
key_put(tsk->thread_keyring);
} /* end exit_keys() */
*/
int exec_keys(struct task_struct *tsk)
{
+ unsigned long flags;
struct key *old;
/* newly exec'd tasks don't get a thread keyring */
key_put(old);
- /* newly exec'd tasks get a fresh process keyring */
- return install_process_keyring(tsk);
+ /* discard the process keyring from a newly exec'd task */
+ spin_lock_irqsave(&tsk->sighand->siglock, flags);
+ old = tsk->signal->process_keyring;
+ tsk->signal->process_keyring = NULL;
+ spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+
+ key_put(old);
+
+ return 0;
} /* end exec_keys() */
*/
void key_fsuid_changed(struct task_struct *tsk)
{
- /* update the ownership of the process keyring */
- if (tsk->process_keyring) {
- down_write(&tsk->process_keyring->sem);
- write_lock(&tsk->process_keyring->lock);
- tsk->process_keyring->uid = tsk->fsuid;
- write_unlock(&tsk->process_keyring->lock);
- up_write(&tsk->process_keyring->sem);
- }
-
/* update the ownership of the thread keyring */
if (tsk->thread_keyring) {
down_write(&tsk->thread_keyring->sem);
*/
void key_fsgid_changed(struct task_struct *tsk)
{
- /* update the ownership of the process keyring */
- if (tsk->process_keyring) {
- down_write(&tsk->process_keyring->sem);
- write_lock(&tsk->process_keyring->lock);
- tsk->process_keyring->gid = tsk->fsgid;
- write_unlock(&tsk->process_keyring->lock);
- up_write(&tsk->process_keyring->sem);
- }
-
/* update the ownership of the thread keyring */
if (tsk->thread_keyring) {
down_write(&tsk->thread_keyring->sem);
key_match_func_t match)
{
struct task_struct *tsk = current;
- struct key *key, *ret, *err, *session;
+ unsigned long flags;
+ struct key *key, *ret, *err, *tmp;
/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
* searchable, but we failed to find a key or we found a negative key;
}
/* search the process keyring second */
- if (tsk->process_keyring) {
- key = keyring_search_aux(tsk->process_keyring, type,
- description, match);
+ if (tsk->signal->process_keyring) {
+ key = keyring_search_aux(tsk->signal->process_keyring,
+ type, description, match);
if (!IS_ERR(key))
goto found;
}
/* search the session keyring last */
- session = tsk->session_keyring;
- if (!session)
- session = tsk->user->session_keyring;
+ spin_lock_irqsave(&tsk->sighand->siglock, flags);
- key = keyring_search_aux(session, type,
- description, match);
+ tmp = tsk->signal->session_keyring;
+ if (!tmp)
+ tmp = tsk->user->session_keyring;
+ atomic_inc(&tmp->usage);
+
+ spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+
+ key = keyring_search_aux(tmp, type, description, match);
+ key_put(tmp);
if (!IS_ERR(key))
goto found;
key_perm_t perm)
{
struct task_struct *tsk = current;
+ unsigned long flags;
struct key *key;
int ret;
break;
case KEY_SPEC_PROCESS_KEYRING:
- if (!tsk->process_keyring) {
+ if (!tsk->signal->process_keyring) {
if (!create)
goto error;
}
}
- key = tsk->process_keyring;
+ key = tsk->signal->process_keyring;
atomic_inc(&key->usage);
break;
case KEY_SPEC_SESSION_KEYRING:
- if (!tsk->session_keyring) {
+ if (!tsk->signal->session_keyring) {
/* always install a session keyring upon access if one
* doesn't exist yet */
ret = install_session_keyring(
goto error;
}
- key = tsk->session_keyring;
+ spin_lock_irqsave(&tsk->sighand->siglock, flags);
+ key = tsk->signal->session_keyring;
atomic_inc(&key->usage);
+ spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
break;
case KEY_SPEC_USER_KEYRING:
long join_session_keyring(const char *name)
{
struct task_struct *tsk = current;
+ unsigned long flags;
struct key *keyring;
long ret;
if (ret < 0)
goto error;
- ret = tsk->session_keyring->serial;
+ spin_lock_irqsave(&tsk->sighand->siglock, flags);
+ ret = tsk->signal->session_keyring->serial;
+ spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
goto error;
}
if (ret < 0)
goto error2;
+ ret = keyring->serial;
key_put(keyring);
- ret = tsk->session_keyring->serial;
-
error2:
up(&key_session_sem);
error: