Merge branch 'next-keys' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security

Pull keys update from James Morris:
 "There's nothing too controversial here:

   - Doc fix for keyctl_read().

   - time_t -> time64_t replacement.

   - Set the module licence on things to prevent tainting"

* 'next-keys' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
  pkcs7: Set the module licence to prevent tainting
  security: keys: Replace time_t with time64_t for struct key_preparsed_payload
  security: keys: Replace time_t/timespec with time64_t
  KEYS: fix in-kernel documentation for keyctl_read()
This commit is contained in:
Linus Torvalds 2017-11-23 20:51:27 -10:00
commit dab0badc87
14 changed files with 66 additions and 65 deletions

View File

@ -628,12 +628,12 @@ The keyctl syscall functions are:
defined key type will return its data as is. If a key type does not defined key type will return its data as is. If a key type does not
implement this function, error EOPNOTSUPP will result. implement this function, error EOPNOTSUPP will result.
As much of the data as can be fitted into the buffer will be copied to If the specified buffer is too small, then the size of the buffer required
userspace if the buffer pointer is not NULL. will be returned. Note that in this case, the contents of the buffer may
have been overwritten in some undefined way.
On a successful return, the function will always return the amount of data
available rather than the amount copied.
Otherwise, on success, the function will return the amount of data copied
into the buffer.
* Instantiate a partially constructed key:: * Instantiate a partially constructed key::

View File

@ -19,6 +19,7 @@
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("PKCS#7 testing key type"); MODULE_DESCRIPTION("PKCS#7 testing key type");
MODULE_AUTHOR("Red Hat, Inc.");
static unsigned pkcs7_usage; static unsigned pkcs7_usage;
module_param_named(usage, pkcs7_usage, uint, S_IWUSR | S_IRUGO); module_param_named(usage, pkcs7_usage, uint, S_IWUSR | S_IRUGO);

View File

