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

Commit 074d5898 authored by Baolin Wang's avatar Baolin Wang Committed by David Howells
Browse files

security: keys: Replace time_t/timespec with time64_t



The 'struct key' will use 'time_t' which we try to remove in the
kernel, since 'time_t' is not year 2038 safe on 32bit systems.
Also the 'struct keyring_search_context' will use 'timespec' type
to record current time, which is also not year 2038 safe on 32bit
systems.

Thus this patch replaces 'time_t' with 'time64_t' which is year 2038
safe for 'struct key', and replace 'timespec' with 'time64_t' for the
'struct keyring_search_context', since we only look at the the seconds
part of 'timespec' variable. Moreover we also change the codes where
using the 'time_t' and 'timespec', and we can get current time by
ktime_get_real_seconds() instead of current_kernel_time(), and use
'TIME64_MAX' macro to initialize the 'time64_t' type variable.

Especially in proc.c file, we have replaced 'unsigned long' and 'timespec'
type with 'u64' and 'time64_t' type to save the timeout value, which means
user will get one 'u64' type timeout value by issuing proc_keys_show()
function.

Signed-off-by: default avatarBaolin Wang <baolin.wang@linaro.org>
Reviewed-by: default avatarArnd Bergmann <arnd@arndb.de>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Reviewed-by: default avatarJames Morris <james.l.morris@oracle.com>
parent be543dd6
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <linux/atomic.h>
#include <linux/assoc_array.h>
#include <linux/refcount.h>
#include <linux/time64.h>

