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:
parent
be543dd626
commit
074d589895
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) |
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue
Block a user