1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * This file is part of UBIFS. |
4 | * |
5 | * Copyright (C) 2006-2008 Nokia Corporation. |
6 | * Copyright (C) 2006, 2007 University of Szeged, Hungary |
7 | * |
8 | * Authors: Zoltan Sogor |
9 | * Artem Bityutskiy (Битюцкий Артём) |
10 | * Adrian Hunter |
11 | */ |
12 | |
13 | /* This file implements EXT2-compatible extended attribute ioctl() calls */ |
14 | |
15 | #include <linux/compat.h> |
16 | #include <linux/mount.h> |
17 | #include <linux/fileattr.h> |
18 | #include "ubifs.h" |
19 | |
20 | /* Need to be kept consistent with checked flags in ioctl2ubifs() */ |
21 | #define UBIFS_SETTABLE_IOCTL_FLAGS \ |
22 | (FS_COMPR_FL | FS_SYNC_FL | FS_APPEND_FL | \ |
23 | FS_IMMUTABLE_FL | FS_DIRSYNC_FL) |
24 | |
25 | /* Need to be kept consistent with checked flags in ubifs2ioctl() */ |
26 | #define UBIFS_GETTABLE_IOCTL_FLAGS \ |
27 | (UBIFS_SETTABLE_IOCTL_FLAGS | FS_ENCRYPT_FL) |
28 | |
29 | /** |
30 | * ubifs_set_inode_flags - set VFS inode flags. |
31 | * @inode: VFS inode to set flags for |
32 | * |
33 | * This function propagates flags from UBIFS inode object to VFS inode object. |
34 | */ |
35 | void ubifs_set_inode_flags(struct inode *inode) |
36 | { |
37 | unsigned int flags = ubifs_inode(inode)->flags; |
38 | |
39 | inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE | S_DIRSYNC | |
40 | S_ENCRYPTED); |
41 | if (flags & UBIFS_SYNC_FL) |
42 | inode->i_flags |= S_SYNC; |
43 | if (flags & UBIFS_APPEND_FL) |
44 | inode->i_flags |= S_APPEND; |
45 | if (flags & UBIFS_IMMUTABLE_FL) |
46 | inode->i_flags |= S_IMMUTABLE; |
47 | if (flags & UBIFS_DIRSYNC_FL) |
48 | inode->i_flags |= S_DIRSYNC; |
49 | if (flags & UBIFS_CRYPT_FL) |
50 | inode->i_flags |= S_ENCRYPTED; |
51 | } |
52 | |
53 | /* |
54 | * ioctl2ubifs - convert ioctl inode flags to UBIFS inode flags. |
55 | * @ioctl_flags: flags to convert |
56 | * |
57 | * This function converts ioctl flags (@FS_COMPR_FL, etc) to UBIFS inode flags |
58 | * (@UBIFS_COMPR_FL, etc). |
59 | */ |
60 | static int ioctl2ubifs(int ioctl_flags) |
61 | { |
62 | int ubifs_flags = 0; |
63 | |
64 | if (ioctl_flags & FS_COMPR_FL) |
65 | ubifs_flags |= UBIFS_COMPR_FL; |
66 | if (ioctl_flags & FS_SYNC_FL) |
67 | ubifs_flags |= UBIFS_SYNC_FL; |
68 | if (ioctl_flags & FS_APPEND_FL) |
69 | ubifs_flags |= UBIFS_APPEND_FL; |
70 | if (ioctl_flags & FS_IMMUTABLE_FL) |
71 | ubifs_flags |= UBIFS_IMMUTABLE_FL; |
72 | if (ioctl_flags & FS_DIRSYNC_FL) |
73 | ubifs_flags |= UBIFS_DIRSYNC_FL; |
74 | |
75 | return ubifs_flags; |
76 | } |
77 | |
78 | /* |
79 | * ubifs2ioctl - convert UBIFS inode flags to ioctl inode flags. |
80 | * @ubifs_flags: flags to convert |
81 | * |
82 | * This function converts UBIFS inode flags (@UBIFS_COMPR_FL, etc) to ioctl |
83 | * flags (@FS_COMPR_FL, etc). |
84 | */ |
85 | static int ubifs2ioctl(int ubifs_flags) |
86 | { |
87 | int ioctl_flags = 0; |
88 | |
89 | if (ubifs_flags & UBIFS_COMPR_FL) |
90 | ioctl_flags |= FS_COMPR_FL; |
91 | if (ubifs_flags & UBIFS_SYNC_FL) |
92 | ioctl_flags |= FS_SYNC_FL; |
93 | if (ubifs_flags & UBIFS_APPEND_FL) |
94 | ioctl_flags |= FS_APPEND_FL; |
95 | if (ubifs_flags & UBIFS_IMMUTABLE_FL) |
96 | ioctl_flags |= FS_IMMUTABLE_FL; |
97 | if (ubifs_flags & UBIFS_DIRSYNC_FL) |
98 | ioctl_flags |= FS_DIRSYNC_FL; |
99 | if (ubifs_flags & UBIFS_CRYPT_FL) |
100 | ioctl_flags |= FS_ENCRYPT_FL; |
101 | |
102 | return ioctl_flags; |
103 | } |
104 | |
105 | static int setflags(struct inode *inode, int flags) |
106 | { |
107 | int err, release; |
108 | struct ubifs_inode *ui = ubifs_inode(inode); |
109 | struct ubifs_info *c = inode->i_sb->s_fs_info; |
110 | struct ubifs_budget_req req = { .dirtied_ino = 1, |
111 | .dirtied_ino_d = ALIGN(ui->data_len, 8) }; |
112 | |
113 | err = ubifs_budget_space(c, req: &req); |
114 | if (err) |
115 | return err; |
116 | |
117 | mutex_lock(&ui->ui_mutex); |
118 | ui->flags &= ~ioctl2ubifs(UBIFS_SETTABLE_IOCTL_FLAGS); |
119 | ui->flags |= ioctl2ubifs(ioctl_flags: flags); |
120 | ubifs_set_inode_flags(inode); |
121 | inode_set_ctime_current(inode); |
122 | release = ui->dirty; |
123 | mark_inode_dirty_sync(inode); |
124 | mutex_unlock(lock: &ui->ui_mutex); |
125 | |
126 | if (release) |
127 | ubifs_release_budget(c, req: &req); |
128 | if (IS_SYNC(inode)) |
129 | err = write_inode_now(inode, sync: 1); |
130 | return err; |
131 | } |
132 | |
133 | int ubifs_fileattr_get(struct dentry *dentry, struct fileattr *fa) |
134 | { |
135 | struct inode *inode = d_inode(dentry); |
136 | int flags = ubifs2ioctl(ubifs_flags: ubifs_inode(inode)->flags); |
137 | |
138 | if (d_is_special(dentry)) |
139 | return -ENOTTY; |
140 | |
141 | dbg_gen("get flags: %#x, i_flags %#x" , flags, inode->i_flags); |
142 | fileattr_fill_flags(fa, flags); |
143 | |
144 | return 0; |
145 | } |
146 | |
147 | int ubifs_fileattr_set(struct mnt_idmap *idmap, |
148 | struct dentry *dentry, struct fileattr *fa) |
149 | { |
150 | struct inode *inode = d_inode(dentry); |
151 | int flags = fa->flags; |
152 | |
153 | if (d_is_special(dentry)) |
154 | return -ENOTTY; |
155 | |
156 | if (fileattr_has_fsx(fa)) |
157 | return -EOPNOTSUPP; |
158 | |
159 | if (flags & ~UBIFS_GETTABLE_IOCTL_FLAGS) |
160 | return -EOPNOTSUPP; |
161 | |
162 | flags &= UBIFS_SETTABLE_IOCTL_FLAGS; |
163 | |
164 | if (!S_ISDIR(inode->i_mode)) |
165 | flags &= ~FS_DIRSYNC_FL; |
166 | |
167 | dbg_gen("set flags: %#x, i_flags %#x" , flags, inode->i_flags); |
168 | return setflags(inode, flags); |
169 | } |
170 | |
171 | long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
172 | { |
173 | int err; |
174 | struct inode *inode = file_inode(f: file); |
175 | |
176 | switch (cmd) { |
177 | case FS_IOC_SET_ENCRYPTION_POLICY: { |
178 | struct ubifs_info *c = inode->i_sb->s_fs_info; |
179 | |
180 | err = ubifs_enable_encryption(c); |
181 | if (err) |
182 | return err; |
183 | |
184 | return fscrypt_ioctl_set_policy(filp: file, arg: (const void __user *)arg); |
185 | } |
186 | case FS_IOC_GET_ENCRYPTION_POLICY: |
187 | return fscrypt_ioctl_get_policy(filp: file, arg: (void __user *)arg); |
188 | |
189 | case FS_IOC_GET_ENCRYPTION_POLICY_EX: |
190 | return fscrypt_ioctl_get_policy_ex(filp: file, arg: (void __user *)arg); |
191 | |
192 | case FS_IOC_ADD_ENCRYPTION_KEY: |
193 | return fscrypt_ioctl_add_key(filp: file, arg: (void __user *)arg); |
194 | |
195 | case FS_IOC_REMOVE_ENCRYPTION_KEY: |
196 | return fscrypt_ioctl_remove_key(filp: file, arg: (void __user *)arg); |
197 | |
198 | case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS: |
199 | return fscrypt_ioctl_remove_key_all_users(filp: file, |
200 | arg: (void __user *)arg); |
201 | case FS_IOC_GET_ENCRYPTION_KEY_STATUS: |
202 | return fscrypt_ioctl_get_key_status(filp: file, arg: (void __user *)arg); |
203 | |
204 | case FS_IOC_GET_ENCRYPTION_NONCE: |
205 | return fscrypt_ioctl_get_nonce(filp: file, arg: (void __user *)arg); |
206 | |
207 | default: |
208 | return -ENOTTY; |
209 | } |
210 | } |
211 | |
212 | #ifdef CONFIG_COMPAT |
213 | long ubifs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
214 | { |
215 | switch (cmd) { |
216 | case FS_IOC32_GETFLAGS: |
217 | cmd = FS_IOC_GETFLAGS; |
218 | break; |
219 | case FS_IOC32_SETFLAGS: |
220 | cmd = FS_IOC_SETFLAGS; |
221 | break; |
222 | case FS_IOC_SET_ENCRYPTION_POLICY: |
223 | case FS_IOC_GET_ENCRYPTION_POLICY: |
224 | case FS_IOC_GET_ENCRYPTION_POLICY_EX: |
225 | case FS_IOC_ADD_ENCRYPTION_KEY: |
226 | case FS_IOC_REMOVE_ENCRYPTION_KEY: |
227 | case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS: |
228 | case FS_IOC_GET_ENCRYPTION_KEY_STATUS: |
229 | case FS_IOC_GET_ENCRYPTION_NONCE: |
230 | break; |
231 | default: |
232 | return -ENOIOCTLCMD; |
233 | } |
234 | return ubifs_ioctl(file, cmd, arg: (unsigned long)compat_ptr(uptr: arg)); |
235 | } |
236 | #endif |
237 | |