linux/mm/secretmem.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright IBM Corporation, 2021
   4 *
   5 * Author: Mike Rapoport <rppt@linux.ibm.com>
   6 */
   7
   8#include <linux/mm.h>
   9#include <linux/fs.h>
  10#include <linux/swap.h>
  11#include <linux/mount.h>
  12#include <linux/memfd.h>
  13#include <linux/bitops.h>
  14#include <linux/printk.h>
  15#include <linux/pagemap.h>
  16#include <linux/syscalls.h>
  17#include <linux/pseudo_fs.h>
  18#include <linux/secretmem.h>
  19#include <linux/set_memory.h>
  20#include <linux/sched/signal.h>
  21
  22#include <uapi/linux/magic.h>
  23
  24#include <asm/tlbflush.h>
  25
  26#include "internal.h"
  27
  28#undef pr_fmt
  29#define pr_fmt(fmt) "secretmem: " fmt
  30
  31/*
  32 * Define mode and flag masks to allow validation of the system call
  33 * parameters.
  34 */
  35#define SECRETMEM_MODE_MASK     (0x0)
  36#define SECRETMEM_FLAGS_MASK    SECRETMEM_MODE_MASK
  37
  38static bool secretmem_enable __ro_after_init;
  39module_param_named(enable, secretmem_enable, bool, 0400);
  40MODULE_PARM_DESC(secretmem_enable,
  41                 "Enable secretmem and memfd_secret(2) system call");
  42
  43static atomic_t secretmem_users;
  44
  45bool secretmem_active(void)
  46{
  47        return !!atomic_read(&secretmem_users);
  48}
  49
  50static vm_fault_t secretmem_fault(struct vm_fault *vmf)
  51{
  52        struct address_space *mapping = vmf->vma->vm_file->f_mapping;
  53        struct inode *inode = file_inode(vmf->vma->vm_file);
  54        pgoff_t offset = vmf->pgoff;
  55        gfp_t gfp = vmf->gfp_mask;
  56        unsigned long addr;
  57        struct page *page;
  58        int err;
  59
  60        if (((loff_t)vmf->pgoff << PAGE_SHIFT) >= i_size_read(inode))
  61                return vmf_error(-EINVAL);
  62
  63retry:
  64        page = find_lock_page(mapping, offset);
  65        if (!page) {
  66                page = alloc_page(gfp | __GFP_ZERO);
  67                if (!page)
  68                        return VM_FAULT_OOM;
  69
  70                err = set_direct_map_invalid_noflush(page);
  71                if (err) {
  72                        put_page(page);
  73                        return vmf_error(err);
  74                }
  75
  76                __SetPageUptodate(page);
  77                err = add_to_page_cache_lru(page, mapping, offset, gfp);
  78                if (unlikely(err)) {
  79                        put_page(page);
  80                        /*
  81                         * If a split of large page was required, it
  82                         * already happened when we marked the page invalid
  83                         * which guarantees that this call won't fail
  84                         */
  85                        set_direct_map_default_noflush(page);
  86                        if (err == -EEXIST)
  87                                goto retry;
  88
  89                        return vmf_error(err);
  90                }
  91
  92                addr = (unsigned long)page_address(page);
  93                flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
  94        }
  95
  96        vmf->page = page;
  97        return VM_FAULT_LOCKED;
  98}
  99
 100static const struct vm_operations_struct secretmem_vm_ops = {
 101        .fault = secretmem_fault,
 102};
 103
 104static int secretmem_release(struct inode *inode, struct file *file)
 105{
 106        atomic_dec(&secretmem_users);
 107        return 0;
 108}
 109
 110static int secretmem_mmap(struct file *file, struct vm_area_struct *vma)
 111{
 112        unsigned long len = vma->vm_end - vma->vm_start;
 113
 114        if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0)
 115                return -EINVAL;
 116
 117        if (mlock_future_check(vma->vm_mm, vma->vm_flags | VM_LOCKED, len))
 118                return -EAGAIN;
 119
 120        vma->vm_flags |= VM_LOCKED | VM_DONTDUMP;
 121        vma->vm_ops = &secretmem_vm_ops;
 122
 123        return 0;
 124}
 125
 126bool vma_is_secretmem(struct vm_area_struct *vma)
 127{
 128        return vma->vm_ops == &secretmem_vm_ops;
 129}
 130
 131static const struct file_operations secretmem_fops = {
 132        .release        = secretmem_release,
 133        .mmap           = secretmem_mmap,
 134};
 135
 136static bool secretmem_isolate_page(struct page *page, isolate_mode_t mode)
 137{
 138        return false;
 139}
 140
 141static int secretmem_migratepage(struct address_space *mapping,
 142                                 struct page *newpage, struct page *page,
 143                                 enum migrate_mode mode)
 144{
 145        return -EBUSY;
 146}
 147
 148static void secretmem_freepage(struct page *page)
 149{
 150        set_direct_map_default_noflush(page);
 151        clear_highpage(page);
 152}
 153
 154const struct address_space_operations secretmem_aops = {
 155        .set_page_dirty = __set_page_dirty_no_writeback,
 156        .freepage       = secretmem_freepage,
 157        .migratepage    = secretmem_migratepage,
 158        .isolate_page   = secretmem_isolate_page,
 159};
 160
 161static struct vfsmount *secretmem_mnt;
 162
 163static struct file *secretmem_file_create(unsigned long flags)
 164{
 165        struct file *file = ERR_PTR(-ENOMEM);
 166        struct inode *inode;
 167
 168        inode = alloc_anon_inode(secretmem_mnt->mnt_sb);
 169        if (IS_ERR(inode))
 170                return ERR_CAST(inode);
 171
 172        file = alloc_file_pseudo(inode, secretmem_mnt, "secretmem",
 173                                 O_RDWR, &secretmem_fops);
 174        if (IS_ERR(file))
 175                goto err_free_inode;
 176
 177        mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);
 178        mapping_set_unevictable(inode->i_mapping);
 179
 180        inode->i_mapping->a_ops = &secretmem_aops;
 181
 182        /* pretend we are a normal file with zero size */
 183        inode->i_mode |= S_IFREG;
 184        inode->i_size = 0;
 185
 186        return file;
 187
 188err_free_inode:
 189        iput(inode);
 190        return file;
 191}
 192
 193SYSCALL_DEFINE1(memfd_secret, unsigned int, flags)
 194{
 195        struct file *file;
 196        int fd, err;
 197
 198        /* make sure local flags do not confict with global fcntl.h */
 199        BUILD_BUG_ON(SECRETMEM_FLAGS_MASK & O_CLOEXEC);
 200
 201        if (!secretmem_enable)
 202                return -ENOSYS;
 203
 204        if (flags & ~(SECRETMEM_FLAGS_MASK | O_CLOEXEC))
 205                return -EINVAL;
 206
 207        fd = get_unused_fd_flags(flags & O_CLOEXEC);
 208        if (fd < 0)
 209                return fd;
 210
 211        file = secretmem_file_create(flags);
 212        if (IS_ERR(file)) {
 213                err = PTR_ERR(file);
 214                goto err_put_fd;
 215        }
 216
 217        file->f_flags |= O_LARGEFILE;
 218
 219        fd_install(fd, file);
 220        atomic_inc(&secretmem_users);
 221        return fd;
 222
 223err_put_fd:
 224        put_unused_fd(fd);
 225        return err;
 226}
 227
 228static int secretmem_init_fs_context(struct fs_context *fc)
 229{
 230        return init_pseudo(fc, SECRETMEM_MAGIC) ? 0 : -ENOMEM;
 231}
 232
 233static struct file_system_type secretmem_fs = {
 234        .name           = "secretmem",
 235        .init_fs_context = secretmem_init_fs_context,
 236        .kill_sb        = kill_anon_super,
 237};
 238
 239static int secretmem_init(void)
 240{
 241        int ret = 0;
 242
 243        if (!secretmem_enable)
 244                return ret;
 245
 246        secretmem_mnt = kern_mount(&secretmem_fs);
 247        if (IS_ERR(secretmem_mnt))
 248                ret = PTR_ERR(secretmem_mnt);
 249
 250        /* prevent secretmem mappings from ever getting PROT_EXEC */
 251        secretmem_mnt->mnt_flags |= MNT_NOEXEC;
 252
 253        return ret;
 254}
 255fs_initcall(secretmem_init);
 256
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.