> +static inline void pks_update_protection(int pkey, unsigned long protection)
> +{
> +     current->thread.saved_pkrs = update_pkey_val(current->thread.saved_pkrs,
> +                                                  pkey, protection);
> +     preempt_disable();
> +     write_pkrs(current->thread.saved_pkrs);
> +     preempt_enable();
> +}

Why does this need preempt count manipulation in addition to the
get/put_cpu_var() inside of write_pkrs()?

> +/**
> + * PKS access control functions
> + *
> + * Change the access of the domain specified by the pkey.  These are global
> + * updates.  They only affects the current running thread.  It is undefined 
> and
> + * a bug for users to call this without having allocated a pkey and using it 
> as
> + * pkey here.
> + *
> + * pks_mknoaccess()
> + *     Disable all access to the domain
> + * pks_mkread()
> + *     Make the domain Read only
> + * pks_mkrdwr()
> + *     Make the domain Read/Write
> + *
> + * @pkey the pkey for which the access should change.
> + *
> + */
> +void pks_mknoaccess(int pkey)
> +{
> +     pks_update_protection(pkey, PKEY_DISABLE_ACCESS);
> +}
> +EXPORT_SYMBOL_GPL(pks_mknoaccess);

These are named like PTE manipulation functions, which is kinda weird.

What's wrong with: pks_disable_access(pkey) ?

> +void pks_mkread(int pkey)
> +{
> +     pks_update_protection(pkey, PKEY_DISABLE_WRITE);
> +}
> +EXPORT_SYMBOL_GPL(pks_mkread);

I really don't like this name.  It doesn't make readable, or even
read-only, *especially* if it was already access-disabled.

> +static const char pks_key_user0[] = "kernel";
> +
> +/* Store names of allocated keys for debug.  Key 0 is reserved for the 
> kernel.  */
> +static const char *pks_key_users[PKS_NUM_KEYS] = {
> +     pks_key_user0
> +};
> +
> +/*
> + * Each key is represented by a bit.  Bit 0 is set for key 0 and reserved for
> + * its use.  We use ulong for the bit operations but only 16 bits are used.
> + */
> +static unsigned long pks_key_allocation_map = 1 << PKS_KERN_DEFAULT_KEY;
> +
> +/*
> + * pks_key_alloc - Allocate a PKS key
> + *
> + * @pkey_user: String stored for debugging of key exhaustion.  The caller is
> + * responsible to maintain this memory until pks_key_free().
> + */
> +int pks_key_alloc(const char * const pkey_user)
> +{
> +     int nr;
> +
> +     if (!cpu_feature_enabled(X86_FEATURE_PKS))
> +             return -EINVAL;

I'm not sure I like -EINVAL for this.  I thought we returned -ENOSPC for
this case for user pkeys.

> +     while (1) {
> +             nr = find_first_zero_bit(&pks_key_allocation_map, PKS_NUM_KEYS);
> +             if (nr >= PKS_NUM_KEYS) {
> +                     pr_info("Cannot allocate supervisor key for %s.\n",
> +                             pkey_user);
> +                     return -ENOSPC;
> +             }
> +             if (!test_and_set_bit_lock(nr, &pks_key_allocation_map))
> +                     break;
> +     }
> +
> +     /* for debugging key exhaustion */
> +     pks_key_users[nr] = pkey_user;
> +
> +     return nr;
> +}
> +EXPORT_SYMBOL_GPL(pks_key_alloc);
> +
> +/*
> + * pks_key_free - Free a previously allocate PKS key
> + *
> + * @pkey: Key to be free'ed
> + */
> +void pks_key_free(int pkey)
> +{
> +     if (!cpu_feature_enabled(X86_FEATURE_PKS))
> +             return;
> +
> +     if (pkey >= PKS_NUM_KEYS || pkey <= PKS_KERN_DEFAULT_KEY)
> +             return;

This seems worthy of a WARN_ON_ONCE() at least.  It's essentially
corrupt data coming into a kernel API.

Reply via email to