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

Commit 18240904 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-linus3' of...

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
parents f86054c2 8a478905
Loading
Loading
Loading
Loading
+8 −5
Original line number Diff line number Diff line
@@ -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 (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;
}
+9 −0
Original line number Diff line number Diff line
@@ -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 */
+2 −1
Original line number Diff line number Diff line
@@ -147,6 +147,7 @@ static void put_cred_rcu(struct rcu_head *rcu)
	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);
	kmem_cache_free(cred_jar, cred);
+51 −27
Original line number Diff line number Diff line
@@ -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]");
}
+2 −2
Original line number Diff line number Diff line
@@ -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);
Loading