mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-15 05:11:32 +00:00
Merge branch 'for-linus3' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6
* 'for-linus3' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: SELinux: inline selinux_is_enabled in !CONFIG_SECURITY_SELINUX KEYS: Fix garbage collector KEYS: Unlock tasklist when exiting early from keyctl_session_to_parent CRED: Allow put_cred() to cope with a NULL groups list SELinux: flush the avc before disabling SELinux SELinux: seperate avc_cache flushing Creds: creds->security can be NULL is selinux is disabled
This commit is contained in:
commit
1824090496
@ -15,6 +15,7 @@
|
||||
#include <linux/capability.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/key.h>
|
||||
#include <linux/selinux.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
struct user_struct;
|
||||
@ -182,11 +183,13 @@ static inline bool creds_are_invalid(const struct cred *cred)
|
||||
if (atomic_read(&cred->usage) < atomic_read(&cred->subscribers))
|
||||
return true;
|
||||
#ifdef CONFIG_SECURITY_SELINUX
|
||||
if ((unsigned long) cred->security < PAGE_SIZE)
|
||||
return true;
|
||||
if ((*(u32*)cred->security & 0xffffff00) ==
|
||||
(POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8))
|
||||
return true;
|
||||
if (selinux_is_enabled()) {
|
||||
if ((unsigned long) cred->security < PAGE_SIZE)
|
||||
return true;
|
||||
if ((*(u32 *)cred->security & 0xffffff00) ==
|
||||
(POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8))
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
@ -61,6 +61,11 @@ void selinux_secmark_refcount_inc(void);
|
||||
* existing SECMARK targets has been removed/flushed.
|
||||
*/
|
||||
void selinux_secmark_refcount_dec(void);
|
||||
|
||||
/**
|
||||
* selinux_is_enabled - is SELinux enabled?
|
||||
*/
|
||||
bool selinux_is_enabled(void);
|
||||
#else
|
||||
|
||||
static inline int selinux_string_to_sid(const char *str, u32 *sid)
|
||||
@ -84,6 +89,10 @@ static inline void selinux_secmark_refcount_dec(void)
|
||||
return;
|
||||
}
|
||||
|
||||
static inline bool selinux_is_enabled(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_SECURITY_SELINUX */
|
||||
|
||||
#endif /* _LINUX_SELINUX_H */
|
||||
|
@ -147,7 +147,8 @@ 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);
|
||||
if (cred->group_info)
|
||||
put_group_info(cred->group_info);
|
||||
free_uid(cred->user);
|
||||
kmem_cache_free(cred_jar, cred);
|
||||
}
|
||||
|
@ -26,8 +26,10 @@ static void key_garbage_collector(struct work_struct *);
|
||||
static DEFINE_TIMER(key_gc_timer, key_gc_timer_func, 0, 0);
|
||||
static DECLARE_WORK(key_gc_work, key_garbage_collector);
|
||||
static key_serial_t key_gc_cursor; /* the last key the gc considered */
|
||||
static bool key_gc_again;
|
||||
static unsigned long key_gc_executing;
|
||||
static time_t key_gc_next_run = LONG_MAX;
|
||||
static time_t key_gc_new_timer;
|
||||
|
||||
/*
|
||||
* Schedule a garbage collection run
|
||||
@ -40,9 +42,7 @@ void key_schedule_gc(time_t gc_at)
|
||||
|
||||
kenter("%ld", gc_at - now);
|
||||
|
||||
gc_at += key_gc_delay;
|
||||
|
||||
if (now >= gc_at) {
|
||||
if (gc_at <= now) {
|
||||
schedule_work(&key_gc_work);
|
||||
} else if (gc_at < key_gc_next_run) {
|
||||
expires = jiffies + (gc_at - now) * HZ;
|
||||
@ -112,16 +112,18 @@ static void key_garbage_collector(struct work_struct *work)
|
||||
struct rb_node *rb;
|
||||
key_serial_t cursor;
|
||||
struct key *key, *xkey;
|
||||
time_t new_timer = LONG_MAX, limit;
|
||||
time_t new_timer = LONG_MAX, limit, now;
|
||||
|
||||
kenter("");
|
||||
now = current_kernel_time().tv_sec;
|
||||
kenter("[%x,%ld]", key_gc_cursor, key_gc_new_timer - now);
|
||||
|
||||
if (test_and_set_bit(0, &key_gc_executing)) {
|
||||
key_schedule_gc(current_kernel_time().tv_sec);
|
||||
key_schedule_gc(current_kernel_time().tv_sec + 1);
|
||||
kleave(" [busy; deferring]");
|
||||
return;
|
||||
}
|
||||
|
||||
limit = current_kernel_time().tv_sec;
|
||||
limit = now;
|
||||
if (limit > key_gc_delay)
|
||||
limit -= key_gc_delay;
|
||||
else
|
||||
@ -129,12 +131,19 @@ static void key_garbage_collector(struct work_struct *work)
|
||||
|
||||
spin_lock(&key_serial_lock);
|
||||
|
||||
if (RB_EMPTY_ROOT(&key_serial_tree))
|
||||
goto reached_the_end;
|
||||
if (unlikely(RB_EMPTY_ROOT(&key_serial_tree))) {
|
||||
spin_unlock(&key_serial_lock);
|
||||
clear_bit(0, &key_gc_executing);
|
||||
return;
|
||||
}
|
||||
|
||||
cursor = key_gc_cursor;
|
||||
if (cursor < 0)
|
||||
cursor = 0;
|
||||
if (cursor > 0)
|
||||
new_timer = key_gc_new_timer;
|
||||
else
|
||||
key_gc_again = false;
|
||||
|
||||
/* find the first key above the cursor */
|
||||
key = NULL;
|
||||
@ -160,35 +169,50 @@ static void key_garbage_collector(struct work_struct *work)
|
||||
|
||||
/* trawl through the keys looking for keyrings */
|
||||
for (;;) {
|
||||
if (key->expiry > 0 && key->expiry < new_timer)
|
||||
if (key->expiry > now && key->expiry < new_timer) {
|
||||
kdebug("will expire %x in %ld",
|
||||
key_serial(key), key->expiry - now);
|
||||
new_timer = key->expiry;
|
||||
}
|
||||
|
||||
if (key->type == &key_type_keyring &&
|
||||
key_gc_keyring(key, limit)) {
|
||||
/* the gc ate our lock */
|
||||
schedule_work(&key_gc_work);
|
||||
goto no_unlock;
|
||||
}
|
||||
key_gc_keyring(key, limit))
|
||||
/* the gc had to release our lock so that the keyring
|
||||
* could be modified, so we have to get it again */
|
||||
goto gc_released_our_lock;
|
||||
|
||||
rb = rb_next(&key->serial_node);
|
||||
if (!rb) {
|
||||
key_gc_cursor = 0;
|
||||
break;
|
||||
}
|
||||
if (!rb)
|
||||
goto reached_the_end;
|
||||
key = rb_entry(rb, struct key, serial_node);
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock(&key_serial_lock);
|
||||
no_unlock:
|
||||
gc_released_our_lock:
|
||||
kdebug("gc_released_our_lock");
|
||||
key_gc_new_timer = new_timer;
|
||||
key_gc_again = true;
|
||||
clear_bit(0, &key_gc_executing);
|
||||
if (new_timer < LONG_MAX)
|
||||
key_schedule_gc(new_timer);
|
||||
|
||||
kleave("");
|
||||
schedule_work(&key_gc_work);
|
||||
kleave(" [continue]");
|
||||
return;
|
||||
|
||||
/* when we reach the end of the run, we set the timer for the next one */
|
||||
reached_the_end:
|
||||
kdebug("reached_the_end");
|
||||
spin_unlock(&key_serial_lock);
|
||||
key_gc_new_timer = new_timer;
|
||||
key_gc_cursor = 0;
|
||||
goto out;
|
||||
clear_bit(0, &key_gc_executing);
|
||||
|
||||
if (key_gc_again) {
|
||||
/* there may have been a key that expired whilst we were
|
||||
* scanning, so if we discarded any links we should do another
|
||||
* scan */
|
||||
new_timer = now + 1;
|
||||
key_schedule_gc(new_timer);
|
||||
} else if (new_timer < LONG_MAX) {
|
||||
new_timer += key_gc_delay;
|
||||
key_schedule_gc(new_timer);
|
||||
}
|
||||
kleave(" [end]");
|
||||
}
|
||||
|
@ -500,7 +500,7 @@ int key_negate_and_link(struct key *key,
|
||||
set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
|
||||
now = current_kernel_time();
|
||||
key->expiry = now.tv_sec + timeout;
|
||||
key_schedule_gc(key->expiry);
|
||||
key_schedule_gc(key->expiry + key_gc_delay);
|
||||
|
||||
if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
|
||||
awaken = 1;
|
||||
@ -909,7 +909,7 @@ void key_revoke(struct key *key)
|
||||
time = now.tv_sec;
|
||||
if (key->revoked_at == 0 || key->revoked_at > time) {
|
||||
key->revoked_at = time;
|
||||
key_schedule_gc(key->revoked_at);
|
||||
key_schedule_gc(key->revoked_at + key_gc_delay);
|
||||
}
|
||||
|
||||
up_write(&key->sem);
|
||||
|
@ -1115,7 +1115,7 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout)
|
||||
}
|
||||
|
||||
key->expiry = expiry;
|
||||
key_schedule_gc(key->expiry);
|
||||
key_schedule_gc(key->expiry + key_gc_delay);
|
||||
|
||||
up_write(&key->sem);
|
||||
key_put(key);
|
||||
@ -1319,6 +1319,7 @@ long keyctl_session_to_parent(void)
|
||||
already_same:
|
||||
ret = 0;
|
||||
not_permitted:
|
||||
write_unlock_irq(&tasklist_lock);
|
||||
put_cred(cred);
|
||||
return ret;
|
||||
|
||||
|
@ -1019,18 +1019,18 @@ void keyring_gc(struct key *keyring, time_t limit)
|
||||
struct key *key;
|
||||
int loop, keep, max;
|
||||
|
||||
kenter("%x", key_serial(keyring));
|
||||
kenter("{%x,%s}", key_serial(keyring), keyring->description);
|
||||
|
||||
down_write(&keyring->sem);
|
||||
|
||||
klist = keyring->payload.subscriptions;
|
||||
if (!klist)
|
||||
goto just_return;
|
||||
goto no_klist;
|
||||
|
||||
/* work out how many subscriptions we're keeping */
|
||||
keep = 0;
|
||||
for (loop = klist->nkeys - 1; loop >= 0; loop--)
|
||||
if (!key_is_dead(klist->keys[loop], limit));
|
||||
if (!key_is_dead(klist->keys[loop], limit))
|
||||
keep++;
|
||||
|
||||
if (keep == klist->nkeys)
|
||||
@ -1041,7 +1041,7 @@ void keyring_gc(struct key *keyring, time_t limit)
|
||||
new = kmalloc(sizeof(struct keyring_list) + max * sizeof(struct key *),
|
||||
GFP_KERNEL);
|
||||
if (!new)
|
||||
goto just_return;
|
||||
goto nomem;
|
||||
new->maxkeys = max;
|
||||
new->nkeys = 0;
|
||||
new->delkey = 0;
|
||||
@ -1081,7 +1081,21 @@ void keyring_gc(struct key *keyring, time_t limit)
|
||||
discard_new:
|
||||
new->nkeys = keep;
|
||||
keyring_clear_rcu_disposal(&new->rcu);
|
||||
up_write(&keyring->sem);
|
||||
kleave(" [discard]");
|
||||
return;
|
||||
|
||||
just_return:
|
||||
up_write(&keyring->sem);
|
||||
kleave(" [no]");
|
||||
kleave(" [no dead]");
|
||||
return;
|
||||
|
||||
no_klist:
|
||||
up_write(&keyring->sem);
|
||||
kleave(" [no_klist]");
|
||||
return;
|
||||
|
||||
nomem:
|
||||
up_write(&keyring->sem);
|
||||
kleave(" [oom]");
|
||||
}
|
||||
|
@ -709,18 +709,16 @@ out:
|
||||
}
|
||||
|
||||
/**
|
||||
* avc_ss_reset - Flush the cache and revalidate migrated permissions.
|
||||
* @seqno: policy sequence number
|
||||
* avc_flush - Flush the cache
|
||||
*/
|
||||
int avc_ss_reset(u32 seqno)
|
||||
static void avc_flush(void)
|
||||
{
|
||||
struct avc_callback_node *c;
|
||||
int i, rc = 0, tmprc;
|
||||
unsigned long flag;
|
||||
struct avc_node *node;
|
||||
struct hlist_head *head;
|
||||
struct hlist_node *next;
|
||||
struct avc_node *node;
|
||||
spinlock_t *lock;
|
||||
unsigned long flag;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AVC_CACHE_SLOTS; i++) {
|
||||
head = &avc_cache.slots[i];
|
||||
@ -737,6 +735,18 @@ int avc_ss_reset(u32 seqno)
|
||||
rcu_read_unlock();
|
||||
spin_unlock_irqrestore(lock, flag);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* avc_ss_reset - Flush the cache and revalidate migrated permissions.
|
||||
* @seqno: policy sequence number
|
||||
*/
|
||||
int avc_ss_reset(u32 seqno)
|
||||
{
|
||||
struct avc_callback_node *c;
|
||||
int rc = 0, tmprc;
|
||||
|
||||
avc_flush();
|
||||
|
||||
for (c = avc_callbacks; c; c = c->next) {
|
||||
if (c->events & AVC_CALLBACK_RESET) {
|
||||
@ -858,6 +868,8 @@ u32 avc_policy_seqno(void)
|
||||
|
||||
void avc_disable(void)
|
||||
{
|
||||
avc_flush();
|
||||
synchronize_rcu();
|
||||
if (avc_node_cachep)
|
||||
kmem_cache_destroy(avc_node_cachep);
|
||||
}
|
||||
|
@ -63,3 +63,9 @@ void selinux_secmark_refcount_dec(void)
|
||||
atomic_dec(&selinux_secmark_refcount);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(selinux_secmark_refcount_dec);
|
||||
|
||||
bool selinux_is_enabled(void)
|
||||
{
|
||||
return selinux_enabled;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(selinux_is_enabled);
|
||||
|
Loading…
Reference in New Issue
Block a user