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 }; 193