diff options
Diffstat (limited to 'fs/efivarfs/file.c')
-rw-r--r-- | fs/efivarfs/file.c | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c index c424e4813ec8..d48e0d261d78 100644 --- a/fs/efivarfs/file.c +++ b/fs/efivarfs/file.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/efi.h> | 10 | #include <linux/efi.h> |
11 | #include <linux/fs.h> | 11 | #include <linux/fs.h> |
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include <linux/mount.h> | ||
13 | 14 | ||
14 | #include "internal.h" | 15 | #include "internal.h" |
15 | 16 | ||
@@ -103,9 +104,78 @@ out_free: | |||
103 | return size; | 104 | return size; |
104 | } | 105 | } |
105 | 106 | ||
107 | static int | ||
108 | efivarfs_ioc_getxflags(struct file *file, void __user *arg) | ||
109 | { | ||
110 | struct inode *inode = file->f_mapping->host; | ||
111 | unsigned int i_flags; | ||
112 | unsigned int flags = 0; | ||
113 | |||
114 | i_flags = inode->i_flags; | ||
115 | if (i_flags & S_IMMUTABLE) | ||
116 | flags |= FS_IMMUTABLE_FL; | ||
117 | |||
118 | if (copy_to_user(arg, &flags, sizeof(flags))) | ||
119 | return -EFAULT; | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | static int | ||
124 | efivarfs_ioc_setxflags(struct file *file, void __user *arg) | ||
125 | { | ||
126 | struct inode *inode = file->f_mapping->host; | ||
127 | unsigned int flags; | ||
128 | unsigned int i_flags = 0; | ||
129 | int error; | ||
130 | |||
131 | if (!inode_owner_or_capable(inode)) | ||
132 | return -EACCES; | ||
133 | |||
134 | if (copy_from_user(&flags, arg, sizeof(flags))) | ||
135 | return -EFAULT; | ||
136 | |||
137 | if (flags & ~FS_IMMUTABLE_FL) | ||
138 | return -EOPNOTSUPP; | ||
139 | |||
140 | if (!capable(CAP_LINUX_IMMUTABLE)) | ||
141 | return -EPERM; | ||
142 | |||
143 | if (flags & FS_IMMUTABLE_FL) | ||
144 | i_flags |= S_IMMUTABLE; | ||
145 | |||
146 | |||
147 | error = mnt_want_write_file(file); | ||
148 | if (error) | ||
149 | return error; | ||
150 | |||
151 | inode_lock(inode); | ||
152 | inode_set_flags(inode, i_flags, S_IMMUTABLE); | ||
153 | inode_unlock(inode); | ||
154 | |||
155 | mnt_drop_write_file(file); | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | long | ||
161 | efivarfs_file_ioctl(struct file *file, unsigned int cmd, unsigned long p) | ||
162 | { | ||
163 | void __user *arg = (void __user *)p; | ||
164 | |||
165 | switch (cmd) { | ||
166 | case FS_IOC_GETFLAGS: | ||
167 | return efivarfs_ioc_getxflags(file, arg); | ||
168 | case FS_IOC_SETFLAGS: | ||
169 | return efivarfs_ioc_setxflags(file, arg); | ||
170 | } | ||
171 | |||
172 | return -ENOTTY; | ||
173 | } | ||
174 | |||
106 | const struct file_operations efivarfs_file_operations = { | 175 | const struct file_operations efivarfs_file_operations = { |
107 | .open = simple_open, | 176 | .open = simple_open, |
108 | .read = efivarfs_file_read, | 177 | .read = efivarfs_file_read, |
109 | .write = efivarfs_file_write, | 178 | .write = efivarfs_file_write, |
110 | .llseek = no_llseek, | 179 | .llseek = no_llseek, |
180 | .unlocked_ioctl = efivarfs_file_ioctl, | ||
111 | }; | 181 | }; |