Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris: "A quiet cycle for the security subsystem with just a few maintenance updates." * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: Smack: create a sysfs mount point for smackfs Smack: use select not depends in Kconfig Yama: remove locking from delete path Yama: add RCU to drop read locking drivers/char/tpm: remove tasklet and cleanup KEYS: Use keyring_alloc() to create special keyrings KEYS: Reduce initial permissions on keys KEYS: Make the session and process keyrings per-thread seccomp: Make syscall skipping and nr changes more consistent key: Fix resource leak keys: Fix unreachable code KEYS: Add payload preparsing opportunity prior to key instantiate or update
This commit is contained in:
commit
2a74dbb9a8
20 changed files with 369 additions and 370 deletions
127
kernel/cred.c
127
kernel/cred.c
|
@ -29,17 +29,6 @@
|
|||
|
||||
static struct kmem_cache *cred_jar;
|
||||
|
||||
/*
|
||||
* 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(init_cred.tgcred.lock),
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The initial credentials for the initial task
|
||||
*/
|
||||
|
@ -65,9 +54,6 @@ struct cred init_cred = {
|
|||
.user = INIT_USER,
|
||||
.user_ns = &init_user_ns,
|
||||
.group_info = &init_groups,
|
||||
#ifdef CONFIG_KEYS
|
||||
.tgcred = &init_tgcred,
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline void set_cred_subscribers(struct cred *cred, int n)
|
||||
|
@ -95,36 +81,6 @@ static inline void alter_cred_subscribers(const struct cred *_cred, int n)
|
|||
#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
|
||||
*/
|
||||
|
@ -150,9 +106,10 @@ static void put_cred_rcu(struct rcu_head *rcu)
|
|||
#endif
|
||||
|
||||
security_cred_free(cred);
|
||||
key_put(cred->session_keyring);
|
||||
key_put(cred->process_keyring);
|
||||
key_put(cred->thread_keyring);
|
||||
key_put(cred->request_key_auth);
|
||||
release_tgcred(cred);
|
||||
if (cred->group_info)
|
||||
put_group_info(cred->group_info);
|
||||
free_uid(cred->user);
|
||||
|
@ -246,15 +203,6 @@ struct cred *cred_alloc_blank(void)
|
|||
if (!new)
|
||||
return NULL;
|
||||
|
||||
#ifdef CONFIG_KEYS
|
||||
new->tgcred = kzalloc(sizeof(*new->tgcred), GFP_KERNEL);
|
||||
if (!new->tgcred) {
|
||||
kmem_cache_free(cred_jar, new);
|
||||
return NULL;
|
||||
}
|
||||
atomic_set(&new->tgcred->usage, 1);
|
||||
#endif
|
||||
|
||||
atomic_set(&new->usage, 1);
|
||||
#ifdef CONFIG_DEBUG_CREDENTIALS
|
||||
new->magic = CRED_MAGIC;
|
||||
|
@ -308,9 +256,10 @@ struct cred *prepare_creds(void)
|
|||
get_user_ns(new->user_ns);
|
||||
|
||||
#ifdef CONFIG_KEYS
|
||||
key_get(new->session_keyring);
|
||||
key_get(new->process_keyring);
|
||||
key_get(new->thread_keyring);
|
||||
key_get(new->request_key_auth);
|
||||
atomic_inc(&new->tgcred->usage);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURITY
|
||||
|
@ -334,39 +283,20 @@ EXPORT_SYMBOL(prepare_creds);
|
|||
*/
|
||||
struct cred *prepare_exec_creds(void)
|
||||
{
|
||||
struct thread_group_cred *tgcred = NULL;
|
||||
struct cred *new;
|
||||
|
||||
#ifdef CONFIG_KEYS
|
||||
tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
|
||||
if (!tgcred)
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
new = prepare_creds();
|
||||
if (!new) {
|
||||
kfree(tgcred);
|
||||
if (!new)
|
||||
return new;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KEYS
|
||||
/* newly exec'd tasks don't get a thread keyring */
|
||||
key_put(new->thread_keyring);
|
||||
new->thread_keyring = NULL;
|
||||
|
||||
/* create a new per-thread-group creds for all this set of threads to
|
||||
* share */
|
||||
memcpy(tgcred, new->tgcred, sizeof(struct thread_group_cred));
|
||||
|
||||
atomic_set(&tgcred->usage, 1);
|
||||
spin_lock_init(&tgcred->lock);
|
||||
|
||||
/* inherit the session keyring; new process keyring */
|
||||
key_get(tgcred->session_keyring);
|
||||
tgcred->process_keyring = NULL;
|
||||
|
||||
release_tgcred(new);
|
||||
new->tgcred = tgcred;
|
||||
key_put(new->process_keyring);
|
||||
new->process_keyring = NULL;
|
||||
#endif
|
||||
|
||||
return new;
|
||||
|
@ -383,9 +313,6 @@ struct cred *prepare_exec_creds(void)
|
|||
*/
|
||||
int copy_creds(struct task_struct *p, unsigned long clone_flags)
|
||||
{
|
||||
#ifdef CONFIG_KEYS
|
||||
struct thread_group_cred *tgcred;
|
||||
#endif
|
||||
struct cred *new;
|
||||
int ret;
|
||||
|
||||
|
@ -425,22 +352,12 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
|
|||
install_thread_keyring_to_cred(new);
|
||||
}
|
||||
|
||||
/* we share the process and session keyrings between all the threads in
|
||||
* a process - this is slightly icky as we violate COW credentials a
|
||||
* bit */
|
||||
/* The process keyring is only shared between the threads in a process;
|
||||
* anything outside of those threads doesn't inherit.
|
||||
*/
|
||||
if (!(clone_flags & CLONE_THREAD)) {
|
||||
tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
|
||||
if (!tgcred) {
|
||||
ret = -ENOMEM;
|
||||
goto error_put;
|
||||
}
|
||||
atomic_set(&tgcred->usage, 1);
|
||||
spin_lock_init(&tgcred->lock);
|
||||
tgcred->process_keyring = NULL;
|
||||
tgcred->session_keyring = key_get(new->tgcred->session_keyring);
|
||||
|
||||
release_tgcred(new);
|
||||
new->tgcred = tgcred;
|
||||
key_put(new->process_keyring);
|
||||
new->process_keyring = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -643,9 +560,6 @@ void __init cred_init(void)
|
|||
*/
|
||||
struct cred *prepare_kernel_cred(struct task_struct *daemon)
|
||||
{
|
||||
#ifdef CONFIG_KEYS
|
||||
struct thread_group_cred *tgcred;
|
||||
#endif
|
||||
const struct cred *old;
|
||||
struct cred *new;
|
||||
|
||||
|
@ -653,14 +567,6 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
|
|||
if (!new)
|
||||
return NULL;
|
||||
|
||||
#ifdef CONFIG_KEYS
|
||||
tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
|
||||
if (!tgcred) {
|
||||
kmem_cache_free(cred_jar, new);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
kdebug("prepare_kernel_cred() alloc %p", new);
|
||||
|
||||
if (daemon)
|
||||
|
@ -678,13 +584,10 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
|
|||
get_group_info(new->group_info);
|
||||
|
||||
#ifdef CONFIG_KEYS
|
||||
atomic_set(&tgcred->usage, 1);
|
||||
spin_lock_init(&tgcred->lock);
|
||||
tgcred->process_keyring = NULL;
|
||||
tgcred->session_keyring = NULL;
|
||||
new->tgcred = tgcred;
|
||||
new->request_key_auth = NULL;
|
||||
new->session_keyring = NULL;
|
||||
new->process_keyring = NULL;
|
||||
new->thread_keyring = NULL;
|
||||
new->request_key_auth = NULL;
|
||||
new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -396,25 +396,29 @@ int __secure_computing(int this_syscall)
|
|||
#ifdef CONFIG_SECCOMP_FILTER
|
||||
case SECCOMP_MODE_FILTER: {
|
||||
int data;
|
||||
struct pt_regs *regs = task_pt_regs(current);
|
||||
ret = seccomp_run_filters(this_syscall);
|
||||
data = ret & SECCOMP_RET_DATA;
|
||||
ret &= SECCOMP_RET_ACTION;
|
||||
switch (ret) {
|
||||
case SECCOMP_RET_ERRNO:
|
||||
/* Set the low-order 16-bits as a errno. */
|
||||
syscall_set_return_value(current, task_pt_regs(current),
|
||||
syscall_set_return_value(current, regs,
|
||||
-data, 0);
|
||||
goto skip;
|
||||
case SECCOMP_RET_TRAP:
|
||||
/* Show the handler the original registers. */
|
||||
syscall_rollback(current, task_pt_regs(current));
|
||||
syscall_rollback(current, regs);
|
||||
/* Let the filter pass back 16 bits of data. */
|
||||
seccomp_send_sigsys(this_syscall, data);
|
||||
goto skip;
|
||||
case SECCOMP_RET_TRACE:
|
||||
/* Skip these calls if there is no tracer. */
|
||||
if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP))
|
||||
if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) {
|
||||
syscall_set_return_value(current, regs,
|
||||
-ENOSYS, 0);
|
||||
goto skip;
|
||||
}
|
||||
/* Allow the BPF to provide the event message */
|
||||
ptrace_event(PTRACE_EVENT_SECCOMP, data);
|
||||
/*
|
||||
|
@ -425,6 +429,9 @@ int __secure_computing(int this_syscall)
|
|||
*/
|
||||
if (fatal_signal_pending(current))
|
||||
break;
|
||||
if (syscall_get_nr(current, regs) < 0)
|
||||
goto skip; /* Explicit request to skip. */
|
||||
|
||||
return 0;
|
||||
case SECCOMP_RET_ALLOW:
|
||||
return 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue