LCOV - code coverage report
Current view: top level - arch/x86/mm - pkeys.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 3 56 5.4 %
Date: 2022-04-01 14:35:51 Functions: 1 7 14.3 %
Branches: 0 32 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * Intel Memory Protection Keys management
       4                 :            :  * Copyright (c) 2015, Intel Corporation.
       5                 :            :  */
       6                 :            : #include <linux/debugfs.h>                /* debugfs_create_u32()         */
       7                 :            : #include <linux/mm_types.h>             /* mm_struct, vma, etc...       */
       8                 :            : #include <linux/pkeys.h>                /* PKEY_*                       */
       9                 :            : #include <uapi/asm-generic/mman-common.h>
      10                 :            : 
      11                 :            : #include <asm/cpufeature.h>             /* boot_cpu_has, ...            */
      12                 :            : #include <asm/mmu_context.h>            /* vma_pkey()                   */
      13                 :            : #include <asm/fpu/internal.h>             /* init_fpstate                 */
      14                 :            : 
      15                 :          0 : int __execute_only_pkey(struct mm_struct *mm)
      16                 :            : {
      17                 :          0 :         bool need_to_set_mm_pkey = false;
      18                 :          0 :         int execute_only_pkey = mm->context.execute_only_pkey;
      19                 :          0 :         int ret;
      20                 :            : 
      21                 :            :         /* Do we need to assign a pkey for mm's execute-only maps? */
      22         [ #  # ]:          0 :         if (execute_only_pkey == -1) {
      23                 :            :                 /* Go allocate one to use, which might fail */
      24                 :          0 :                 execute_only_pkey = mm_pkey_alloc(mm);
      25         [ #  # ]:          0 :                 if (execute_only_pkey < 0)
      26                 :            :                         return -1;
      27                 :            :                 need_to_set_mm_pkey = true;
      28                 :            :         }
      29                 :            : 
      30                 :            :         /*
      31                 :            :          * We do not want to go through the relatively costly
      32                 :            :          * dance to set PKRU if we do not need to.  Check it
      33                 :            :          * first and assume that if the execute-only pkey is
      34                 :            :          * write-disabled that we do not have to set it
      35                 :            :          * ourselves.
      36                 :            :          */
      37   [ #  #  #  # ]:          0 :         if (!need_to_set_mm_pkey &&
      38                 :            :             !__pkru_allows_read(read_pkru(), execute_only_pkey)) {
      39                 :            :                 return execute_only_pkey;
      40                 :            :         }
      41                 :            : 
      42                 :            :         /*
      43                 :            :          * Set up PKRU so that it denies access for everything
      44                 :            :          * other than execution.
      45                 :            :          */
      46                 :          0 :         ret = arch_set_user_pkey_access(current, execute_only_pkey,
      47                 :            :                         PKEY_DISABLE_ACCESS);
      48                 :            :         /*
      49                 :            :          * If the PKRU-set operation failed somehow, just return
      50                 :            :          * 0 and effectively disable execute-only support.
      51                 :            :          */
      52         [ #  # ]:          0 :         if (ret) {
      53                 :          0 :                 mm_set_pkey_free(mm, execute_only_pkey);
      54                 :          0 :                 return -1;
      55                 :            :         }
      56                 :            : 
      57                 :            :         /* We got one, store it and use it from here on out */
      58         [ #  # ]:          0 :         if (need_to_set_mm_pkey)
      59                 :          0 :                 mm->context.execute_only_pkey = execute_only_pkey;
      60                 :            :         return execute_only_pkey;
      61                 :            : }
      62                 :            : 
      63                 :          0 : static inline bool vma_is_pkey_exec_only(struct vm_area_struct *vma)
      64                 :            : {
      65                 :            :         /* Do this check first since the vm_flags should be hot */
      66                 :          0 :         if ((vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC)) != VM_EXEC)
      67                 :            :                 return false;
      68         [ #  # ]:          0 :         if (vma_pkey(vma) != vma->vm_mm->context.execute_only_pkey)
      69                 :            :                 return false;
      70                 :            : 
      71                 :            :         return true;
      72                 :            : }
      73                 :            : 
      74                 :            : /*
      75                 :            :  * This is only called for *plain* mprotect calls.
      76                 :            :  */
      77                 :          0 : int __arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot, int pkey)
      78                 :            : {
      79                 :            :         /*
      80                 :            :          * Is this an mprotect_pkey() call?  If so, never
      81                 :            :          * override the value that came from the user.
      82                 :            :          */
      83         [ #  # ]:          0 :         if (pkey != -1)
      84                 :            :                 return pkey;
      85                 :            : 
      86                 :            :         /*
      87                 :            :          * The mapping is execute-only.  Go try to get the
      88                 :            :          * execute-only protection key.  If we fail to do that,
      89                 :            :          * fall through as if we do not have execute-only
      90                 :            :          * support in this mm.
      91                 :            :          */
      92         [ #  # ]:          0 :         if (prot == PROT_EXEC) {
      93                 :          0 :                 pkey = execute_only_pkey(vma->vm_mm);
      94         [ #  # ]:          0 :                 if (pkey > 0)
      95                 :            :                         return pkey;
      96         [ #  # ]:          0 :         } else if (vma_is_pkey_exec_only(vma)) {
      97                 :            :                 /*
      98                 :            :                  * Protections are *not* PROT_EXEC, but the mapping
      99                 :            :                  * is using the exec-only pkey.  This mapping was
     100                 :            :                  * PROT_EXEC and will no longer be.  Move back to
     101                 :            :                  * the default pkey.
     102                 :            :                  */
     103                 :            :                 return ARCH_DEFAULT_PKEY;
     104                 :            :         }
     105                 :            : 
     106                 :            :         /*
     107                 :            :          * This is a vanilla, non-pkey mprotect (or we failed to
     108                 :            :          * setup execute-only), inherit the pkey from the VMA we
     109                 :            :          * are working on.
     110                 :            :          */
     111                 :          0 :         return vma_pkey(vma);
     112                 :            : }
     113                 :            : 
     114                 :            : #define PKRU_AD_KEY(pkey)       (PKRU_AD_BIT << ((pkey) * PKRU_BITS_PER_PKEY))
     115                 :            : 
     116                 :            : /*
     117                 :            :  * Make the default PKRU value (at execve() time) as restrictive
     118                 :            :  * as possible.  This ensures that any threads clone()'d early
     119                 :            :  * in the process's lifetime will not accidentally get access
     120                 :            :  * to data which is pkey-protected later on.
     121                 :            :  */
     122                 :            : u32 init_pkru_value = PKRU_AD_KEY( 1) | PKRU_AD_KEY( 2) | PKRU_AD_KEY( 3) |
     123                 :            :                       PKRU_AD_KEY( 4) | PKRU_AD_KEY( 5) | PKRU_AD_KEY( 6) |
     124                 :            :                       PKRU_AD_KEY( 7) | PKRU_AD_KEY( 8) | PKRU_AD_KEY( 9) |
     125                 :            :                       PKRU_AD_KEY(10) | PKRU_AD_KEY(11) | PKRU_AD_KEY(12) |
     126                 :            :                       PKRU_AD_KEY(13) | PKRU_AD_KEY(14) | PKRU_AD_KEY(15);
     127                 :            : 
     128                 :            : /*
     129                 :            :  * Called from the FPU code when creating a fresh set of FPU
     130                 :            :  * registers.  This is called from a very specific context where
     131                 :            :  * we know the FPU regstiers are safe for use and we can use PKRU
     132                 :            :  * directly.
     133                 :            :  */
     134                 :          0 : void copy_init_pkru_to_fpregs(void)
     135                 :            : {
     136                 :          0 :         u32 init_pkru_value_snapshot = READ_ONCE(init_pkru_value);
     137                 :            :         /*
     138                 :            :          * Override the PKRU state that came from 'init_fpstate'
     139                 :            :          * with the baseline from the process.
     140                 :            :          */
     141                 :          0 :         write_pkru(init_pkru_value_snapshot);
     142                 :          0 : }
     143                 :            : 
     144                 :          0 : static ssize_t init_pkru_read_file(struct file *file, char __user *user_buf,
     145                 :            :                              size_t count, loff_t *ppos)
     146                 :            : {
     147                 :          0 :         char buf[32];
     148                 :          0 :         unsigned int len;
     149                 :            : 
     150                 :          0 :         len = sprintf(buf, "0x%x\n", init_pkru_value);
     151                 :          0 :         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
     152                 :            : }
     153                 :            : 
     154                 :          0 : static ssize_t init_pkru_write_file(struct file *file,
     155                 :            :                  const char __user *user_buf, size_t count, loff_t *ppos)
     156                 :            : {
     157                 :          0 :         struct pkru_state *pk;
     158                 :          0 :         char buf[32];
     159                 :          0 :         ssize_t len;
     160                 :          0 :         u32 new_init_pkru;
     161                 :            : 
     162                 :          0 :         len = min(count, sizeof(buf) - 1);
     163         [ #  # ]:          0 :         if (copy_from_user(buf, user_buf, len))
     164                 :            :                 return -EFAULT;
     165                 :            : 
     166                 :            :         /* Make the buffer a valid string that we can not overrun */
     167                 :          0 :         buf[len] = '\0';
     168         [ #  # ]:          0 :         if (kstrtouint(buf, 0, &new_init_pkru))
     169                 :            :                 return -EINVAL;
     170                 :            : 
     171                 :            :         /*
     172                 :            :          * Don't allow insane settings that will blow the system
     173                 :            :          * up immediately if someone attempts to disable access
     174                 :            :          * or writes to pkey 0.
     175                 :            :          */
     176         [ #  # ]:          0 :         if (new_init_pkru & (PKRU_AD_BIT|PKRU_WD_BIT))
     177                 :            :                 return -EINVAL;
     178                 :            : 
     179                 :          0 :         WRITE_ONCE(init_pkru_value, new_init_pkru);
     180                 :          0 :         pk = get_xsave_addr(&init_fpstate.xsave, XFEATURE_PKRU);
     181         [ #  # ]:          0 :         if (!pk)
     182                 :            :                 return -EINVAL;
     183                 :          0 :         pk->pkru = new_init_pkru;
     184                 :          0 :         return count;
     185                 :            : }
     186                 :            : 
     187                 :            : static const struct file_operations fops_init_pkru = {
     188                 :            :         .read = init_pkru_read_file,
     189                 :            :         .write = init_pkru_write_file,
     190                 :            :         .llseek = default_llseek,
     191                 :            : };
     192                 :            : 
     193                 :         21 : static int __init create_init_pkru_value(void)
     194                 :            : {
     195                 :         21 :         debugfs_create_file("init_pkru", S_IRUSR | S_IWUSR,
     196                 :            :                         arch_debugfs_dir, NULL, &fops_init_pkru);
     197                 :         21 :         return 0;
     198                 :            : }
     199                 :            : late_initcall(create_init_pkru_value);
     200                 :            : 
     201                 :          0 : static __init int setup_init_pkru(char *opt)
     202                 :            : {
     203                 :          0 :         u32 new_init_pkru;
     204                 :            : 
     205         [ #  # ]:          0 :         if (kstrtouint(opt, 0, &new_init_pkru))
     206                 :            :                 return 1;
     207                 :            : 
     208                 :          0 :         WRITE_ONCE(init_pkru_value, new_init_pkru);
     209                 :            : 
     210                 :          0 :         return 1;
     211                 :            : }
     212                 :            : __setup("init_pkru=", setup_init_pkru);

Generated by: LCOV version 1.14