#ifdef __KERNEL__
#include <linux/uidgid.h>
@@ -162,10 +163,10 @@ struct key {
	struct key_user		*user;		/* owner of this key */
	void			*security;	/* security data for this key */
	union {
		time_t		expiry;		/* time at which key expires (or 0) */
		time_t		revoked_at;	/* time at which key was revoked */
		time64_t	expiry;		/* time at which key expires (or 0) */
		time64_t	revoked_at;	/* time at which key was revoked */
	};
	time_t			last_used_at;	/* last time used for LRU keyring discard */
	time64_t		last_used_at;	/* last time used for LRU keyring discard */
	kuid_t			uid;
	kgid_t			gid;
	key_perm_t		perm;		/* access permissions */
+10 −10
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ DECLARE_WORK(key_gc_work, key_garbage_collector);
static void key_gc_timer_func(unsigned long);
static DEFINE_TIMER(key_gc_timer, key_gc_timer_func);

static time_t key_gc_next_run = LONG_MAX;
static time64_t key_gc_next_run = TIME64_MAX;
static struct key_type *key_gc_dead_keytype;

static unsigned long key_gc_flags;
@@ -53,12 +53,12 @@ struct key_type key_type_dead = {
 * Schedule a garbage collection run.
 * - time precision isn't particularly important
 */
void key_schedule_gc(time_t gc_at)
void key_schedule_gc(time64_t gc_at)
{
	unsigned long expires;
	time_t now = current_kernel_time().tv_sec;
	time64_t now = ktime_get_real_seconds();

	kenter("%ld", gc_at - now);
	kenter("%lld", gc_at - now);

	if (gc_at <= now || test_bit(KEY_GC_REAP_KEYTYPE, &key_gc_flags)) {
		kdebug("IMMEDIATE");
@@ -87,7 +87,7 @@ void key_schedule_gc_links(void)
static void key_gc_timer_func(unsigned long data)
{
	kenter("");
	key_gc_next_run = LONG_MAX;
	key_gc_next_run = TIME64_MAX;
	key_schedule_gc_links();
}

@@ -184,11 +184,11 @@ static void key_garbage_collector(struct work_struct *work)

	struct rb_node *cursor;
	struct key *key;
	time_t new_timer, limit;
	time64_t new_timer, limit;

	kenter("[%lx,%x]", key_gc_flags, gc_state);

	limit = current_kernel_time().tv_sec;
	limit = ktime_get_real_seconds();
	if (limit > key_gc_delay)
		limit -= key_gc_delay;
	else
@@ -204,7 +204,7 @@ static void key_garbage_collector(struct work_struct *work)
		gc_state |= KEY_GC_REAPING_DEAD_1;
	kdebug("new pass %x", gc_state);

	new_timer = LONG_MAX;
	new_timer = TIME64_MAX;

	/* As only this function is permitted to remove things from the key
	 * serial tree, if cursor is non-NULL then it will always point to a
@@ -235,7 +235,7 @@ static void key_garbage_collector(struct work_struct *work)

		if (gc_state & KEY_GC_SET_TIMER) {
			if (key->expiry > limit && key->expiry < new_timer) {
				kdebug("will expire %x in %ld",
				kdebug("will expire %x in %lld",
				       key_serial(key), key->expiry - limit);
				new_timer = key->expiry;
			}
@@ -276,7 +276,7 @@ static void key_garbage_collector(struct work_struct *work)
	 */
	kdebug("pass complete");

	if (gc_state & KEY_GC_SET_TIMER && new_timer != (time_t)LONG_MAX) {
	if (gc_state & KEY_GC_SET_TIMER && new_timer != (time64_t)TIME64_MAX) {
		new_timer += key_gc_delay;
		key_schedule_gc(new_timer);
	}
+4 −4
Original line number Diff line number Diff line
@@ -130,7 +130,7 @@ struct keyring_search_context {
	int			skipped_ret;
	bool			possessed;
	key_ref_t		result;
	struct timespec		now;
	time64_t		now;
};

extern bool key_default_cmp(const struct key *key,
@@ -169,10 +169,10 @@ extern void key_change_session_keyring(struct callback_head *twork);

extern struct work_struct key_gc_work;
extern unsigned key_gc_delay;
extern void keyring_gc(struct key *keyring, time_t limit);
extern void keyring_gc(struct key *keyring, time64_t limit);
extern void keyring_restriction_gc(struct key *keyring,
				   struct key_type *dead_type);
extern void key_schedule_gc(time_t gc_at);
extern void key_schedule_gc(time64_t gc_at);
extern void key_schedule_gc_links(void);
extern void key_gc_keytype(struct key_type *ktype);

@@ -211,7 +211,7 @@ extern struct key *key_get_instantiation_authkey(key_serial_t target_id);
/*
 * Determine whether a key is dead.
 */
static inline bool key_is_dead(const struct key *key, time_t limit)
static inline bool key_is_dead(const struct key *key, time64_t limit)
{
	return
		key->flags & ((1 << KEY_FLAG_DEAD) |
+6 −13
Original line number Diff line number Diff line
@@ -570,7 +570,6 @@ int key_reject_and_link(struct key *key,
			struct key *authkey)
{
	struct assoc_array_edit *edit;
	struct timespec now;
	int ret, awaken, link_ret = 0;

	key_check(key);
@@ -593,8 +592,7 @@ int key_reject_and_link(struct key *key,
		/* mark the key as being negatively instantiated */
		atomic_inc(&key->user->nikeys);
		mark_key_instantiated(key, -error);
		now = current_kernel_time();
		key->expiry = now.tv_sec + timeout;
		key->expiry = ktime_get_real_seconds() + timeout;
		key_schedule_gc(key->expiry + key_gc_delay);

		if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
@@ -710,16 +708,13 @@ struct key_type *key_type_lookup(const char *type)

void key_set_timeout(struct key *key, unsigned timeout)
{
	struct timespec now;
	time_t expiry = 0;
	time64_t expiry = 0;

	/* make the changes with the locks held to prevent races */
	down_write(&key->sem);

	if (timeout > 0) {
		now = current_kernel_time();
		expiry = now.tv_sec + timeout;
	}
	if (timeout > 0)
		expiry = ktime_get_real_seconds() + timeout;

	key->expiry = expiry;
	key_schedule_gc(key->expiry + key_gc_delay);
@@ -1028,8 +1023,7 @@ EXPORT_SYMBOL(key_update);
 */
void key_revoke(struct key *key)
{
	struct timespec now;
	time_t time;
	time64_t time;

	key_check(key);

@@ -1044,8 +1038,7 @@ void key_revoke(struct key *key)
		key->type->revoke(key);

	/* set the death time to no more than the expiry time */
	now = current_kernel_time();
	time = now.tv_sec;
	time = ktime_get_real_seconds();
	if (key->revoked_at == 0 || key->revoked_at > time) {
		key->revoked_at = time;
		key_schedule_gc(key->revoked_at + key_gc_delay);
+10 −10
Original line number Diff line number Diff line
@@ -565,7 +565,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data)

	/* skip invalidated, revoked and expired keys */
	if (ctx->flags & KEYRING_SEARCH_DO_STATE_CHECK) {
		time_t expiry = READ_ONCE(key->expiry);
		time64_t expiry = READ_ONCE(key->expiry);

		if (kflags & ((1 << KEY_FLAG_INVALIDATED) |
			      (1 << KEY_FLAG_REVOKED))) {
@@ -574,7 +574,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data)
			goto skipped;
		}

		if (expiry && ctx->now.tv_sec >= expiry) {
		if (expiry && ctx->now >= expiry) {
			if (!(ctx->flags & KEYRING_SEARCH_SKIP_EXPIRED))
				ctx->result = ERR_PTR(-EKEYEXPIRED);
			kleave(" = %d [expire]", ctx->skipped_ret);
@@ -834,10 +834,10 @@ static bool search_nested_keyrings(struct key *keyring,
	key = key_ref_to_ptr(ctx->result);
	key_check(key);
	if (!(ctx->flags & KEYRING_SEARCH_NO_UPDATE_TIME)) {
		key->last_used_at = ctx->now.tv_sec;
		keyring->last_used_at = ctx->now.tv_sec;
		key->last_used_at = ctx->now;
		keyring->last_used_at = ctx->now;
		while (sp > 0)
			stack[--sp].keyring->last_used_at = ctx->now.tv_sec;
			stack[--sp].keyring->last_used_at = ctx->now;
	}
	kleave(" = true");
	return true;
@@ -898,7 +898,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
	}

	rcu_read_lock();
	ctx->now = current_kernel_time();
	ctx->now = ktime_get_real_seconds();
	if (search_nested_keyrings(keyring, ctx))
		__key_get(key_ref_to_ptr(ctx->result));
	rcu_read_unlock();
@@ -1149,7 +1149,7 @@ struct key *find_keyring_by_name(const char *name, bool uid_keyring)
			 * (ie. it has a zero usage count) */
			if (!refcount_inc_not_zero(&keyring->usage))
				continue;
			keyring->last_used_at = current_kernel_time().tv_sec;
			keyring->last_used_at = ktime_get_real_seconds();
			goto out;
		}
	}
@@ -1489,7 +1489,7 @@ static void keyring_revoke(struct key *keyring)
static bool keyring_gc_select_iterator(void *object, void *iterator_data)
{
	struct key *key = keyring_ptr_to_key(object);
	time_t *limit = iterator_data;
	time64_t *limit = iterator_data;

	if (key_is_dead(key, *limit))
		return false;
@@ -1500,7 +1500,7 @@ static bool keyring_gc_select_iterator(void *object, void *iterator_data)
static int keyring_gc_check_iterator(const void *object, void *iterator_data)
{
	const struct key *key = keyring_ptr_to_key(object);
	time_t *limit = iterator_data;
	time64_t *limit = iterator_data;

	key_check(key);
	return key_is_dead(key, *limit);
@@ -1512,7 +1512,7 @@ static int keyring_gc_check_iterator(const void *object, void *iterator_data)
 * Not called with any locks held.  The keyring's key struct will not be
 * deallocated under us as only our caller may deallocate it.
 */
void keyring_gc(struct key *keyring, time_t limit)
void keyring_gc(struct key *keyring, time64_t limit)
{
	int result;

Loading