Commit | Line | Data |
---|---|---|
be71b5cb KK |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * | |
4 | * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved. | |
5 | * | |
6 | */ | |
7 | ||
be71b5cb | 8 | #include <linux/fs.h> |
be71b5cb KK |
9 | #include <linux/posix_acl.h> |
10 | #include <linux/posix_acl_xattr.h> | |
11 | #include <linux/xattr.h> | |
12 | ||
13 | #include "debug.h" | |
14 | #include "ntfs.h" | |
15 | #include "ntfs_fs.h" | |
16 | ||
17 | // clang-format off | |
0d19f3d7 DP |
18 | #define SYSTEM_DOS_ATTRIB "system.dos_attrib" |
19 | #define SYSTEM_NTFS_ATTRIB "system.ntfs_attrib" | |
20 | #define SYSTEM_NTFS_ATTRIB_BE "system.ntfs_attrib_be" | |
21 | #define SYSTEM_NTFS_SECURITY "system.ntfs_security" | |
be71b5cb KK |
22 | // clang-format on |
23 | ||
24 | static inline size_t unpacked_ea_size(const struct EA_FULL *ea) | |
25 | { | |
96de65a9 KK |
26 | return ea->size ? le32_to_cpu(ea->size) : |
27 | ALIGN(struct_size(ea, name, | |
d3624466 KK |
28 | 1 + ea->name_len + |
29 | le16_to_cpu(ea->elength)), | |
30 | 4); | |
be71b5cb KK |
31 | } |
32 | ||
33 | static inline size_t packed_ea_size(const struct EA_FULL *ea) | |
34 | { | |
35 | return struct_size(ea, name, | |
36 | 1 + ea->name_len + le16_to_cpu(ea->elength)) - | |
37 | offsetof(struct EA_FULL, flags); | |
38 | } | |
39 | ||
40 | /* | |
41 | * find_ea | |
42 | * | |
e8b8e97f | 43 | * Assume there is at least one xattr in the list. |
be71b5cb KK |
44 | */ |
45 | static inline bool find_ea(const struct EA_FULL *ea_all, u32 bytes, | |
0e8235d2 | 46 | const char *name, u8 name_len, u32 *off, u32 *ea_sz) |
be71b5cb | 47 | { |
0e8235d2 | 48 | u32 ea_size; |
be71b5cb | 49 | |
0e8235d2 KK |
50 | *off = 0; |
51 | if (!ea_all) | |
be71b5cb KK |
52 | return false; |
53 | ||
0e8235d2 | 54 | for (; *off < bytes; *off += ea_size) { |
be71b5cb | 55 | const struct EA_FULL *ea = Add2Ptr(ea_all, *off); |
0e8235d2 | 56 | ea_size = unpacked_ea_size(ea); |
be71b5cb | 57 | if (ea->name_len == name_len && |
0e8235d2 KK |
58 | !memcmp(ea->name, name, name_len)) { |
59 | if (ea_sz) | |
60 | *ea_sz = ea_size; | |
be71b5cb | 61 | return true; |
0e8235d2 | 62 | } |
be71b5cb | 63 | } |
0e8235d2 KK |
64 | |
65 | return false; | |
be71b5cb KK |
66 | } |
67 | ||
68 | /* | |
e8b8e97f KA |
69 | * ntfs_read_ea - Read all extended attributes. |
70 | * @ea: New allocated memory. | |
71 | * @info: Pointer into resident data. | |
be71b5cb KK |
72 | */ |
73 | static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea, | |
74 | size_t add_bytes, const struct EA_INFO **info) | |
75 | { | |
0e8235d2 | 76 | int err = -EINVAL; |
cff32466 | 77 | struct ntfs_sb_info *sbi = ni->mi.sbi; |
be71b5cb KK |
78 | struct ATTR_LIST_ENTRY *le = NULL; |
79 | struct ATTRIB *attr_info, *attr_ea; | |
80 | void *ea_p; | |
0e8235d2 | 81 | u32 size, off, ea_size; |
be71b5cb KK |
82 | |
83 | static_assert(le32_to_cpu(ATTR_EA_INFO) < le32_to_cpu(ATTR_EA)); | |
84 | ||
85 | *ea = NULL; | |
86 | *info = NULL; | |
87 | ||
88 | attr_info = | |
89 | ni_find_attr(ni, NULL, &le, ATTR_EA_INFO, NULL, 0, NULL, NULL); | |
90 | attr_ea = | |
91 | ni_find_attr(ni, attr_info, &le, ATTR_EA, NULL, 0, NULL, NULL); | |
92 | ||
93 | if (!attr_ea || !attr_info) | |
94 | return 0; | |
95 | ||
96 | *info = resident_data_ex(attr_info, sizeof(struct EA_INFO)); | |
97 | if (!*info) | |
0e8235d2 | 98 | goto out; |
be71b5cb | 99 | |
e8b8e97f | 100 | /* Check Ea limit. */ |
be71b5cb | 101 | size = le32_to_cpu((*info)->size); |
0e8235d2 KK |
102 | if (size > sbi->ea_max_size) { |
103 | err = -EFBIG; | |
104 | goto out; | |
105 | } | |
be71b5cb | 106 | |
0e8235d2 KK |
107 | if (attr_size(attr_ea) > sbi->ea_max_size) { |
108 | err = -EFBIG; | |
109 | goto out; | |
110 | } | |
111 | ||
112 | if (!size) { | |
113 | /* EA info persists, but xattr is empty. Looks like EA problem. */ | |
114 | goto out; | |
115 | } | |
be71b5cb | 116 | |
e8b8e97f | 117 | /* Allocate memory for packed Ea. */ |
e001e608 | 118 | ea_p = kmalloc(size_add(size, add_bytes), GFP_NOFS); |
be71b5cb KK |
119 | if (!ea_p) |
120 | return -ENOMEM; | |
121 | ||
0e8235d2 | 122 | if (attr_ea->non_res) { |
be71b5cb KK |
123 | struct runs_tree run; |
124 | ||
125 | run_init(&run); | |
126 | ||
42f86b12 | 127 | err = attr_load_runs_range(ni, ATTR_EA, NULL, 0, &run, 0, size); |
be71b5cb | 128 | if (!err) |
cff32466 | 129 | err = ntfs_read_run_nb(sbi, &run, 0, ea_p, size, NULL); |
be71b5cb KK |
130 | run_close(&run); |
131 | ||
132 | if (err) | |
0e8235d2 | 133 | goto out1; |
be71b5cb KK |
134 | } else { |
135 | void *p = resident_data_ex(attr_ea, size); | |
136 | ||
0e8235d2 KK |
137 | if (!p) |
138 | goto out1; | |
be71b5cb KK |
139 | memcpy(ea_p, p, size); |
140 | } | |
141 | ||
142 | memset(Add2Ptr(ea_p, size), 0, add_bytes); | |
0e8235d2 KK |
143 | |
144 | /* Check all attributes for consistency. */ | |
145 | for (off = 0; off < size; off += ea_size) { | |
146 | const struct EA_FULL *ef = Add2Ptr(ea_p, off); | |
147 | u32 bytes = size - off; | |
148 | ||
149 | /* Check if we can use field ea->size. */ | |
150 | if (bytes < sizeof(ef->size)) | |
151 | goto out1; | |
152 | ||
153 | if (ef->size) { | |
154 | ea_size = le32_to_cpu(ef->size); | |
155 | if (ea_size > bytes) | |
156 | goto out1; | |
157 | continue; | |
158 | } | |
159 | ||
160 | /* Check if we can use fields ef->name_len and ef->elength. */ | |
161 | if (bytes < offsetof(struct EA_FULL, name)) | |
162 | goto out1; | |
163 | ||
164 | ea_size = ALIGN(struct_size(ef, name, | |
165 | 1 + ef->name_len + | |
166 | le16_to_cpu(ef->elength)), | |
167 | 4); | |
168 | if (ea_size > bytes) | |
169 | goto out1; | |
170 | } | |
171 | ||
be71b5cb KK |
172 | *ea = ea_p; |
173 | return 0; | |
174 | ||
0e8235d2 | 175 | out1: |
195c52bd | 176 | kfree(ea_p); |
0e8235d2 KK |
177 | out: |
178 | ntfs_set_state(sbi, NTFS_DIRTY_DIRTY); | |
be71b5cb KK |
179 | return err; |
180 | } | |
181 | ||
182 | /* | |
183 | * ntfs_list_ea | |
184 | * | |
e8b8e97f KA |
185 | * Copy a list of xattrs names into the buffer |
186 | * provided, or compute the buffer size required. | |
be71b5cb | 187 | * |
e8b8e97f KA |
188 | * Return: |
189 | * * Number of bytes used / required on | |
190 | * * -ERRNO - on failure | |
be71b5cb KK |
191 | */ |
192 | static ssize_t ntfs_list_ea(struct ntfs_inode *ni, char *buffer, | |
193 | size_t bytes_per_buffer) | |
194 | { | |
195 | const struct EA_INFO *info; | |
196 | struct EA_FULL *ea_all = NULL; | |
197 | const struct EA_FULL *ea; | |
198 | u32 off, size; | |
199 | int err; | |
0e8235d2 | 200 | int ea_size; |
be71b5cb KK |
201 | size_t ret; |
202 | ||
203 | err = ntfs_read_ea(ni, &ea_all, 0, &info); | |
204 | if (err) | |
205 | return err; | |
206 | ||
207 | if (!info || !ea_all) | |
208 | return 0; | |
209 | ||
210 | size = le32_to_cpu(info->size); | |
211 | ||
e8b8e97f | 212 | /* Enumerate all xattrs. */ |
0e8235d2 | 213 | for (ret = 0, off = 0; off < size; off += ea_size) { |
be71b5cb | 214 | ea = Add2Ptr(ea_all, off); |
0e8235d2 | 215 | ea_size = unpacked_ea_size(ea); |
be71b5cb KK |
216 | |
217 | if (buffer) { | |
218 | if (ret + ea->name_len + 1 > bytes_per_buffer) { | |
219 | err = -ERANGE; | |
220 | goto out; | |
221 | } | |
222 | ||
223 | memcpy(buffer + ret, ea->name, ea->name_len); | |
224 | buffer[ret + ea->name_len] = 0; | |
225 | } | |
226 | ||
227 | ret += ea->name_len + 1; | |
228 | } | |
229 | ||
230 | out: | |
195c52bd | 231 | kfree(ea_all); |
be71b5cb KK |
232 | return err ? err : ret; |
233 | } | |
234 | ||
235 | static int ntfs_get_ea(struct inode *inode, const char *name, size_t name_len, | |
236 | void *buffer, size_t size, size_t *required) | |
237 | { | |
238 | struct ntfs_inode *ni = ntfs_i(inode); | |
239 | const struct EA_INFO *info; | |
240 | struct EA_FULL *ea_all = NULL; | |
241 | const struct EA_FULL *ea; | |
242 | u32 off, len; | |
243 | int err; | |
244 | ||
245 | if (!(ni->ni_flags & NI_FLAG_EA)) | |
246 | return -ENODATA; | |
247 | ||
248 | if (!required) | |
249 | ni_lock(ni); | |
250 | ||
251 | len = 0; | |
252 | ||
253 | if (name_len > 255) { | |
254 | err = -ENAMETOOLONG; | |
255 | goto out; | |
256 | } | |
257 | ||
258 | err = ntfs_read_ea(ni, &ea_all, 0, &info); | |
259 | if (err) | |
260 | goto out; | |
261 | ||
262 | if (!info) | |
263 | goto out; | |
264 | ||
e8b8e97f | 265 | /* Enumerate all xattrs. */ |
0e8235d2 KK |
266 | if (!find_ea(ea_all, le32_to_cpu(info->size), name, name_len, &off, |
267 | NULL)) { | |
be71b5cb KK |
268 | err = -ENODATA; |
269 | goto out; | |
270 | } | |
271 | ea = Add2Ptr(ea_all, off); | |
272 | ||
273 | len = le16_to_cpu(ea->elength); | |
274 | if (!buffer) { | |
275 | err = 0; | |
276 | goto out; | |
277 | } | |
278 | ||
279 | if (len > size) { | |
280 | err = -ERANGE; | |
281 | if (required) | |
282 | *required = len; | |
283 | goto out; | |
284 | } | |
285 | ||
286 | memcpy(buffer, ea->name + ea->name_len + 1, len); | |
287 | err = 0; | |
288 | ||
289 | out: | |
195c52bd | 290 | kfree(ea_all); |
be71b5cb KK |
291 | if (!required) |
292 | ni_unlock(ni); | |
293 | ||
294 | return err ? err : len; | |
295 | } | |
296 | ||
297 | static noinline int ntfs_set_ea(struct inode *inode, const char *name, | |
298 | size_t name_len, const void *value, | |
1842fbc8 KK |
299 | size_t val_size, int flags, bool locked, |
300 | __le16 *ea_size) | |
be71b5cb KK |
301 | { |
302 | struct ntfs_inode *ni = ntfs_i(inode); | |
303 | struct ntfs_sb_info *sbi = ni->mi.sbi; | |
304 | int err; | |
305 | struct EA_INFO ea_info; | |
306 | const struct EA_INFO *info; | |
307 | struct EA_FULL *new_ea; | |
308 | struct EA_FULL *ea_all = NULL; | |
309 | size_t add, new_pack; | |
0e8235d2 | 310 | u32 off, size, ea_sz; |
be71b5cb KK |
311 | __le16 size_pack; |
312 | struct ATTRIB *attr; | |
313 | struct ATTR_LIST_ENTRY *le; | |
314 | struct mft_inode *mi; | |
315 | struct runs_tree ea_run; | |
316 | u64 new_sz; | |
317 | void *p; | |
318 | ||
3a2154b2 KK |
319 | if (!locked) |
320 | ni_lock(ni); | |
be71b5cb KK |
321 | |
322 | run_init(&ea_run); | |
323 | ||
324 | if (name_len > 255) { | |
325 | err = -ENAMETOOLONG; | |
326 | goto out; | |
327 | } | |
328 | ||
fa3cacf5 | 329 | add = ALIGN(struct_size(ea_all, name, 1 + name_len + val_size), 4); |
be71b5cb KK |
330 | |
331 | err = ntfs_read_ea(ni, &ea_all, add, &info); | |
332 | if (err) | |
333 | goto out; | |
334 | ||
335 | if (!info) { | |
336 | memset(&ea_info, 0, sizeof(ea_info)); | |
337 | size = 0; | |
338 | size_pack = 0; | |
339 | } else { | |
340 | memcpy(&ea_info, info, sizeof(ea_info)); | |
341 | size = le32_to_cpu(ea_info.size); | |
342 | size_pack = ea_info.size_pack; | |
343 | } | |
344 | ||
0e8235d2 | 345 | if (info && find_ea(ea_all, size, name, name_len, &off, &ea_sz)) { |
be71b5cb | 346 | struct EA_FULL *ea; |
be71b5cb KK |
347 | |
348 | if (flags & XATTR_CREATE) { | |
349 | err = -EEXIST; | |
350 | goto out; | |
351 | } | |
352 | ||
353 | ea = Add2Ptr(ea_all, off); | |
354 | ||
355 | /* | |
356 | * Check simple case when we try to insert xattr with the same value | |
357 | * e.g. ntfs_save_wsl_perm | |
358 | */ | |
359 | if (val_size && le16_to_cpu(ea->elength) == val_size && | |
360 | !memcmp(ea->name + ea->name_len + 1, value, val_size)) { | |
e8b8e97f | 361 | /* xattr already contains the required value. */ |
be71b5cb KK |
362 | goto out; |
363 | } | |
364 | ||
e8b8e97f | 365 | /* Remove current xattr. */ |
be71b5cb KK |
366 | if (ea->flags & FILE_NEED_EA) |
367 | le16_add_cpu(&ea_info.count, -1); | |
368 | ||
be71b5cb KK |
369 | le16_add_cpu(&ea_info.size_pack, 0 - packed_ea_size(ea)); |
370 | ||
371 | memmove(ea, Add2Ptr(ea, ea_sz), size - off - ea_sz); | |
372 | ||
373 | size -= ea_sz; | |
374 | memset(Add2Ptr(ea_all, size), 0, ea_sz); | |
375 | ||
376 | ea_info.size = cpu_to_le32(size); | |
377 | ||
378 | if ((flags & XATTR_REPLACE) && !val_size) { | |
e8b8e97f | 379 | /* Remove xattr. */ |
be71b5cb KK |
380 | goto update_ea; |
381 | } | |
382 | } else { | |
383 | if (flags & XATTR_REPLACE) { | |
384 | err = -ENODATA; | |
385 | goto out; | |
386 | } | |
387 | ||
388 | if (!ea_all) { | |
195c52bd | 389 | ea_all = kzalloc(add, GFP_NOFS); |
be71b5cb KK |
390 | if (!ea_all) { |
391 | err = -ENOMEM; | |
392 | goto out; | |
393 | } | |
394 | } | |
395 | } | |
396 | ||
e8b8e97f | 397 | /* Append new xattr. */ |
be71b5cb KK |
398 | new_ea = Add2Ptr(ea_all, size); |
399 | new_ea->size = cpu_to_le32(add); | |
400 | new_ea->flags = 0; | |
401 | new_ea->name_len = name_len; | |
402 | new_ea->elength = cpu_to_le16(val_size); | |
403 | memcpy(new_ea->name, name, name_len); | |
404 | new_ea->name[name_len] = 0; | |
405 | memcpy(new_ea->name + name_len + 1, value, val_size); | |
406 | new_pack = le16_to_cpu(ea_info.size_pack) + packed_ea_size(new_ea); | |
be71b5cb | 407 | ea_info.size_pack = cpu_to_le16(new_pack); |
e8b8e97f | 408 | /* New size of ATTR_EA. */ |
be71b5cb | 409 | size += add; |
cff32466 KK |
410 | ea_info.size = cpu_to_le32(size); |
411 | ||
412 | /* | |
413 | * 1. Check ea_info.size_pack for overflow. | |
e479f0a6 | 414 | * 2. New attribute size must fit value from $AttrDef |
cff32466 KK |
415 | */ |
416 | if (new_pack > 0xffff || size > sbi->ea_max_size) { | |
417 | ntfs_inode_warn( | |
418 | inode, | |
419 | "The size of extended attributes must not exceed 64KiB"); | |
be71b5cb KK |
420 | err = -EFBIG; // -EINVAL? |
421 | goto out; | |
422 | } | |
be71b5cb KK |
423 | |
424 | update_ea: | |
425 | ||
426 | if (!info) { | |
e8b8e97f | 427 | /* Create xattr. */ |
be71b5cb KK |
428 | if (!size) { |
429 | err = 0; | |
430 | goto out; | |
431 | } | |
432 | ||
433 | err = ni_insert_resident(ni, sizeof(struct EA_INFO), | |
78ab59fe KK |
434 | ATTR_EA_INFO, NULL, 0, NULL, NULL, |
435 | NULL); | |
be71b5cb KK |
436 | if (err) |
437 | goto out; | |
438 | ||
78ab59fe KK |
439 | err = ni_insert_resident(ni, 0, ATTR_EA, NULL, 0, NULL, NULL, |
440 | NULL); | |
be71b5cb KK |
441 | if (err) |
442 | goto out; | |
443 | } | |
444 | ||
445 | new_sz = size; | |
446 | err = attr_set_size(ni, ATTR_EA, NULL, 0, &ea_run, new_sz, &new_sz, | |
447 | false, NULL); | |
448 | if (err) | |
449 | goto out; | |
450 | ||
451 | le = NULL; | |
452 | attr = ni_find_attr(ni, NULL, &le, ATTR_EA_INFO, NULL, 0, NULL, &mi); | |
453 | if (!attr) { | |
454 | err = -EINVAL; | |
455 | goto out; | |
456 | } | |
457 | ||
458 | if (!size) { | |
e8b8e97f | 459 | /* Delete xattr, ATTR_EA_INFO */ |
78ab59fe | 460 | ni_remove_attr_le(ni, attr, mi, le); |
be71b5cb KK |
461 | } else { |
462 | p = resident_data_ex(attr, sizeof(struct EA_INFO)); | |
463 | if (!p) { | |
464 | err = -EINVAL; | |
465 | goto out; | |
466 | } | |
467 | memcpy(p, &ea_info, sizeof(struct EA_INFO)); | |
468 | mi->dirty = true; | |
469 | } | |
470 | ||
471 | le = NULL; | |
472 | attr = ni_find_attr(ni, NULL, &le, ATTR_EA, NULL, 0, NULL, &mi); | |
473 | if (!attr) { | |
474 | err = -EINVAL; | |
475 | goto out; | |
476 | } | |
477 | ||
478 | if (!size) { | |
e8b8e97f | 479 | /* Delete xattr, ATTR_EA */ |
78ab59fe | 480 | ni_remove_attr_le(ni, attr, mi, le); |
be71b5cb | 481 | } else if (attr->non_res) { |
42f86b12 KK |
482 | err = attr_load_runs_range(ni, ATTR_EA, NULL, 0, &ea_run, 0, |
483 | size); | |
484 | if (err) | |
485 | goto out; | |
486 | ||
63544672 | 487 | err = ntfs_sb_write_run(sbi, &ea_run, 0, ea_all, size, 0); |
be71b5cb KK |
488 | if (err) |
489 | goto out; | |
490 | } else { | |
491 | p = resident_data_ex(attr, size); | |
492 | if (!p) { | |
493 | err = -EINVAL; | |
494 | goto out; | |
495 | } | |
496 | memcpy(p, ea_all, size); | |
497 | mi->dirty = true; | |
498 | } | |
499 | ||
e8b8e97f | 500 | /* Check if we delete the last xattr. */ |
be71b5cb KK |
501 | if (size) |
502 | ni->ni_flags |= NI_FLAG_EA; | |
503 | else | |
504 | ni->ni_flags &= ~NI_FLAG_EA; | |
505 | ||
506 | if (ea_info.size_pack != size_pack) | |
507 | ni->ni_flags |= NI_FLAG_UPDATE_PARENT; | |
1842fbc8 KK |
508 | if (ea_size) |
509 | *ea_size = ea_info.size_pack; | |
be71b5cb KK |
510 | mark_inode_dirty(&ni->vfs_inode); |
511 | ||
512 | out: | |
3a2154b2 KK |
513 | if (!locked) |
514 | ni_unlock(ni); | |
be71b5cb KK |
515 | |
516 | run_close(&ea_run); | |
195c52bd | 517 | kfree(ea_all); |
be71b5cb KK |
518 | |
519 | return err; | |
520 | } | |
521 | ||
522 | #ifdef CONFIG_NTFS3_FS_POSIX_ACL | |
75c5e0c9 KK |
523 | |
524 | /* | |
525 | * ntfs_get_acl - inode_operations::get_acl | |
526 | */ | |
527 | struct posix_acl *ntfs_get_acl(struct mnt_idmap *idmap, | |
528 | struct dentry *dentry, int type) | |
be71b5cb | 529 | { |
75c5e0c9 | 530 | struct inode *inode = d_inode(dentry); |
be71b5cb KK |
531 | struct ntfs_inode *ni = ntfs_i(inode); |
532 | const char *name; | |
533 | size_t name_len; | |
534 | struct posix_acl *acl; | |
535 | size_t req; | |
536 | int err; | |
537 | void *buf; | |
538 | ||
e8b8e97f | 539 | /* Allocate PATH_MAX bytes. */ |
be71b5cb KK |
540 | buf = __getname(); |
541 | if (!buf) | |
542 | return ERR_PTR(-ENOMEM); | |
543 | ||
e8b8e97f | 544 | /* Possible values of 'type' was already checked above. */ |
be71b5cb KK |
545 | if (type == ACL_TYPE_ACCESS) { |
546 | name = XATTR_NAME_POSIX_ACL_ACCESS; | |
547 | name_len = sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1; | |
548 | } else { | |
549 | name = XATTR_NAME_POSIX_ACL_DEFAULT; | |
550 | name_len = sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1; | |
551 | } | |
552 | ||
75c5e0c9 | 553 | ni_lock(ni); |
be71b5cb KK |
554 | |
555 | err = ntfs_get_ea(inode, name, name_len, buf, PATH_MAX, &req); | |
556 | ||
75c5e0c9 | 557 | ni_unlock(ni); |
be71b5cb | 558 | |
e8b8e97f | 559 | /* Translate extended attribute to acl. */ |
2926e429 | 560 | if (err >= 0) { |
0c3bc789 | 561 | acl = posix_acl_from_xattr(&init_user_ns, buf, err); |
0bd5fdb8 KK |
562 | } else if (err == -ENODATA) { |
563 | acl = NULL; | |
be71b5cb | 564 | } else { |
0bd5fdb8 | 565 | acl = ERR_PTR(err); |
be71b5cb KK |
566 | } |
567 | ||
0bd5fdb8 KK |
568 | if (!IS_ERR(acl)) |
569 | set_cached_acl(inode, type, acl); | |
570 | ||
be71b5cb KK |
571 | __putname(buf); |
572 | ||
573 | return acl; | |
574 | } | |
575 | ||
700b7940 | 576 | static noinline int ntfs_set_acl_ex(struct mnt_idmap *idmap, |
be71b5cb | 577 | struct inode *inode, struct posix_acl *acl, |
9186d472 | 578 | int type, bool init_acl) |
be71b5cb KK |
579 | { |
580 | const char *name; | |
581 | size_t size, name_len; | |
460bbf29 KK |
582 | void *value; |
583 | int err; | |
398c35f4 | 584 | int flags; |
460bbf29 | 585 | umode_t mode; |
be71b5cb KK |
586 | |
587 | if (S_ISLNK(inode->i_mode)) | |
588 | return -EOPNOTSUPP; | |
589 | ||
460bbf29 | 590 | mode = inode->i_mode; |
be71b5cb KK |
591 | switch (type) { |
592 | case ACL_TYPE_ACCESS: | |
9186d472 KK |
593 | /* Do not change i_mode if we are in init_acl */ |
594 | if (acl && !init_acl) { | |
700b7940 | 595 | err = posix_acl_update_mode(idmap, inode, &mode, |
ba77237e KK |
596 | &acl); |
597 | if (err) | |
d4073595 | 598 | return err; |
be71b5cb KK |
599 | } |
600 | name = XATTR_NAME_POSIX_ACL_ACCESS; | |
601 | name_len = sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1; | |
602 | break; | |
603 | ||
604 | case ACL_TYPE_DEFAULT: | |
605 | if (!S_ISDIR(inode->i_mode)) | |
606 | return acl ? -EACCES : 0; | |
607 | name = XATTR_NAME_POSIX_ACL_DEFAULT; | |
608 | name_len = sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1; | |
609 | break; | |
610 | ||
611 | default: | |
612 | return -EINVAL; | |
613 | } | |
614 | ||
615 | if (!acl) { | |
398c35f4 | 616 | /* Remove xattr if it can be presented via mode. */ |
be71b5cb KK |
617 | size = 0; |
618 | value = NULL; | |
398c35f4 | 619 | flags = XATTR_REPLACE; |
be71b5cb KK |
620 | } else { |
621 | size = posix_acl_xattr_size(acl->a_count); | |
195c52bd | 622 | value = kmalloc(size, GFP_NOFS); |
be71b5cb KK |
623 | if (!value) |
624 | return -ENOMEM; | |
0c3bc789 | 625 | err = posix_acl_to_xattr(&init_user_ns, acl, value, size); |
be71b5cb KK |
626 | if (err < 0) |
627 | goto out; | |
398c35f4 | 628 | flags = 0; |
be71b5cb KK |
629 | } |
630 | ||
1842fbc8 | 631 | err = ntfs_set_ea(inode, name, name_len, value, size, flags, 0, NULL); |
398c35f4 KK |
632 | if (err == -ENODATA && !size) |
633 | err = 0; /* Removing non existed xattr. */ | |
460bbf29 | 634 | if (!err) { |
be71b5cb | 635 | set_cached_acl(inode, type, acl); |
e31195a3 KK |
636 | inode->i_mode = mode; |
637 | inode->i_ctime = current_time(inode); | |
638 | mark_inode_dirty(inode); | |
460bbf29 | 639 | } |
be71b5cb KK |
640 | |
641 | out: | |
195c52bd | 642 | kfree(value); |
be71b5cb KK |
643 | |
644 | return err; | |
645 | } | |
646 | ||
647 | /* | |
e8b8e97f | 648 | * ntfs_set_acl - inode_operations::set_acl |
be71b5cb | 649 | */ |
13e83a49 | 650 | int ntfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, |
be71b5cb KK |
651 | struct posix_acl *acl, int type) |
652 | { | |
700b7940 | 653 | return ntfs_set_acl_ex(idmap, d_inode(dentry), acl, type, false); |
be71b5cb KK |
654 | } |
655 | ||
656 | /* | |
e8b8e97f KA |
657 | * ntfs_init_acl - Initialize the ACLs of a new inode. |
658 | * | |
659 | * Called from ntfs_create_inode(). | |
be71b5cb | 660 | */ |
700b7940 | 661 | int ntfs_init_acl(struct mnt_idmap *idmap, struct inode *inode, |
be71b5cb KK |
662 | struct inode *dir) |
663 | { | |
664 | struct posix_acl *default_acl, *acl; | |
665 | int err; | |
666 | ||
66019837 KK |
667 | err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); |
668 | if (err) | |
669 | return err; | |
be71b5cb | 670 | |
66019837 | 671 | if (default_acl) { |
700b7940 | 672 | err = ntfs_set_acl_ex(idmap, inode, default_acl, |
9186d472 | 673 | ACL_TYPE_DEFAULT, true); |
be71b5cb | 674 | posix_acl_release(default_acl); |
66019837 KK |
675 | } else { |
676 | inode->i_default_acl = NULL; | |
be71b5cb KK |
677 | } |
678 | ||
19e890ff | 679 | if (acl) { |
66019837 | 680 | if (!err) |
700b7940 | 681 | err = ntfs_set_acl_ex(idmap, inode, acl, |
9186d472 | 682 | ACL_TYPE_ACCESS, true); |
66019837 | 683 | posix_acl_release(acl); |
19e890ff YX |
684 | } else { |
685 | inode->i_acl = NULL; | |
66019837 | 686 | } |
be71b5cb | 687 | |
be71b5cb KK |
688 | return err; |
689 | } | |
690 | #endif | |
691 | ||
692 | /* | |
e8b8e97f | 693 | * ntfs_acl_chmod - Helper for ntfs3_setattr(). |
be71b5cb | 694 | */ |
13e83a49 | 695 | int ntfs_acl_chmod(struct mnt_idmap *idmap, struct dentry *dentry) |
be71b5cb | 696 | { |
138060ba | 697 | struct inode *inode = d_inode(dentry); |
be71b5cb KK |
698 | struct super_block *sb = inode->i_sb; |
699 | ||
700 | if (!(sb->s_flags & SB_POSIXACL)) | |
701 | return 0; | |
702 | ||
703 | if (S_ISLNK(inode->i_mode)) | |
704 | return -EOPNOTSUPP; | |
705 | ||
13e83a49 | 706 | return posix_acl_chmod(idmap, dentry, inode->i_mode); |
be71b5cb KK |
707 | } |
708 | ||
be71b5cb | 709 | /* |
e8b8e97f | 710 | * ntfs_listxattr - inode_operations::listxattr |
be71b5cb KK |
711 | */ |
712 | ssize_t ntfs_listxattr(struct dentry *dentry, char *buffer, size_t size) | |
713 | { | |
714 | struct inode *inode = d_inode(dentry); | |
715 | struct ntfs_inode *ni = ntfs_i(inode); | |
716 | ssize_t ret; | |
717 | ||
718 | if (!(ni->ni_flags & NI_FLAG_EA)) { | |
719 | /* no xattr in file */ | |
720 | return 0; | |
721 | } | |
722 | ||
723 | ni_lock(ni); | |
724 | ||
725 | ret = ntfs_list_ea(ni, buffer, size); | |
726 | ||
727 | ni_unlock(ni); | |
728 | ||
729 | return ret; | |
730 | } | |
731 | ||
732 | static int ntfs_getxattr(const struct xattr_handler *handler, struct dentry *de, | |
733 | struct inode *inode, const char *name, void *buffer, | |
734 | size_t size) | |
735 | { | |
736 | int err; | |
737 | struct ntfs_inode *ni = ntfs_i(inode); | |
be71b5cb | 738 | |
e8b8e97f | 739 | /* Dispatch request. */ |
d45da67c | 740 | if (!strcmp(name, SYSTEM_DOS_ATTRIB)) { |
be71b5cb KK |
741 | /* system.dos_attrib */ |
742 | if (!buffer) { | |
743 | err = sizeof(u8); | |
744 | } else if (size < sizeof(u8)) { | |
745 | err = -ENODATA; | |
746 | } else { | |
747 | err = sizeof(u8); | |
748 | *(u8 *)buffer = le32_to_cpu(ni->std_fa); | |
749 | } | |
750 | goto out; | |
751 | } | |
752 | ||
0d19f3d7 DP |
753 | if (!strcmp(name, SYSTEM_NTFS_ATTRIB) || |
754 | !strcmp(name, SYSTEM_NTFS_ATTRIB_BE)) { | |
be71b5cb KK |
755 | /* system.ntfs_attrib */ |
756 | if (!buffer) { | |
757 | err = sizeof(u32); | |
758 | } else if (size < sizeof(u32)) { | |
759 | err = -ENODATA; | |
760 | } else { | |
761 | err = sizeof(u32); | |
762 | *(u32 *)buffer = le32_to_cpu(ni->std_fa); | |
0d19f3d7 | 763 | if (!strcmp(name, SYSTEM_NTFS_ATTRIB_BE)) |
0203471d | 764 | *(__be32 *)buffer = cpu_to_be32(*(u32 *)buffer); |
be71b5cb KK |
765 | } |
766 | goto out; | |
767 | } | |
768 | ||
d45da67c | 769 | if (!strcmp(name, SYSTEM_NTFS_SECURITY)) { |
be71b5cb KK |
770 | /* system.ntfs_security*/ |
771 | struct SECURITY_DESCRIPTOR_RELATIVE *sd = NULL; | |
772 | size_t sd_size = 0; | |
773 | ||
774 | if (!is_ntfs3(ni->mi.sbi)) { | |
e8b8e97f | 775 | /* We should get nt4 security. */ |
be71b5cb KK |
776 | err = -EINVAL; |
777 | goto out; | |
778 | } else if (le32_to_cpu(ni->std_security_id) < | |
779 | SECURITY_ID_FIRST) { | |
780 | err = -ENOENT; | |
781 | goto out; | |
782 | } | |
783 | ||
784 | err = ntfs_get_security_by_id(ni->mi.sbi, ni->std_security_id, | |
785 | &sd, &sd_size); | |
786 | if (err) | |
787 | goto out; | |
788 | ||
789 | if (!is_sd_valid(sd, sd_size)) { | |
790 | ntfs_inode_warn( | |
791 | inode, | |
792 | "looks like you get incorrect security descriptor id=%u", | |
793 | ni->std_security_id); | |
794 | } | |
795 | ||
796 | if (!buffer) { | |
797 | err = sd_size; | |
798 | } else if (size < sd_size) { | |
799 | err = -ENODATA; | |
800 | } else { | |
801 | err = sd_size; | |
802 | memcpy(buffer, sd, sd_size); | |
803 | } | |
195c52bd | 804 | kfree(sd); |
be71b5cb KK |
805 | goto out; |
806 | } | |
807 | ||
e8b8e97f | 808 | /* Deal with NTFS extended attribute. */ |
d45da67c | 809 | err = ntfs_get_ea(inode, name, strlen(name), buffer, size, NULL); |
be71b5cb KK |
810 | |
811 | out: | |
812 | return err; | |
813 | } | |
814 | ||
815 | /* | |
e8b8e97f | 816 | * ntfs_setxattr - inode_operations::setxattr |
be71b5cb KK |
817 | */ |
818 | static noinline int ntfs_setxattr(const struct xattr_handler *handler, | |
39f60c1c | 819 | struct mnt_idmap *idmap, |
be71b5cb KK |
820 | struct dentry *de, struct inode *inode, |
821 | const char *name, const void *value, | |
822 | size_t size, int flags) | |
823 | { | |
824 | int err = -EINVAL; | |
825 | struct ntfs_inode *ni = ntfs_i(inode); | |
be71b5cb KK |
826 | enum FILE_ATTRIBUTE new_fa; |
827 | ||
e8b8e97f | 828 | /* Dispatch request. */ |
d45da67c | 829 | if (!strcmp(name, SYSTEM_DOS_ATTRIB)) { |
be71b5cb KK |
830 | if (sizeof(u8) != size) |
831 | goto out; | |
832 | new_fa = cpu_to_le32(*(u8 *)value); | |
833 | goto set_new_fa; | |
834 | } | |
835 | ||
0d19f3d7 DP |
836 | if (!strcmp(name, SYSTEM_NTFS_ATTRIB) || |
837 | !strcmp(name, SYSTEM_NTFS_ATTRIB_BE)) { | |
be71b5cb KK |
838 | if (size != sizeof(u32)) |
839 | goto out; | |
0d19f3d7 | 840 | if (!strcmp(name, SYSTEM_NTFS_ATTRIB_BE)) |
0203471d | 841 | new_fa = cpu_to_le32(be32_to_cpu(*(__be32 *)value)); |
0d19f3d7 DP |
842 | else |
843 | new_fa = cpu_to_le32(*(u32 *)value); | |
be71b5cb KK |
844 | |
845 | if (S_ISREG(inode->i_mode)) { | |
e8b8e97f | 846 | /* Process compressed/sparsed in special way. */ |
be71b5cb KK |
847 | ni_lock(ni); |
848 | err = ni_new_attr_flags(ni, new_fa); | |
849 | ni_unlock(ni); | |
850 | if (err) | |
851 | goto out; | |
852 | } | |
853 | set_new_fa: | |
854 | /* | |
855 | * Thanks Mark Harmstone: | |
e8b8e97f | 856 | * Keep directory bit consistency. |
be71b5cb KK |
857 | */ |
858 | if (S_ISDIR(inode->i_mode)) | |
859 | new_fa |= FILE_ATTRIBUTE_DIRECTORY; | |
860 | else | |
861 | new_fa &= ~FILE_ATTRIBUTE_DIRECTORY; | |
862 | ||
863 | if (ni->std_fa != new_fa) { | |
864 | ni->std_fa = new_fa; | |
865 | if (new_fa & FILE_ATTRIBUTE_READONLY) | |
866 | inode->i_mode &= ~0222; | |
867 | else | |
868 | inode->i_mode |= 0222; | |
e8b8e97f | 869 | /* Std attribute always in primary record. */ |
be71b5cb KK |
870 | ni->mi.dirty = true; |
871 | mark_inode_dirty(inode); | |
872 | } | |
873 | err = 0; | |
874 | ||
875 | goto out; | |
876 | } | |
877 | ||
d45da67c | 878 | if (!strcmp(name, SYSTEM_NTFS_SECURITY)) { |
be71b5cb KK |
879 | /* system.ntfs_security*/ |
880 | __le32 security_id; | |
881 | bool inserted; | |
882 | struct ATTR_STD_INFO5 *std; | |
883 | ||
884 | if (!is_ntfs3(ni->mi.sbi)) { | |
885 | /* | |
e8b8e97f KA |
886 | * We should replace ATTR_SECURE. |
887 | * Skip this way cause it is nt4 feature. | |
be71b5cb KK |
888 | */ |
889 | err = -EINVAL; | |
890 | goto out; | |
891 | } | |
892 | ||
893 | if (!is_sd_valid(value, size)) { | |
894 | err = -EINVAL; | |
895 | ntfs_inode_warn( | |
896 | inode, | |
897 | "you try to set invalid security descriptor"); | |
898 | goto out; | |
899 | } | |
900 | ||
901 | err = ntfs_insert_security(ni->mi.sbi, value, size, | |
902 | &security_id, &inserted); | |
903 | if (err) | |
904 | goto out; | |
905 | ||
906 | ni_lock(ni); | |
907 | std = ni_std5(ni); | |
908 | if (!std) { | |
909 | err = -EINVAL; | |
910 | } else if (std->security_id != security_id) { | |
911 | std->security_id = ni->std_security_id = security_id; | |
e8b8e97f | 912 | /* Std attribute always in primary record. */ |
be71b5cb KK |
913 | ni->mi.dirty = true; |
914 | mark_inode_dirty(&ni->vfs_inode); | |
915 | } | |
916 | ni_unlock(ni); | |
917 | goto out; | |
918 | } | |
919 | ||
e8b8e97f | 920 | /* Deal with NTFS extended attribute. */ |
1842fbc8 KK |
921 | err = ntfs_set_ea(inode, name, strlen(name), value, size, flags, 0, |
922 | NULL); | |
be71b5cb KK |
923 | |
924 | out: | |
2d44667c KK |
925 | inode->i_ctime = current_time(inode); |
926 | mark_inode_dirty(inode); | |
927 | ||
be71b5cb KK |
928 | return err; |
929 | } | |
930 | ||
931 | /* | |
932 | * ntfs_save_wsl_perm | |
933 | * | |
934 | * save uid/gid/mode in xattr | |
935 | */ | |
1842fbc8 | 936 | int ntfs_save_wsl_perm(struct inode *inode, __le16 *ea_size) |
be71b5cb KK |
937 | { |
938 | int err; | |
939 | __le32 value; | |
3a2154b2 | 940 | struct ntfs_inode *ni = ntfs_i(inode); |
be71b5cb | 941 | |
3a2154b2 | 942 | ni_lock(ni); |
be71b5cb KK |
943 | value = cpu_to_le32(i_uid_read(inode)); |
944 | err = ntfs_set_ea(inode, "$LXUID", sizeof("$LXUID") - 1, &value, | |
1842fbc8 | 945 | sizeof(value), 0, true, ea_size); |
be71b5cb KK |
946 | if (err) |
947 | goto out; | |
948 | ||
949 | value = cpu_to_le32(i_gid_read(inode)); | |
950 | err = ntfs_set_ea(inode, "$LXGID", sizeof("$LXGID") - 1, &value, | |
1842fbc8 | 951 | sizeof(value), 0, true, ea_size); |
be71b5cb KK |
952 | if (err) |
953 | goto out; | |
954 | ||
955 | value = cpu_to_le32(inode->i_mode); | |
956 | err = ntfs_set_ea(inode, "$LXMOD", sizeof("$LXMOD") - 1, &value, | |
1842fbc8 | 957 | sizeof(value), 0, true, ea_size); |
be71b5cb KK |
958 | if (err) |
959 | goto out; | |
960 | ||
961 | if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { | |
962 | value = cpu_to_le32(inode->i_rdev); | |
963 | err = ntfs_set_ea(inode, "$LXDEV", sizeof("$LXDEV") - 1, &value, | |
1842fbc8 | 964 | sizeof(value), 0, true, ea_size); |
be71b5cb KK |
965 | if (err) |
966 | goto out; | |
967 | } | |
968 | ||
969 | out: | |
3a2154b2 | 970 | ni_unlock(ni); |
be71b5cb KK |
971 | /* In case of error should we delete all WSL xattr? */ |
972 | return err; | |
973 | } | |
974 | ||
975 | /* | |
976 | * ntfs_get_wsl_perm | |
977 | * | |
978 | * get uid/gid/mode from xattr | |
979 | * it is called from ntfs_iget5->ntfs_read_mft | |
980 | */ | |
981 | void ntfs_get_wsl_perm(struct inode *inode) | |
982 | { | |
983 | size_t sz; | |
984 | __le32 value[3]; | |
985 | ||
986 | if (ntfs_get_ea(inode, "$LXUID", sizeof("$LXUID") - 1, &value[0], | |
987 | sizeof(value[0]), &sz) == sizeof(value[0]) && | |
988 | ntfs_get_ea(inode, "$LXGID", sizeof("$LXGID") - 1, &value[1], | |
989 | sizeof(value[1]), &sz) == sizeof(value[1]) && | |
990 | ntfs_get_ea(inode, "$LXMOD", sizeof("$LXMOD") - 1, &value[2], | |
991 | sizeof(value[2]), &sz) == sizeof(value[2])) { | |
992 | i_uid_write(inode, (uid_t)le32_to_cpu(value[0])); | |
993 | i_gid_write(inode, (gid_t)le32_to_cpu(value[1])); | |
994 | inode->i_mode = le32_to_cpu(value[2]); | |
995 | ||
996 | if (ntfs_get_ea(inode, "$LXDEV", sizeof("$$LXDEV") - 1, | |
997 | &value[0], sizeof(value), | |
998 | &sz) == sizeof(value[0])) { | |
999 | inode->i_rdev = le32_to_cpu(value[0]); | |
1000 | } | |
1001 | } | |
1002 | } | |
1003 | ||
1004 | static bool ntfs_xattr_user_list(struct dentry *dentry) | |
1005 | { | |
1006 | return true; | |
1007 | } | |
1008 | ||
1009 | // clang-format off | |
a26aa123 | 1010 | static const struct xattr_handler ntfs_other_xattr_handler = { |
be71b5cb KK |
1011 | .prefix = "", |
1012 | .get = ntfs_getxattr, | |
1013 | .set = ntfs_setxattr, | |
1014 | .list = ntfs_xattr_user_list, | |
1015 | }; | |
1016 | ||
1017 | const struct xattr_handler *ntfs_xattr_handlers[] = { | |
a26aa123 | 1018 | &ntfs_other_xattr_handler, |
be71b5cb KK |
1019 | NULL, |
1020 | }; | |
1021 | // clang-format on |