1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Processing of reparse points 4 * 5 * Part of this file is based on code from the NTFS-3G. 6 * 7 * Copyright (c) 2008-2021 Jean-Pierre Andre 8 * Copyright (c) 2025 LG Electronics Co., Ltd. 9 */ 10 11 #include "ntfs.h" 12 #include "layout.h" 13 #include "attrib.h" 14 #include "inode.h" 15 #include "dir.h" 16 #include "volume.h" 17 #include "mft.h" 18 #include "index.h" 19 #include "lcnalloc.h" 20 #include "reparse.h" 21 22 struct wsl_link_reparse_data { 23 __le32 type; 24 char link[]; 25 }; 26 27 struct wof_reparse_data { 28 __le32 version; 29 __le32 provider; 30 __le32 provider_version; 31 __le32 compression_format; 32 } __packed; 33 34 #define WOF_CURRENT_VERSION cpu_to_le32(1) 35 36 #define WOF_PROVIDER_WIM cpu_to_le32(1) 37 #define WOF_PROVIDER_FILE cpu_to_le32(2) 38 39 #define WOF_PROVIDER_CURRENT_VERSION cpu_to_le32(1) 40 41 #define WOF_COMPRESSION_XPRESS4K cpu_to_le32(0) 42 #define WOF_COMPRESSION_LZX cpu_to_le32(1) 43 #define WOF_COMPRESSION_XPRESS8K cpu_to_le32(2) 44 #define WOF_COMPRESSION_XPRESS16K cpu_to_le32(3) 45 46 static bool reparse_name_is_valid(size_t size, size_t name_off, u16 len) 47 { 48 if ((name_off | len) & 1) 49 return false; 50 51 return name_off + len <= size; 52 } 53 54 /* 55 * Windows-native reparse payloads store pathnames as UTF-16 strings with '\\' 56 * separators. Convert the on-disk UTF-16 target into the mount's NLS and 57 * normalize path separators. 58 */ 59 static int ntfs_reparse_target_to_nls(struct ntfs_volume *vol, 60 const __le16 *uname, u16 ulen, 61 char **target) 62 { 63 int err, i; 64 65 *target = NULL; 66 ulen >>= 1; 67 if (!ulen) 68 return -EINVAL; 69 70 if (!uname[ulen - 1]) 71 ulen--; 72 73 err = ntfs_ucstonls(vol, uname, ulen, (unsigned char **)target, 0); 74 if (err < 0) { 75 ntfs_attr_name_free((unsigned char **)target); 76 return err; 77 } 78 79 for (i = 0; i < err; i++) { 80 if ((*target)[i] == '\\') 81 (*target)[i] = '/'; 82 } 83 84 return 0; 85 } 86 87 /* Index entry in $Extend/$Reparse */ 88 struct reparse_index { 89 struct index_entry_header header; 90 struct reparse_index_key key; 91 __le32 filling; 92 }; 93 94 __le16 reparse_index_name[] = {cpu_to_le16('$'), cpu_to_le16('R'), 0}; 95 96 97 /* 98 * Check if the reparse point attribute buffer is valid. 99 * Returns true if valid, false otherwise. 100 */ 101 static bool valid_reparse_buffer(struct ntfs_inode *ni, 102 const struct reparse_point *reparse_attr, 103 size_t size, 104 size_t payload_min_len) 105 { 106 size_t expected; 107 108 if (!ni || !reparse_attr) 109 return false; 110 111 /* Minimum size must cover reparse_point header */ 112 if (size < sizeof(struct reparse_point)) 113 return false; 114 115 /* The payload must contain the fixed fields for the current tag. */ 116 if (payload_min_len && 117 le16_to_cpu(reparse_attr->reparse_data_length) < payload_min_len) 118 return false; 119 120 /* Reserved zero tag is invalid */ 121 if (reparse_attr->reparse_tag == IO_REPARSE_TAG_RESERVED_ZERO) 122 return false; 123 124 /* Calculate expected total size */ 125 expected = sizeof(struct reparse_point) + 126 le16_to_cpu(reparse_attr->reparse_data_length); 127 128 /* Add GUID size for non-Microsoft tags */ 129 if (!(reparse_attr->reparse_tag & IO_REPARSE_TAG_IS_MICROSOFT)) 130 expected += sizeof(struct guid); 131 132 /* Buffer must exactly match the expected size */ 133 return expected == size; 134 } 135 136 /* 137 * Do some sanity checks on reparse data 138 * 139 * Microsoft reparse points have an 8-byte header whereas 140 * non-Microsoft reparse points have a 24-byte header. In each case, 141 * 'reparse_data_length' must equal the number of non-header bytes. 142 * 143 * If the reparse data looks like a junction point or symbolic 144 * link, more checks can be done. 145 */ 146 static bool valid_reparse_data(struct ntfs_inode *ni, 147 const struct reparse_point *reparse_attr, size_t size) 148 { 149 if (size < sizeof(*reparse_attr)) 150 return false; 151 152 switch (reparse_attr->reparse_tag) { 153 case IO_REPARSE_TAG_MOUNT_POINT: 154 { 155 struct mount_point_reparse_data *data; 156 size_t data_offs; 157 158 if (!valid_reparse_buffer(ni, reparse_attr, size, sizeof(*data))) 159 return false; 160 161 data = (struct mount_point_reparse_data *)reparse_attr->reparse_data; 162 data_offs = offsetof(struct reparse_point, reparse_data) + 163 offsetof(struct mount_point_reparse_data, path_buffer); 164 165 if (!reparse_name_is_valid(size, 166 data_offs + 167 le16_to_cpu(data->substitute_name_offset), 168 le16_to_cpu(data->substitute_name_length)) || 169 !reparse_name_is_valid(size, 170 data_offs + 171 le16_to_cpu(data->print_name_offset), 172 le16_to_cpu(data->print_name_length))) 173 return false; 174 break; 175 } 176 case IO_REPARSE_TAG_SYMLINK: 177 { 178 struct symlink_reparse_data *data; 179 size_t data_offs; 180 181 if (!valid_reparse_buffer(ni, reparse_attr, size, 182 sizeof(*data))) 183 return false; 184 185 data = (struct symlink_reparse_data *)reparse_attr->reparse_data; 186 data_offs = offsetof(struct reparse_point, reparse_data) + 187 offsetof(struct symlink_reparse_data, path_buffer); 188 189 if (!reparse_name_is_valid(size, 190 data_offs + 191 le16_to_cpu(data->substitute_name_offset), 192 le16_to_cpu(data->substitute_name_length)) || 193 !reparse_name_is_valid(size, 194 data_offs + 195 le16_to_cpu(data->print_name_offset), 196 le16_to_cpu(data->print_name_length))) 197 return false; 198 break; 199 } 200 case IO_REPARSE_TAG_LX_SYMLINK: 201 { 202 struct wsl_link_reparse_data *data; 203 204 if (!valid_reparse_buffer(ni, reparse_attr, size, 205 sizeof(*data))) 206 return false; 207 208 data = (struct wsl_link_reparse_data *)reparse_attr->reparse_data; 209 210 if (le16_to_cpu(reparse_attr->reparse_data_length) <= sizeof(data->type) || 211 data->type != cpu_to_le32(2)) 212 return false; 213 break; 214 } 215 case IO_REPARSE_TAG_AF_UNIX: 216 case IO_REPARSE_TAG_LX_FIFO: 217 case IO_REPARSE_TAG_LX_CHR: 218 case IO_REPARSE_TAG_LX_BLK: 219 if (!valid_reparse_buffer(ni, reparse_attr, size, 0)) 220 return false; 221 if (le16_to_cpu(reparse_attr->reparse_data_length) || 222 !(ni->flags & FILE_ATTRIBUTE_RECALL_ON_OPEN)) 223 return false; 224 break; 225 case IO_REPARSE_TAG_WOF: { 226 if (!valid_reparse_buffer(ni, reparse_attr, size, 227 sizeof(struct wof_reparse_data))) 228 return false; 229 break; 230 } 231 default: 232 if (!valid_reparse_buffer(ni, reparse_attr, size, 0)) 233 return false; 234 break; 235 } 236 237 return true; 238 } 239 240 static unsigned int ntfs_reparse_tag_mode(__le32 reparse_tag) 241 { 242 unsigned int mode = 0; 243 244 switch (reparse_tag) { 245 case IO_REPARSE_TAG_MOUNT_POINT: 246 case IO_REPARSE_TAG_SYMLINK: 247 case IO_REPARSE_TAG_LX_SYMLINK: 248 mode = S_IFLNK; 249 break; 250 case IO_REPARSE_TAG_AF_UNIX: 251 mode = S_IFSOCK; 252 break; 253 case IO_REPARSE_TAG_LX_FIFO: 254 mode = S_IFIFO; 255 break; 256 case IO_REPARSE_TAG_LX_CHR: 257 mode = S_IFCHR; 258 break; 259 case IO_REPARSE_TAG_LX_BLK: 260 mode = S_IFBLK; 261 } 262 263 return mode; 264 } 265 266 /* 267 * Parse reparse point data and initialize its in-memory representation. 268 */ 269 int ntfs_parse_reparse(struct ntfs_inode *ni, unsigned int *mode) 270 { 271 s64 attr_size = 0; 272 int err = -EINVAL; 273 unsigned int lth; 274 struct reparse_point *reparse_attr; 275 276 kvfree(ni->target); 277 ni->target = NULL; 278 ni->reparse_tag = 0; 279 ni->reparse_flags = 0; 280 *mode = 0; 281 282 reparse_attr = ntfs_attr_readall(ni, AT_REPARSE_POINT, NULL, 0, 283 &attr_size); 284 if (IS_ERR(reparse_attr)) { 285 err = PTR_ERR(reparse_attr); 286 ntfs_error(ni->vol->sb, 287 "Failed to read reparse point: %d.", err); 288 return err; 289 } 290 if (!valid_reparse_data(ni, reparse_attr, attr_size)) { 291 ntfs_error(ni->vol->sb, "Invalid reparse point."); 292 err = -EFSCORRUPTED; 293 goto out; 294 } 295 296 switch (reparse_attr->reparse_tag) { 297 case IO_REPARSE_TAG_MOUNT_POINT: 298 { 299 struct mount_point_reparse_data *data = 300 (struct mount_point_reparse_data *)reparse_attr->reparse_data; 301 const __le16 *name = (const __le16 *)((u8 *)data->path_buffer + 302 le16_to_cpu(data->substitute_name_offset)); 303 304 err = ntfs_reparse_target_to_nls(ni->vol, 305 name, 306 le16_to_cpu(data->substitute_name_length), 307 &ni->target); 308 break; 309 } 310 case IO_REPARSE_TAG_SYMLINK: 311 { 312 struct symlink_reparse_data *data = 313 (struct symlink_reparse_data *)reparse_attr->reparse_data; 314 const __le16 *name = (const __le16 *)((u8 *)data->path_buffer + 315 le16_to_cpu(data->substitute_name_offset)); 316 317 err = ntfs_reparse_target_to_nls(ni->vol, 318 name, 319 le16_to_cpu(data->substitute_name_length), 320 &ni->target); 321 if (!err) 322 ni->reparse_flags = data->flags; 323 break; 324 } 325 case IO_REPARSE_TAG_LX_SYMLINK: 326 { 327 struct wsl_link_reparse_data *wsl_link_data = 328 (struct wsl_link_reparse_data *)reparse_attr->reparse_data; 329 330 if (wsl_link_data->type == cpu_to_le32(2)) { 331 lth = le16_to_cpu(reparse_attr->reparse_data_length) - 332 sizeof(wsl_link_data->type); 333 ni->target = kvzalloc(lth + 1, GFP_NOFS); 334 if (ni->target) { 335 memcpy(ni->target, wsl_link_data->link, lth); 336 ni->target[lth] = 0; 337 err = 0; 338 } 339 } 340 break; 341 } 342 case IO_REPARSE_TAG_WOF: 343 { 344 #ifdef CONFIG_NTFS_FS_WOF_COMPRESSION 345 const struct wof_reparse_data *wof_data = 346 (const struct wof_reparse_data *)reparse_attr->reparse_data; 347 348 ni->itype.compressed.block_size_bits = 0; 349 ni->itype.compressed.block_size = 0; 350 if (wof_data->version == WOF_CURRENT_VERSION && 351 wof_data->provider == WOF_PROVIDER_FILE && 352 wof_data->provider_version == 353 WOF_PROVIDER_CURRENT_VERSION) { 354 switch (wof_data->compression_format) { 355 case WOF_COMPRESSION_XPRESS4K: 356 ni->itype.compressed.block_size_bits = 357 12; 358 break; 359 case WOF_COMPRESSION_XPRESS8K: 360 ni->itype.compressed.block_size_bits = 361 13; 362 break; 363 case WOF_COMPRESSION_XPRESS16K: 364 ni->itype.compressed.block_size_bits = 365 14; 366 break; 367 case WOF_COMPRESSION_LZX: 368 ni->itype.compressed.block_size_bits = 369 15; 370 break; 371 } 372 } 373 if (ni->itype.compressed.block_size_bits) 374 ni->itype.compressed.block_size = 375 1 376 << ni->itype.compressed.block_size_bits; 377 #endif 378 NInoSetWofCompressed(ni); 379 VFS_I(ni)->i_mode &= ~0222; 380 err = 0; 381 break; 382 } 383 default: 384 err = 0; 385 } 386 387 if (!err) { 388 *mode = ntfs_reparse_tag_mode( 389 reparse_attr->reparse_tag); 390 ni->reparse_tag = reparse_attr->reparse_tag; 391 } 392 393 out: 394 kvfree(reparse_attr); 395 396 return err; 397 } 398 399 unsigned int ntfs_reparse_tag_dt_types(struct ntfs_volume *vol, unsigned long mref) 400 { 401 s64 attr_size = 0; 402 struct reparse_point *reparse_attr; 403 unsigned int dt_type = DT_UNKNOWN; 404 struct inode *vi; 405 406 vi = ntfs_iget(vol->sb, mref); 407 if (IS_ERR(vi)) 408 return DT_UNKNOWN; 409 410 reparse_attr = (struct reparse_point *)ntfs_attr_readall(NTFS_I(vi), 411 AT_REPARSE_POINT, NULL, 0, &attr_size); 412 if (IS_ERR(reparse_attr)) 413 reparse_attr = NULL; 414 415 if (reparse_attr && attr_size >= sizeof(*reparse_attr)) { 416 switch (reparse_attr->reparse_tag) { 417 case IO_REPARSE_TAG_MOUNT_POINT: 418 case IO_REPARSE_TAG_SYMLINK: 419 case IO_REPARSE_TAG_LX_SYMLINK: 420 dt_type = DT_LNK; 421 break; 422 case IO_REPARSE_TAG_AF_UNIX: 423 dt_type = DT_SOCK; 424 break; 425 case IO_REPARSE_TAG_LX_FIFO: 426 dt_type = DT_FIFO; 427 break; 428 case IO_REPARSE_TAG_LX_CHR: 429 dt_type = DT_CHR; 430 break; 431 case IO_REPARSE_TAG_LX_BLK: 432 dt_type = DT_BLK; 433 } 434 } 435 436 kvfree(reparse_attr); 437 438 iput(vi); 439 return dt_type; 440 } 441 442 static bool ntfs_is_drive_letter(const char *target) 443 { 444 return ((target[0] >= 'A' && target[0] <= 'Z') || 445 (target[0] >= 'a' && target[0] <= 'z')) && 446 target[1] == ':'; 447 } 448 449 /* 450 * ntfs_translate_symlink_path 451 * 452 * @dentry: dentry of the symlink/junction being resolved 453 * @target: NUL-terminated NLS target string with '\\' already normalized to '/' 454 * @translated: out parameter, set to a newly kmalloc'd relative path on success 455 * 456 * Windows junctions (IO_REPARSE_TAG_MOUNT_POINT) and non-relative symlinks 457 * (IO_REPARSE_TAG_SYMLINK without SYMLINK_FLAG_RELATIVE) store substitute 458 * names such as "/??/C:/foo", "//?/C:/foo", "/foo", or "C:/foo". Linux 459 * cannot continue pathname lookup from those syntaxes, so rewrite them as a 460 * path relative to the symlink's containing directory on this NTFS volume, 461 * anchored at the volume root via "../". 462 * 463 * Note: bind-mounted subtrees of the volume may resolve to unexpected 464 * locations because the computed "../" depth is relative to the NTFS volume 465 * root, not the bind-mounted subtree root. 466 * 467 * Return: 0 on success with *translated set to a newly allocated string the 468 * caller must kfree(); negative errno on failure. 469 */ 470 int ntfs_translate_symlink_path(struct dentry *dentry, const char *target, 471 char **translated) 472 { 473 char *buf, *link_path, *out, *p; 474 const char *path, *tail; 475 unsigned int up_levels = 0; 476 size_t tail_len, out_len; 477 int err; 478 479 if (!dentry || !target || !translated) 480 return -EINVAL; 481 482 path = target; 483 /* reject UNC path. */ 484 if (path[0] == '/' && path[1] == '/' && 485 !(path[2] == '?' && path[3] == '/')) 486 return -EOPNOTSUPP; 487 488 /* target starts with "/??/" or "//?/"? */ 489 if ((path[0] == '/' && path[1] == '?' && path[2] == '?' && path[3] == '/') || 490 (path[0] == '/' && path[1] == '/' && path[2] == '?' && path[3] == '/')) 491 path += 4; 492 493 /* target must start with a drive character or '/'. */ 494 if (ntfs_is_drive_letter(path)) { 495 if (path[2] && path[2] != '/') 496 return -EOPNOTSUPP; 497 tail = path + 2; 498 if (*tail == '/') 499 tail++; 500 } else if (*path == '/') { 501 tail = path + 1; 502 } else { 503 return -EOPNOTSUPP; 504 } 505 506 tail_len = strlen(tail); 507 508 buf = kmalloc(PATH_MAX, GFP_NOFS); 509 if (!buf) 510 return -ENOMEM; 511 512 link_path = dentry_path_raw(dentry, buf, PATH_MAX); 513 if (IS_ERR(link_path)) { 514 err = PTR_ERR(link_path); 515 goto out; 516 } 517 518 /* count '/' after the leading slash. */ 519 for (p = link_path + 1; *p; p++) 520 if (*p == '/') 521 up_levels++; 522 523 /* build "./" + ("../" * up_levels) + tail. */ 524 out_len = 2 + up_levels * 3 + tail_len; 525 if (out_len >= PATH_MAX) { 526 err = -ENAMETOOLONG; 527 goto out; 528 } 529 530 out = kmalloc(out_len + 1, GFP_NOFS); 531 if (!out) { 532 err = -ENOMEM; 533 goto out; 534 } 535 536 memcpy(out, "./", 2); 537 p = out + 2; 538 while (up_levels--) { 539 memcpy(p, "../", 3); 540 p += 3; 541 } 542 memcpy(p, tail, tail_len + 1); 543 544 *translated = out; 545 err = 0; 546 out: 547 kfree(buf); 548 return err; 549 } 550 551 /* 552 * Set the index for new reparse data 553 */ 554 static int set_reparse_index(struct ntfs_inode *ni, struct ntfs_index_context *xr, 555 __le32 reparse_tag) 556 { 557 struct reparse_index indx; 558 u64 file_id_cpu; 559 __le64 file_id; 560 561 file_id_cpu = MK_MREF(ni->mft_no, ni->seq_no); 562 file_id = cpu_to_le64(file_id_cpu); 563 indx.header.data.vi.data_offset = 564 cpu_to_le16(sizeof(struct index_entry_header) + sizeof(struct reparse_index_key)); 565 indx.header.data.vi.data_length = 0; 566 indx.header.data.vi.reservedV = 0; 567 indx.header.length = cpu_to_le16(sizeof(struct reparse_index)); 568 indx.header.key_length = cpu_to_le16(sizeof(struct reparse_index_key)); 569 indx.header.flags = 0; 570 indx.header.reserved = 0; 571 indx.key.reparse_tag = reparse_tag; 572 /* danger on processors which require proper alignment! */ 573 memcpy(&indx.key.file_id, &file_id, 8); 574 indx.filling = 0; 575 ntfs_index_ctx_reinit(xr); 576 577 return ntfs_ie_add(xr, (struct index_entry *)&indx); 578 } 579 580 /* 581 * Remove a reparse data index entry if attribute present 582 */ 583 static int remove_reparse_index(struct inode *rp, struct ntfs_index_context *xr, 584 __le32 *preparse_tag) 585 { 586 struct reparse_index_key key; 587 u64 file_id_cpu; 588 __le64 file_id; 589 s64 size; 590 struct ntfs_inode *ni = NTFS_I(rp); 591 int err = 0, ret = ni->data_size; 592 593 if (ni->data_size == 0) 594 return 0; 595 596 /* read the existing reparse_tag */ 597 size = ntfs_inode_attr_pread(rp, 0, 4, (char *)preparse_tag); 598 if (size != 4) 599 return -ENODATA; 600 601 file_id_cpu = MK_MREF(ni->mft_no, ni->seq_no); 602 file_id = cpu_to_le64(file_id_cpu); 603 key.reparse_tag = *preparse_tag; 604 /* danger on processors which require proper alignment! */ 605 memcpy(&key.file_id, &file_id, 8); 606 if (!ntfs_index_lookup(&key, sizeof(struct reparse_index_key), xr)) { 607 err = ntfs_index_rm(xr); 608 if (err) 609 ret = err; 610 } 611 return ret; 612 } 613 614 /* 615 * Open the $Extend/$Reparse file and its index 616 */ 617 static struct ntfs_index_context *open_reparse_index(struct ntfs_volume *vol) 618 { 619 struct ntfs_index_context *xr = NULL; 620 u64 mref; 621 __le16 *uname; 622 struct ntfs_name *name = NULL; 623 int uname_len; 624 struct inode *vi, *dir_vi; 625 626 /* do not use path_name_to inode - could reopen root */ 627 dir_vi = ntfs_iget(vol->sb, FILE_Extend); 628 if (IS_ERR(dir_vi)) 629 return NULL; 630 631 uname_len = ntfs_nlstoucs(vol, "$Reparse", 8, &uname, 632 NTFS_MAX_NAME_LEN); 633 if (uname_len < 0) { 634 iput(dir_vi); 635 return NULL; 636 } 637 638 mutex_lock_nested(&NTFS_I(dir_vi)->mrec_lock, NTFS_EXTEND_MUTEX_PARENT); 639 mref = ntfs_lookup_inode_by_name(NTFS_I(dir_vi), uname, uname_len, 640 &name); 641 mutex_unlock(&NTFS_I(dir_vi)->mrec_lock); 642 kfree(name); 643 kmem_cache_free(ntfs_name_cache, uname); 644 if (IS_ERR_MREF(mref)) 645 goto put_dir_vi; 646 647 vi = ntfs_iget(vol->sb, MREF(mref)); 648 if (IS_ERR(vi)) 649 goto put_dir_vi; 650 651 xr = ntfs_index_ctx_get(NTFS_I(vi), reparse_index_name, 2); 652 if (!xr) 653 iput(vi); 654 put_dir_vi: 655 iput(dir_vi); 656 return xr; 657 } 658 659 660 /* 661 * Update the reparse data and index 662 * 663 * The reparse data attribute should have been created, and 664 * an existing index is expected if there is an existing value. 665 * 666 */ 667 static int update_reparse_data(struct ntfs_inode *ni, struct ntfs_index_context *xr, 668 char *value, size_t size) 669 { 670 struct inode *rp_inode; 671 int err = 0; 672 s64 written; 673 int oldsize; 674 __le32 reparse_tag; 675 struct ntfs_inode *rp_ni; 676 677 rp_inode = ntfs_attr_iget(VFS_I(ni), AT_REPARSE_POINT, AT_UNNAMED, 0); 678 if (IS_ERR(rp_inode)) 679 return -EINVAL; 680 rp_ni = NTFS_I(rp_inode); 681 682 /* remove the existing reparse data */ 683 oldsize = remove_reparse_index(rp_inode, xr, &reparse_tag); 684 if (oldsize < 0) { 685 err = oldsize; 686 goto put_rp_inode; 687 } 688 689 /* overwrite value if any */ 690 written = ntfs_inode_attr_pwrite(rp_inode, 0, size, value, false); 691 if (written != size) { 692 ntfs_error(ni->vol->sb, "Failed to update reparse data\n"); 693 err = -EIO; 694 goto put_rp_inode; 695 } 696 697 err = set_reparse_index(ni, xr, 698 ((const struct reparse_point *)value)->reparse_tag); 699 if (err && oldsize > 0) { 700 /* 701 * If cannot index, try to remove the reparse 702 * data and log the error. There will be an 703 * inconsistency if removal fails. 704 */ 705 ntfs_attr_rm(rp_ni); 706 ntfs_error(ni->vol->sb, 707 "Failed to index reparse data. Possible corruption.\n"); 708 } 709 710 mark_mft_record_dirty(ni); 711 put_rp_inode: 712 iput(rp_inode); 713 714 return err; 715 } 716 717 /* 718 * Delete a reparse index entry 719 */ 720 int ntfs_delete_reparse_index(struct ntfs_inode *ni) 721 { 722 struct inode *vi; 723 struct ntfs_index_context *xr; 724 struct ntfs_inode *xrni; 725 __le32 reparse_tag; 726 int err = 0; 727 728 if (!(ni->flags & FILE_ATTR_REPARSE_POINT)) 729 return 0; 730 731 vi = ntfs_attr_iget(VFS_I(ni), AT_REPARSE_POINT, AT_UNNAMED, 0); 732 if (IS_ERR(vi)) 733 return PTR_ERR(vi); 734 735 /* 736 * read the existing reparse data (the tag is enough) 737 * and un-index it 738 */ 739 xr = open_reparse_index(ni->vol); 740 if (xr) { 741 xrni = xr->idx_ni; 742 mutex_lock_nested(&xrni->mrec_lock, NTFS_EXTEND_MUTEX_PARENT); 743 err = remove_reparse_index(vi, xr, &reparse_tag); 744 if (err < 0) { 745 ntfs_index_ctx_put(xr); 746 mutex_unlock(&xrni->mrec_lock); 747 iput(VFS_I(xrni)); 748 goto out; 749 } 750 mark_mft_record_dirty(xrni); 751 ntfs_index_ctx_put(xr); 752 mutex_unlock(&xrni->mrec_lock); 753 iput(VFS_I(xrni)); 754 } 755 756 ni->flags &= ~FILE_ATTR_REPARSE_POINT; 757 NInoSetFileNameDirty(ni); 758 mark_mft_record_dirty(ni); 759 760 out: 761 iput(vi); 762 return err; 763 } 764 765 /* 766 * Set the reparse data from an extended attribute 767 */ 768 static int ntfs_set_ntfs_reparse_data(struct ntfs_inode *ni, char *value, size_t size) 769 { 770 int err = 0; 771 struct ntfs_inode *xrni; 772 struct ntfs_index_context *xr; 773 774 if (!ni) 775 return -EINVAL; 776 777 /* 778 * reparse data compatibily with EA is not checked 779 * any more, it is required by Windows 10, but may 780 * lead to problems with earlier versions. 781 */ 782 if (valid_reparse_data(ni, (const struct reparse_point *)value, size) == false) 783 return -EINVAL; 784 785 xr = open_reparse_index(ni->vol); 786 if (!xr) 787 return -EINVAL; 788 xrni = xr->idx_ni; 789 790 if (!ntfs_attr_exist(ni, AT_REPARSE_POINT, AT_UNNAMED, 0)) { 791 struct reparse_point rp = {0, }; 792 793 /* 794 * no reparse data attribute : add one, 795 * apparently, this does not feed the new value in 796 * Note : NTFS version must be >= 3 797 */ 798 if (ni->vol->major_ver < 3) { 799 err = -EOPNOTSUPP; 800 ntfs_index_ctx_put(xr); 801 goto out; 802 } 803 804 err = ntfs_attr_add(ni, AT_REPARSE_POINT, AT_UNNAMED, 0, (u8 *)&rp, sizeof(rp)); 805 if (err) { 806 ntfs_index_ctx_put(xr); 807 goto out; 808 } 809 ni->flags |= FILE_ATTR_REPARSE_POINT; 810 NInoSetFileNameDirty(ni); 811 mark_mft_record_dirty(ni); 812 } 813 814 /* update value and index */ 815 mutex_lock_nested(&xrni->mrec_lock, NTFS_EXTEND_MUTEX_PARENT); 816 err = update_reparse_data(ni, xr, value, size); 817 if (err) { 818 ni->flags &= ~FILE_ATTR_REPARSE_POINT; 819 NInoSetFileNameDirty(ni); 820 mark_mft_record_dirty(ni); 821 } 822 ntfs_index_ctx_put(xr); 823 mutex_unlock(&xrni->mrec_lock); 824 825 out: 826 if (!err) 827 mark_mft_record_dirty(xrni); 828 iput(VFS_I(xrni)); 829 830 return err; 831 } 832 833 /* 834 * Set reparse data for a WSL type symlink 835 */ 836 int ntfs_reparse_set_wsl_symlink(struct ntfs_inode *ni, 837 const char *target, int target_len) 838 { 839 int err = 0; 840 int reparse_len; 841 struct reparse_point *reparse; 842 struct wsl_link_reparse_data *data; 843 844 reparse_len = sizeof(struct reparse_point) + sizeof(data->type) + 845 target_len; 846 reparse = kvzalloc(reparse_len, GFP_NOFS); 847 if (!reparse) 848 return -ENOMEM; 849 850 ni->target = kstrdup(target, GFP_NOFS); 851 if (!ni->target) { 852 kvfree(reparse); 853 return -ENOMEM; 854 } 855 856 data = (struct wsl_link_reparse_data *)reparse->reparse_data; 857 reparse->reparse_tag = IO_REPARSE_TAG_LX_SYMLINK; 858 reparse->reparse_data_length = 859 cpu_to_le16(sizeof(data->type) + target_len); 860 reparse->reserved = 0; 861 data->type = cpu_to_le32(2); 862 memcpy(data->link, target, target_len); 863 err = ntfs_set_ntfs_reparse_data(ni, 864 (char *)reparse, reparse_len); 865 kvfree(reparse); 866 if (err) { 867 kfree(ni->target); 868 ni->target = NULL; 869 } else { 870 ni->reparse_tag = IO_REPARSE_TAG_LX_SYMLINK; 871 ni->reparse_flags = 0; 872 } 873 return err; 874 } 875 876 int ntfs_reparse_set_native_symlink(struct ntfs_inode *ni, 877 const char *target, int target_len) 878 { 879 int err = 0; 880 bool is_absolute, prt_sub_shared = true; 881 char *sub_name = NULL; 882 char *prt_name = NULL; 883 __le16 *sub_name_utf16 = NULL; 884 __le16 *prt_name_utf16 = NULL; 885 int sub_len, prt_len; 886 int total_data_len, total_reparse_len; 887 struct reparse_point *reparse = NULL; 888 struct symlink_reparse_data *data; 889 int i; 890 891 /* Determine if target is absolute (starts with drive letter like C:/ or C:\) */ 892 is_absolute = target_len > 2 && 893 ntfs_is_drive_letter(target) && 894 (target[2] == '/' || target[2] == '\\'); 895 896 897 /* Normalize and prepare NLS paths */ 898 prt_name = kstrdup(target, GFP_NOFS); 899 if (!prt_name) 900 return -ENOMEM; 901 902 /* Replace '/' with '\' */ 903 for (i = 0; i < target_len; i++) { 904 if (prt_name[i] == '/') 905 prt_name[i] = '\\'; 906 } 907 908 if (is_absolute) { 909 /* Prepend '\??\' to Substitutename */ 910 sub_name = kmalloc(target_len + 5, GFP_NOFS); 911 if (!sub_name) { 912 err = -ENOMEM; 913 goto out; 914 } 915 snprintf(sub_name, target_len + 5, "\\??\\%s", prt_name); 916 prt_sub_shared = false; 917 } else { 918 /* For relative symlinks (including absolute paths without drive letters), 919 * SubstituteName and PrintName are identical. 920 */ 921 sub_name = prt_name; 922 } 923 924 /* Convert NLS paths to UTF-16 */ 925 sub_len = ntfs_nlstoucs(ni->vol, sub_name, strlen(sub_name), 926 &sub_name_utf16, PATH_MAX); 927 if (sub_len < 0) { 928 err = sub_len; 929 goto out; 930 } 931 932 prt_len = ntfs_nlstoucs(ni->vol, prt_name, strlen(prt_name), 933 &prt_name_utf16, PATH_MAX); 934 if (prt_len < 0) { 935 err = prt_len; 936 goto out; 937 } 938 939 /* Check for buffer size limits */ 940 total_data_len = sizeof(struct symlink_reparse_data) + 941 (sub_len + prt_len) * sizeof(__le16); 942 if (total_data_len > 16384) { /* 16KB max reparse tag size */ 943 err = -EFBIG; 944 goto out; 945 } 946 947 total_reparse_len = sizeof(struct reparse_point) + total_data_len; 948 reparse = kvzalloc(total_reparse_len, GFP_NOFS); 949 if (!reparse) { 950 err = -ENOMEM; 951 goto out; 952 } 953 954 /* Pack fields in reparse buffer */ 955 reparse->reparse_tag = IO_REPARSE_TAG_SYMLINK; 956 reparse->reparse_data_length = cpu_to_le16(total_data_len); 957 reparse->reserved = 0; 958 959 data = (struct symlink_reparse_data *)reparse->reparse_data; 960 data->substitute_name_offset = 0; 961 data->substitute_name_length = cpu_to_le16(sub_len * sizeof(__le16)); 962 data->print_name_offset = data->substitute_name_length; 963 data->print_name_length = cpu_to_le16(prt_len * sizeof(__le16)); 964 data->flags = is_absolute ? 0 : cpu_to_le32(SYMLINK_FLAG_RELATIVE); 965 966 /* Copy names to path_buffer */ 967 memcpy(data->path_buffer, sub_name_utf16, sub_len * sizeof(__le16)); 968 memcpy(data->path_buffer + sub_len, prt_name_utf16, prt_len * sizeof(__le16)); 969 970 err = ntfs_set_ntfs_reparse_data(ni, (char *)reparse, total_reparse_len); 971 if (!err) { 972 strreplace(sub_name, '\\', '/'); 973 ni->target = sub_name; 974 sub_name = NULL; 975 if (prt_sub_shared) 976 prt_name = NULL; 977 ni->reparse_tag = IO_REPARSE_TAG_SYMLINK; 978 ni->reparse_flags = is_absolute ? 0 : 979 cpu_to_le32(SYMLINK_FLAG_RELATIVE); 980 } 981 982 out: 983 kfree(prt_name); 984 if (!prt_sub_shared) 985 kfree(sub_name); 986 kvfree(sub_name_utf16); 987 kvfree(prt_name_utf16); 988 kvfree(reparse); 989 return err; 990 } 991 992 /* 993 * Set reparse data for a WSL special file other than a symlink 994 * (socket, fifo, character or block device) 995 */ 996 int ntfs_reparse_set_wsl_not_symlink(struct ntfs_inode *ni, mode_t mode) 997 { 998 int err; 999 int len; 1000 int reparse_len; 1001 __le32 reparse_tag; 1002 struct reparse_point *reparse; 1003 1004 len = 0; 1005 if (S_ISSOCK(mode)) 1006 reparse_tag = IO_REPARSE_TAG_AF_UNIX; 1007 else if (S_ISFIFO(mode)) 1008 reparse_tag = IO_REPARSE_TAG_LX_FIFO; 1009 else if (S_ISCHR(mode)) 1010 reparse_tag = IO_REPARSE_TAG_LX_CHR; 1011 else if (S_ISBLK(mode)) 1012 reparse_tag = IO_REPARSE_TAG_LX_BLK; 1013 else 1014 return -EOPNOTSUPP; 1015 1016 reparse_len = sizeof(struct reparse_point) + len; 1017 reparse = kvzalloc(reparse_len, GFP_NOFS); 1018 if (!reparse) 1019 err = -ENOMEM; 1020 else { 1021 reparse->reparse_tag = reparse_tag; 1022 reparse->reparse_data_length = cpu_to_le16(len); 1023 reparse->reserved = cpu_to_le16(0); 1024 err = ntfs_set_ntfs_reparse_data(ni, (char *)reparse, 1025 reparse_len); 1026 kvfree(reparse); 1027 if (!err) { 1028 ni->reparse_tag = reparse_tag; 1029 ni->reparse_flags = 0; 1030 } 1031 } 1032 1033 return err; 1034 } 1035