@ -11,6 +11,7 @@
#define pr_fmt(fmt) "PKCS7: "fmt #define pr_fmt(fmt) "PKCS7: "fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/err.h> #include <linux/err.h>
@ -19,6 +20,10 @@
#include "pkcs7_parser.h" #include "pkcs7_parser.h"
#include "pkcs7-asn1.h" #include "pkcs7-asn1.h"
MODULE_DESCRIPTION("PKCS#7 parser");
MODULE_AUTHOR("Red Hat, Inc.");
MODULE_LICENSE("GPL");
struct pkcs7_parse_context { struct pkcs7_parse_context {
struct pkcs7_message *msg; /* Message being constructed */ struct pkcs7_message *msg; /* Message being constructed */
struct pkcs7_signed_info *sinfo; /* SignedInfo being constructed */ struct pkcs7_signed_info *sinfo; /* SignedInfo being constructed */

View File

@ -22,6 +22,8 @@
#include <crypto/public_key.h> #include <crypto/public_key.h>
#include <crypto/akcipher.h> #include <crypto/akcipher.h>
MODULE_DESCRIPTION("In-software asymmetric public-key subtype");
MODULE_AUTHOR("Red Hat, Inc.");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/* /*

View File

@ -275,4 +275,5 @@ module_init(x509_key_init);
module_exit(x509_key_exit); module_exit(x509_key_exit);
MODULE_DESCRIPTION("X.509 certificate parser"); MODULE_DESCRIPTION("X.509 certificate parser");
MODULE_AUTHOR("Red Hat, Inc.");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View File

@ -44,7 +44,7 @@ struct key_preparsed_payload {
const void *data; /* Raw data */ const void *data; /* Raw data */
size_t datalen; /* Raw datalen */ size_t datalen; /* Raw datalen */
size_t quotalen; /* Quota length for proposed payload */ size_t quotalen; /* Quota length for proposed payload */
time_t expiry; /* Expiry time of key */ time64_t expiry; /* Expiry time of key */
} __randomize_layout; } __randomize_layout;
typedef int (*request_key_actor_t)(struct key_construction *key, typedef int (*request_key_actor_t)(struct key_construction *key,

View File

@ -24,6 +24,7 @@
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/assoc_array.h> #include <linux/assoc_array.h>
#include <linux/refcount.h> #include <linux/refcount.h>
#include <linux/time64.h>
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/uidgid.h> #include <linux/uidgid.h>
@ -162,10 +163,10 @@ struct key {
struct key_user *user; /* owner of this key */ struct key_user *user; /* owner of this key */
void *security; /* security data for this key */ void *security; /* security data for this key */
union { union {
time_t expiry; /* time at which key expires (or 0) */ time64_t expiry; /* time at which key expires (or 0) */
time_t revoked_at; /* time at which key was revoked */ 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; kuid_t uid;
kgid_t gid; kgid_t gid;
key_perm_t perm; /* access permissions */ 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 void key_gc_timer_func(unsigned long);
static DEFINE_TIMER(key_gc_timer, key_gc_timer_func); 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 struct key_type *key_gc_dead_keytype;
static unsigned long key_gc_flags; static unsigned long key_gc_flags;
@ -53,12 +53,12 @@ struct key_type key_type_dead = {
* Schedule a garbage collection run. * Schedule a garbage collection run.
* - time precision isn't particularly important * - 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; 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)) { if (gc_at <= now || test_bit(KEY_GC_REAP_KEYTYPE, &key_gc_flags)) {
kdebug("IMMEDIATE"); kdebug("IMMEDIATE");
@ -87,7 +87,7 @@ void key_schedule_gc_links(void)
static void key_gc_timer_func(unsigned long data) static void key_gc_timer_func(unsigned long data)
{ {
kenter(""); kenter("");
key_gc_next_run = LONG_MAX; key_gc_next_run = TIME64_MAX;
key_schedule_gc_links(); key_schedule_gc_links();
} }
@ -184,11 +184,11 @@ static void key_garbage_collector(struct work_struct *work)
struct rb_node *cursor; struct rb_node *cursor;
struct key *key; struct key *key;
time_t new_timer, limit; time64_t new_timer, limit;
kenter("[%lx,%x]", key_gc_flags, gc_state); kenter("[%lx,%x]", key_gc_flags, gc_state);
limit = current_kernel_time().tv_sec; limit = ktime_get_real_seconds();
if (limit > key_gc_delay) if (limit > key_gc_delay)
limit -= key_gc_delay; limit -= key_gc_delay;
else else
@ -204,7 +204,7 @@ static void key_garbage_collector(struct work_struct *work)
gc_state |= KEY_GC_REAPING_DEAD_1; gc_state |= KEY_GC_REAPING_DEAD_1;
kdebug("new pass %x", gc_state); 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 /* 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 * serial tree, if cursor is non-NULL then it will always point to a
@ -235,7 +235,7 @@ continue_scanning:
if (gc_state & KEY_GC_SET_TIMER) { if (gc_state & KEY_GC_SET_TIMER) {
if (key->expiry > limit && key->expiry < new_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); key_serial(key), key->expiry - limit);
new_timer = key->expiry; new_timer = key->expiry;
} }
@ -276,7 +276,7 @@ maybe_resched:
*/ */
kdebug("pass complete"); 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; new_timer += key_gc_delay;
key_schedule_gc(new_timer); key_schedule_gc(new_timer);
} }

View File

@ -130,7 +130,7 @@ struct keyring_search_context {
int skipped_ret; int skipped_ret;
bool possessed; bool possessed;
key_ref_t result; key_ref_t result;
struct timespec now; time64_t now;
}; };
extern bool key_default_cmp(const struct key *key, 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 struct work_struct key_gc_work;
extern unsigned key_gc_delay; 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, extern void keyring_restriction_gc(struct key *keyring,
struct key_type *dead_type); 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_schedule_gc_links(void);
extern void key_gc_keytype(struct key_type *ktype); 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. * 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 return
key->flags & ((1 << KEY_FLAG_DEAD) | key->flags & ((1 << KEY_FLAG_DEAD) |

View File

@ -460,7 +460,7 @@ static int __key_instantiate_and_link(struct key *key,
if (authkey) if (authkey)
key_revoke(authkey); key_revoke(authkey);
if (prep->expiry != TIME_T_MAX) { if (prep->expiry != TIME64_MAX) {
key->expiry = prep->expiry; key->expiry = prep->expiry;
key_schedule_gc(prep->expiry + key_gc_delay); key_schedule_gc(prep->expiry + key_gc_delay);
} }
@ -506,7 +506,7 @@ int key_instantiate_and_link(struct key *key,
prep.data = data; prep.data = data;
prep.datalen = datalen; prep.datalen = datalen;
prep.quotalen = key->type->def_datalen; prep.quotalen = key->type->def_datalen;
prep.expiry = TIME_T_MAX; prep.expiry = TIME64_MAX;
if (key->type->preparse) { if (key->type->preparse) {
ret = key->type->preparse(&prep); ret = key->type->preparse(&prep);
if (ret < 0) if (ret < 0)
@ -570,7 +570,6 @@ int key_reject_and_link(struct key *key,
struct key *authkey) struct key *authkey)
{ {
struct assoc_array_edit *edit; struct assoc_array_edit *edit;
struct timespec now;
int ret, awaken, link_ret = 0; int ret, awaken, link_ret = 0;
key_check(key); key_check(key);
@ -593,8 +592,7 @@ int key_reject_and_link(struct key *key,
/* mark the key as being negatively instantiated */ /* mark the key as being negatively instantiated */
atomic_inc(&key->user->nikeys); atomic_inc(&key->user->nikeys);
mark_key_instantiated(key, -error); mark_key_instantiated(key, -error);
now = current_kernel_time(); key->expiry = ktime_get_real_seconds() + timeout;
key->expiry = now.tv_sec + timeout;
key_schedule_gc(key->expiry + key_gc_delay); key_schedule_gc(key->expiry + key_gc_delay);
if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
@ -710,16 +708,13 @@ found_kernel_type:
void key_set_timeout(struct key *key, unsigned timeout) void key_set_timeout(struct key *key, unsigned timeout)
{ {
struct timespec now; time64_t expiry = 0;
time_t expiry = 0;
/* make the changes with the locks held to prevent races */ /* make the changes with the locks held to prevent races */
down_write(&key->sem); down_write(&key->sem);
if (timeout > 0) { if (timeout > 0)
now = current_kernel_time(); expiry = ktime_get_real_seconds() + timeout;
expiry = now.tv_sec + timeout;
}
key->expiry = expiry; key->expiry = expiry;
key_schedule_gc(key->expiry + key_gc_delay); key_schedule_gc(key->expiry + key_gc_delay);
@ -850,7 +845,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
prep.data = payload; prep.data = payload;
prep.datalen = plen; prep.datalen = plen;
prep.quotalen = index_key.type->def_datalen; prep.quotalen = index_key.type->def_datalen;
prep.expiry = TIME_T_MAX; prep.expiry = TIME64_MAX;
if (index_key.type->preparse) { if (index_key.type->preparse) {
ret = index_key.type->preparse(&prep); ret = index_key.type->preparse(&prep);
if (ret < 0) { if (ret < 0) {
@ -994,7 +989,7 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
prep.data = payload; prep.data = payload;
prep.datalen = plen; prep.datalen = plen;
prep.quotalen = key->type->def_datalen; prep.quotalen = key->type->def_datalen;
prep.expiry = TIME_T_MAX; prep.expiry = TIME64_MAX;
if (key->type->preparse) { if (key->type->preparse) {
ret = key->type->preparse(&prep); ret = key->type->preparse(&prep);
if (ret < 0) if (ret < 0)
@ -1028,8 +1023,7 @@ EXPORT_SYMBOL(key_update);
*/ */
void key_revoke(struct key *key) void key_revoke(struct key *key)
{ {
struct timespec now; time64_t time;
time_t time;
key_check(key); key_check(key);
@ -1044,8 +1038,7 @@ void key_revoke(struct key *key)
key->type->revoke(key); key->type->revoke(key);
/* set the death time to no more than the expiry time */ /* set the death time to no more than the expiry time */
now = current_kernel_time(); time = ktime_get_real_seconds();
time = now.tv_sec;
if (key->revoked_at == 0 || key->revoked_at > time) { if (key->revoked_at == 0 || key->revoked_at > time) {
key->revoked_at = time; key->revoked_at = time;
key_schedule_gc(key->revoked_at + key_gc_delay); 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 */ /* skip invalidated, revoked and expired keys */
if (ctx->flags & KEYRING_SEARCH_DO_STATE_CHECK) { 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) | if (kflags & ((1 << KEY_FLAG_INVALIDATED) |
(1 << KEY_FLAG_REVOKED))) { (1 << KEY_FLAG_REVOKED))) {
@ -574,7 +574,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data)
goto skipped; goto skipped;
} }
if (expiry && ctx->now.tv_sec >= expiry) { if (expiry && ctx->now >= expiry) {
if (!(ctx->flags & KEYRING_SEARCH_SKIP_EXPIRED)) if (!(ctx->flags & KEYRING_SEARCH_SKIP_EXPIRED))
ctx->result = ERR_PTR(-EKEYEXPIRED); ctx->result = ERR_PTR(-EKEYEXPIRED);
kleave(" = %d [expire]", ctx->skipped_ret); kleave(" = %d [expire]", ctx->skipped_ret);
@ -834,10 +834,10 @@ found:
key = key_ref_to_ptr(ctx->result); key = key_ref_to_ptr(ctx->result);
key_check(key); key_check(key);
if (!(ctx->flags & KEYRING_SEARCH_NO_UPDATE_TIME)) { if (!(ctx->flags & KEYRING_SEARCH_NO_UPDATE_TIME)) {
key->last_used_at = ctx->now.tv_sec; key->last_used_at = ctx->now;
keyring->last_used_at = ctx->now.tv_sec; keyring->last_used_at = ctx->now;
while (sp > 0) while (sp > 0)
stack[--sp].keyring->last_used_at = ctx->now.tv_sec; stack[--sp].keyring->last_used_at = ctx->now;
} }
kleave(" = true"); kleave(" = true");
return true; return true;
@ -898,7 +898,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
} }
rcu_read_lock(); rcu_read_lock();
ctx->now = current_kernel_time(); ctx->now = ktime_get_real_seconds();
if (search_nested_keyrings(keyring, ctx)) if (search_nested_keyrings(keyring, ctx))
__key_get(key_ref_to_ptr(ctx->result)); __key_get(key_ref_to_ptr(ctx->result));
rcu_read_unlock(); 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) */ * (ie. it has a zero usage count) */
if (!refcount_inc_not_zero(&keyring->usage)) if (!refcount_inc_not_zero(&keyring->usage))
continue; continue;
keyring->last_used_at = current_kernel_time().tv_sec; keyring->last_used_at = ktime_get_real_seconds();
goto out; goto out;
} }
} }
@ -1489,7 +1489,7 @@ static void keyring_revoke(struct key *keyring)
static bool keyring_gc_select_iterator(void *object, void *iterator_data) static bool keyring_gc_select_iterator(void *object, void *iterator_data)
{ {
struct key *key = keyring_ptr_to_key(object); struct key *key = keyring_ptr_to_key(object);
time_t *limit = iterator_data; time64_t *limit = iterator_data;
if (key_is_dead(key, *limit)) if (key_is_dead(key, *limit))
return false; 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) static int keyring_gc_check_iterator(const void *object, void *iterator_data)
{ {
const struct key *key = keyring_ptr_to_key(object); const struct key *key = keyring_ptr_to_key(object);
time_t *limit = iterator_data; time64_t *limit = iterator_data;
key_check(key); key_check(key);
return key_is_dead(key, *limit); 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 * Not called with any locks held. The keyring's key struct will not be
* deallocated under us as only our caller may deallocate it. * 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; int result;

View File

@ -89,7 +89,7 @@ EXPORT_SYMBOL(key_task_permission);
int key_validate(const struct key *key) int key_validate(const struct key *key)
{ {
unsigned long flags = READ_ONCE(key->flags); 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)) if (flags & (1 << KEY_FLAG_INVALIDATED))
return -ENOKEY; return -ENOKEY;
@ -101,8 +101,7 @@ int key_validate(const struct key *key)
/* check it hasn't expired */ /* check it hasn't expired */
if (expiry) { if (expiry) {
struct timespec now = current_kernel_time(); if (ktime_get_real_seconds() >= expiry)
if (now.tv_sec >= expiry)
return -EKEYEXPIRED; 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 rb_node *_p = v;
struct key *key = rb_entry(_p, struct key, serial_node); struct key *key = rb_entry(_p, struct key, serial_node);
struct timespec now;
time_t expiry;
unsigned long timo;
unsigned long flags; unsigned long flags;
key_ref_t key_ref, skey_ref; key_ref_t key_ref, skey_ref;
time64_t now, expiry;
char xbuf[16]; char xbuf[16];
short state; short state;
u64 timo;
int rc; int rc;
struct keyring_search_context ctx = { struct keyring_search_context ctx = {
@ -215,7 +214,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
if (rc < 0) if (rc < 0)
return 0; return 0;
now = current_kernel_time(); now = ktime_get_real_seconds();
rcu_read_lock(); rcu_read_lock();
@ -223,21 +222,21 @@ static int proc_keys_show(struct seq_file *m, void *v)
expiry = READ_ONCE(key->expiry); expiry = READ_ONCE(key->expiry);
if (expiry == 0) { if (expiry == 0) {
memcpy(xbuf, "perm", 5); memcpy(xbuf, "perm", 5);
} else if (now.tv_sec >= expiry) { } else if (now >= expiry) {
memcpy(xbuf, "expd", 5); memcpy(xbuf, "expd", 5);
} else { } else {
timo = expiry - now.tv_sec; timo = expiry - now;
if (timo < 60) if (timo < 60)
sprintf(xbuf, "%lus", timo); sprintf(xbuf, "%llus", timo);
else if (timo < 60*60) else if (timo < 60*60)
sprintf(xbuf, "%lum", timo / 60); sprintf(xbuf, "%llum", div_u64(timo, 60));
else if (timo < 60*60*24) 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) else if (timo < 60*60*24*7)
sprintf(xbuf, "%lud", timo / (60*60*24)); sprintf(xbuf, "%llud", div_u64(timo, 60 * 60 * 24));
else else
sprintf(xbuf, "%luw", timo / (60*60*24*7)); sprintf(xbuf, "%lluw", div_u64(timo, 60 * 60 * 24 * 7));
} }
state = key_read_state(key); state = key_read_state(key);

View File

@ -738,7 +738,7 @@ try_again:
if (ret < 0) if (ret < 0)
goto invalid_key; goto invalid_key;
key->last_used_at = current_kernel_time().tv_sec; key->last_used_at = ktime_get_real_seconds();
error: error:
put_cred(ctx.cred); put_cred(ctx.cred);