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: Baolin Wang <baolin.wang@linaro.org>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: James Morris <james.l.morris@oracle.com>
This commit is contained in:
Baolin Wang 2017-11-15 16:38:45 +00:00 committed by David Howells
parent be543dd626
commit 074d589895
8 changed files with 47 additions and 55 deletions

View File

@ -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 */

View File

@ -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);
}

View File

@ -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) |

View File

@ -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);

View File

@ -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;

View File

@ -89,7 +89,7 @@ EXPORT_SYMBOL(key_task_permission);
int key_validate(const struct key *key)
{
unsigned long flags = READ_ONCE(key->flags);
time_t expiry = READ_ONCE(key->expiry);
time64_t expiry = READ_ONCE(key->expiry);
if (flags & (1 << KEY_FLAG_INVALIDATED))
return -ENOKEY;
@ -101,8 +101,7 @@ int key_validate(const struct key *key)
/* check it hasn't expired */
if (expiry) {
struct timespec now = current_kernel_time();
if (now.tv_sec >= expiry)
if (ktime_get_real_seconds() >= expiry)
return -EKEYEXPIRED;
}

View File

@ -178,13 +178,12 @@ static int proc_keys_show(struct seq_file *m, void *v)
{
struct rb_node *_p = v;
struct key *key = rb_entry(_p, struct key, serial_node);
struct timespec now;
time_t expiry;
unsigned long timo;
unsigned long flags;
key_ref_t key_ref, skey_ref;
time64_t now, expiry;
char xbuf[16];
short state;
u64 timo;
int rc;
struct keyring_search_context ctx = {
@ -215,7 +214,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
if (rc < 0)
return 0;
now = current_kernel_time();
now = ktime_get_real_seconds();
rcu_read_lock();
@ -223,21 +222,21 @@ static int proc_keys_show(struct seq_file *m, void *v)
expiry = READ_ONCE(key->expiry);
if (expiry == 0) {
memcpy(xbuf, "perm", 5);
} else if (now.tv_sec >= expiry) {
} else if (now >= expiry) {
memcpy(xbuf, "expd", 5);
} else {
timo = expiry - now.tv_sec;
timo = expiry - now;
if (timo < 60)
sprintf(xbuf, "%lus", timo);
sprintf(xbuf, "%llus", timo);
else if (timo < 60*60)
sprintf(xbuf, "%lum", timo / 60);
sprintf(xbuf, "%llum", div_u64(timo, 60));
else if (timo < 60*60*24)
sprintf(xbuf, "%luh", timo / (60*60));
sprintf(xbuf, "%lluh", div_u64(timo, 60 * 60));
else if (timo < 60*60*24*7)
sprintf(xbuf, "%lud", timo / (60*60*24));
sprintf(xbuf, "%llud", div_u64(timo, 60 * 60 * 24));
else
sprintf(xbuf, "%luw", timo / (60*60*24*7));
sprintf(xbuf, "%lluw", div_u64(timo, 60 * 60 * 24 * 7));
}
state = key_read_state(key);

View File

@ -738,7 +738,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
if (ret < 0)
goto invalid_key;
key->last_used_at = current_kernel_time().tv_sec;
key->last_used_at = ktime_get_real_seconds();
error:
put_cred(ctx.cred);