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