root/fs/efivarfs/file.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. efivarfs_file_write
  2. efivarfs_file_read
  3. efivarfs_getflags
  4. efivarfs_ioc_getxflags
  5. efivarfs_ioc_setxflags
  6. efivarfs_file_ioctl

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2012 Red Hat, Inc.
   4  * Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
   5  */
   6 
   7 #include <linux/efi.h>
   8 #include <linux/delay.h>
   9 #include <linux/fs.h>
  10 #include <linux/slab.h>
  11 #include <linux/mount.h>
  12 
  13 #include "internal.h"
  14 
  15 static ssize_t efivarfs_file_write(struct file *file,
  16                 const char __user *userbuf, size_t count, loff_t *ppos)
  17 {
  18         struct efivar_entry *var = file->private_data;
  19         void *data;
  20         u32 attributes;
  21         struct inode *inode = file->f_mapping->host;
  22         unsigned long datasize = count - sizeof(attributes);
  23         ssize_t bytes;
  24         bool set = false;
  25 
  26         if (count < sizeof(attributes))
  27                 return -EINVAL;
  28 
  29         if (copy_from_user(&attributes, userbuf, sizeof(attributes)))
  30                 return -EFAULT;
  31 
  32         if (attributes & ~(EFI_VARIABLE_MASK))
  33                 return -EINVAL;
  34 
  35         data = memdup_user(userbuf + sizeof(attributes), datasize);
  36         if (IS_ERR(data))
  37                 return PTR_ERR(data);
  38 
  39         bytes = efivar_entry_set_get_size(var, attributes, &datasize,
  40                                           data, &set);
  41         if (!set && bytes) {
  42                 if (bytes == -ENOENT)
  43                         bytes = -EIO;
  44                 goto out;
  45         }
  46 
  47         if (bytes == -ENOENT) {
  48                 drop_nlink(inode);
  49                 d_delete(file->f_path.dentry);
  50                 dput(file->f_path.dentry);
  51         } else {
  52                 inode_lock(inode);
  53                 i_size_write(inode, datasize + sizeof(attributes));
  54                 inode_unlock(inode);
  55         }
  56 
  57         bytes = count;
  58 
  59 out:
  60         kfree(data);
  61 
  62         return bytes;
  63 }
  64 
  65 static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
  66                 size_t count, loff_t *ppos)
  67 {
  68         struct efivar_entry *var = file->private_data;
  69         unsigned long datasize = 0;
  70         u32 attributes;
  71         void *data;
  72         ssize_t size = 0;
  73         int err;
  74 
  75         while (!__ratelimit(&file->f_cred->user->ratelimit)) {
  76                 if (!msleep_interruptible(50))
  77                         return -EINTR;
  78         }
  79 
  80         err = efivar_entry_size(var, &datasize);
  81 
  82         /*
  83          * efivarfs represents uncommitted variables with
  84          * zero-length files. Reading them should return EOF.
  85          */
  86         if (err == -ENOENT)
  87                 return 0;
  88         else if (err)
  89                 return err;
  90 
  91         data = kmalloc(datasize + sizeof(attributes), GFP_KERNEL);
  92 
  93         if (!data)
  94                 return -ENOMEM;
  95 
  96         size = efivar_entry_get(var, &attributes, &datasize,
  97                                 data + sizeof(attributes));
  98         if (size)
  99                 goto out_free;
 100 
 101         memcpy(data, &attributes, sizeof(attributes));
 102         size = simple_read_from_buffer(userbuf, count, ppos,
 103                                        data, datasize + sizeof(attributes));
 104 out_free:
 105         kfree(data);
 106 
 107         return size;
 108 }
 109 
 110 static inline unsigned int efivarfs_getflags(struct inode *inode)
 111 {
 112         unsigned int i_flags;
 113         unsigned int flags = 0;
 114 
 115         i_flags = inode->i_flags;
 116         if (i_flags & S_IMMUTABLE)
 117                 flags |= FS_IMMUTABLE_FL;
 118         return flags;
 119 }
 120 
 121 static int
 122 efivarfs_ioc_getxflags(struct file *file, void __user *arg)
 123 {
 124         struct inode *inode = file->f_mapping->host;
 125         unsigned int flags = efivarfs_getflags(inode);
 126 
 127         if (copy_to_user(arg, &flags, sizeof(flags)))
 128                 return -EFAULT;
 129         return 0;
 130 }
 131 
 132 static int
 133 efivarfs_ioc_setxflags(struct file *file, void __user *arg)
 134 {
 135         struct inode *inode = file->f_mapping->host;
 136         unsigned int flags;
 137         unsigned int i_flags = 0;
 138         unsigned int oldflags = efivarfs_getflags(inode);
 139         int error;
 140 
 141         if (!inode_owner_or_capable(inode))
 142                 return -EACCES;
 143 
 144         if (copy_from_user(&flags, arg, sizeof(flags)))
 145                 return -EFAULT;
 146 
 147         if (flags & ~FS_IMMUTABLE_FL)
 148                 return -EOPNOTSUPP;
 149 
 150         if (flags & FS_IMMUTABLE_FL)
 151                 i_flags |= S_IMMUTABLE;
 152 
 153 
 154         error = mnt_want_write_file(file);
 155         if (error)
 156                 return error;
 157 
 158         inode_lock(inode);
 159 
 160         error = vfs_ioc_setflags_prepare(inode, oldflags, flags);
 161         if (error)
 162                 goto out;
 163 
 164         inode_set_flags(inode, i_flags, S_IMMUTABLE);
 165 out:
 166         inode_unlock(inode);
 167         mnt_drop_write_file(file);
 168         return error;
 169 }
 170 
 171 static long
 172 efivarfs_file_ioctl(struct file *file, unsigned int cmd, unsigned long p)
 173 {
 174         void __user *arg = (void __user *)p;
 175 
 176         switch (cmd) {
 177         case FS_IOC_GETFLAGS:
 178                 return efivarfs_ioc_getxflags(file, arg);
 179         case FS_IOC_SETFLAGS:
 180                 return efivarfs_ioc_setxflags(file, arg);
 181         }
 182 
 183         return -ENOTTY;
 184 }
 185 
 186 const struct file_operations efivarfs_file_operations = {
 187         .open   = simple_open,
 188         .read   = efivarfs_file_read,
 189         .write  = efivarfs_file_write,
 190         .llseek = no_llseek,
 191         .unlocked_ioctl = efivarfs_file_ioctl,
 192 };

/* [<][>][^][v][top][bottom][index][help] */