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 PTR_ERR(vi); 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 if (set_reparse_index(ni, xr, ((const struct reparse_point *)value)->reparse_tag) && 698 oldsize > 0) { 699 /* 700 * If cannot index, try to remove the reparse 701 * data and log the error. There will be an 702 * inconsistency if removal fails. 703 */ 704 ntfs_attr_rm(rp_ni); 705 ntfs_error(ni->vol->sb, 706 "Failed to index reparse data. Possible corruption.\n"); 707 } 708 709 mark_mft_record_dirty(ni); 710 put_rp_inode: 711 iput(rp_inode); 712 713 return err; 714 } 715 716 /* 717 * Delete a reparse index entry 718 */ 719 int ntfs_delete_reparse_index(struct ntfs_inode *ni) 720 { 721 struct inode *vi; 722 struct ntfs_index_context *xr; 723 struct ntfs_inode *xrni; 724 __le32 reparse_tag; 725 int err = 0; 726 727 if (!(ni->flags & FILE_ATTR_REPARSE_POINT)) 728 return 0; 729 730 vi = ntfs_attr_iget(VFS_I(ni), AT_REPARSE_POINT, AT_UNNAMED, 0); 731 if (IS_ERR(vi)) 732 return PTR_ERR(vi); 733 734 /* 735 * read the existing reparse data (the tag is enough) 736 * and un-index it 737 */ 738 xr = open_reparse_index(ni->vol); 739 if (xr) { 740 xrni = xr->idx_ni; 741 mutex_lock_nested(&xrni->mrec_lock, NTFS_EXTEND_MUTEX_PARENT); 742 err = remove_reparse_index(vi, xr, &reparse_tag); 743 if (err < 0) { 744 ntfs_index_ctx_put(xr); 745 mutex_unlock(&xrni->mrec_lock); 746 iput(VFS_I(xrni)); 747 goto out; 748 } 749 mark_mft_record_dirty(xrni); 750 ntfs_index_ctx_put(xr); 751 mutex_unlock(&xrni->mrec_lock); 752 iput(VFS_I(xrni)); 753 } 754 755 ni->flags &= ~FILE_ATTR_REPARSE_POINT; 756 NInoSetFileNameDirty(ni); 757 mark_mft_record_dirty(ni); 758 759 out: 760 iput(vi); 761 return err; 762 } 763 764 /* 765 * Set the reparse data from an extended attribute 766 */ 767 static int ntfs_set_ntfs_reparse_data(struct ntfs_inode *ni, char *value, size_t size) 768 { 769 int err = 0; 770 struct ntfs_inode *xrni; 771 struct ntfs_index_context *xr; 772 773 if (!ni) 774 return -EINVAL; 775 776 /* 777 * reparse data compatibily with EA is not checked 778 * any more, it is required by Windows 10, but may 779 * lead to problems with earlier versions. 780 */ 781 if (valid_reparse_data(ni, (const struct reparse_point *)value, size) == false) 782 return -EINVAL; 783 784 xr = open_reparse_index(ni->vol); 785 if (!xr) 786 return -EINVAL; 787 xrni = xr->idx_ni; 788 789 if (!ntfs_attr_exist(ni, AT_REPARSE_POINT, AT_UNNAMED, 0)) { 790 struct reparse_point rp = {0, }; 791 792 /* 793 * no reparse data attribute : add one, 794 * apparently, this does not feed the new value in 795 * Note : NTFS version must be >= 3 796 */ 797 if (ni->vol->major_ver < 3) { 798 err = -EOPNOTSUPP; 799 ntfs_index_ctx_put(xr); 800 goto out; 801 } 802 803 err = ntfs_attr_add(ni, AT_REPARSE_POINT, AT_UNNAMED, 0, (u8 *)&rp, sizeof(rp)); 804 if (err) { 805 ntfs_index_ctx_put(xr); 806 goto out; 807 } 808 ni->flags |= FILE_ATTR_REPARSE_POINT; 809 NInoSetFileNameDirty(ni); 810 mark_mft_record_dirty(ni); 811 } 812 813 /* update value and index */ 814 mutex_lock_nested(&xrni->mrec_lock, NTFS_EXTEND_MUTEX_PARENT); 815 err = update_reparse_data(ni, xr, value, size); 816 if (err) { 817 ni->flags &= ~FILE_ATTR_REPARSE_POINT; 818 NInoSetFileNameDirty(ni); 819 mark_mft_record_dirty(ni); 820 } 821 ntfs_index_ctx_put(xr); 822 mutex_unlock(&xrni->mrec_lock); 823 824 out: 825 if (!err) 826 mark_mft_record_dirty(xrni); 827 iput(VFS_I(xrni)); 828 829 return err; 830 } 831 832 /* 833 * Set reparse data for a WSL type symlink 834 */ 835 int ntfs_reparse_set_wsl_symlink(struct ntfs_inode *ni, 836 const char *target, int target_len) 837 { 838 int err = 0; 839 int reparse_len; 840 struct reparse_point *reparse; 841 struct wsl_link_reparse_data *data; 842 843 reparse_len = sizeof(struct reparse_point) + sizeof(data->type) + 844 target_len; 845 reparse = kvzalloc(reparse_len, GFP_NOFS); 846 if (!reparse) 847 return -ENOMEM; 848 849 ni->target = kstrdup(target, GFP_NOFS); 850 if (!ni->target) { 851 kvfree(reparse); 852 return -ENOMEM; 853 } 854 855 data = (struct wsl_link_reparse_data *)reparse->reparse_data; 856 reparse->reparse_tag = IO_REPARSE_TAG_LX_SYMLINK; 857 reparse->reparse_data_length = 858 cpu_to_le16(sizeof(data->type) + target_len); 859 reparse->reserved = 0; 860 data->type = cpu_to_le32(2); 861 memcpy(data->link, target, target_len); 862 err = ntfs_set_ntfs_reparse_data(ni, 863 (char *)reparse, reparse_len); 864 kvfree(reparse); 865 if (err) { 866 kfree(ni->target); 867 ni->target = NULL; 868 } else { 869 ni->reparse_tag = IO_REPARSE_TAG_LX_SYMLINK; 870 ni->reparse_flags = 0; 871 } 872 return err; 873 } 874 875 int ntfs_reparse_set_native_symlink(struct ntfs_inode *ni, 876 const char *target, int target_len) 877 { 878 int err = 0; 879 bool is_absolute, prt_sub_shared = true; 880 char *sub_name = NULL; 881 char *prt_name = NULL; 882 __le16 *sub_name_utf16 = NULL; 883 __le16 *prt_name_utf16 = NULL; 884 int sub_len, prt_len; 885 int total_data_len, total_reparse_len; 886 struct reparse_point *reparse = NULL; 887 struct symlink_reparse_data *data; 888 int i; 889 890 /* Determine if target is absolute (starts with drive letter like C:/ or C:\) */ 891 is_absolute = target_len > 2 && 892 ntfs_is_drive_letter(target) && 893 (target[2] == '/' || target[2] == '\\'); 894 895 896 /* Normalize and prepare NLS paths */ 897 prt_name = kstrdup(target, GFP_NOFS); 898 if (!prt_name) 899 return -ENOMEM; 900 901 /* Replace '/' with '\' */ 902 for (i = 0; i < target_len; i++) { 903 if (prt_name[i] == '/') 904 prt_name[i] = '\\'; 905 } 906 907 if (is_absolute) { 908 /* Prepend '\??\' to Substitutename */ 909 sub_name = kmalloc(target_len + 5, GFP_NOFS); 910 if (!sub_name) { 911 err = -ENOMEM; 912 goto out; 913 } 914 snprintf(sub_name, target_len + 5, "\\??\\%s", prt_name); 915 prt_sub_shared = false; 916 } else { 917 /* For relative symlinks (including absolute paths without drive letters), 918 * SubstituteName and PrintName are identical. 919 */ 920 sub_name = prt_name; 921 } 922 923 /* Convert NLS paths to UTF-16 */ 924 sub_len = ntfs_nlstoucs(ni->vol, sub_name, strlen(sub_name), 925 &sub_name_utf16, PATH_MAX); 926 if (sub_len < 0) { 927 err = sub_len; 928 goto out; 929 } 930 931 prt_len = ntfs_nlstoucs(ni->vol, prt_name, strlen(prt_name), 932 &prt_name_utf16, PATH_MAX); 933 if (prt_len < 0) { 934 err = prt_len; 935 goto out; 936 } 937 938 /* Check for buffer size limits */ 939 total_data_len = sizeof(struct symlink_reparse_data) + 940 (sub_len + prt_len) * sizeof(__le16); 941 if (total_data_len > 16384) { /* 16KB max reparse tag size */ 942 err = -EFBIG; 943 goto out; 944 } 945 946 total_reparse_len = sizeof(struct reparse_point) + total_data_len; 947 reparse = kvzalloc(total_reparse_len, GFP_NOFS); 948 if (!reparse) { 949 err = -ENOMEM; 950 goto out; 951 } 952 953 /* Pack fields in reparse buffer */ 954 reparse->reparse_tag = IO_REPARSE_TAG_SYMLINK; 955 reparse->reparse_data_length = cpu_to_le16(total_data_len); 956 reparse->reserved = 0; 957 958 data = (struct symlink_reparse_data *)reparse->reparse_data; 959 data->substitute_name_offset = 0; 960 data->substitute_name_length = cpu_to_le16(sub_len * sizeof(__le16)); 961 data->print_name_offset = data->substitute_name_length; 962 data->print_name_length = cpu_to_le16(prt_len * sizeof(__le16)); 963 data->flags = is_absolute ? 0 : cpu_to_le32(SYMLINK_FLAG_RELATIVE); 964 965 /* Copy names to path_buffer */ 966 memcpy(data->path_buffer, sub_name_utf16, sub_len * sizeof(__le16)); 967 memcpy(data->path_buffer + sub_len, prt_name_utf16, prt_len * sizeof(__le16)); 968 969 err = ntfs_set_ntfs_reparse_data(ni, (char *)reparse, total_reparse_len); 970 if (!err) { 971 strreplace(sub_name, '\\', '/'); 972 ni->target = sub_name; 973 sub_name = NULL; 974 if (prt_sub_shared) 975 prt_name = NULL; 976 ni->reparse_tag = IO_REPARSE_TAG_SYMLINK; 977 ni->reparse_flags = is_absolute ? 0 : 978 cpu_to_le32(SYMLINK_FLAG_RELATIVE); 979 } 980 981 out: 982 kfree(prt_name); 983 if (!prt_sub_shared) 984 kfree(sub_name); 985 kvfree(sub_name_utf16); 986 kvfree(prt_name_utf16); 987 kvfree(reparse); 988 return err; 989 } 990 991 /* 992 * Set reparse data for a WSL special file other than a symlink 993 * (socket, fifo, character or block device) 994 */ 995 int ntfs_reparse_set_wsl_not_symlink(struct ntfs_inode *ni, mode_t mode) 996 { 997 int err; 998 int len; 999 int reparse_len; 1000 __le32 reparse_tag; 1001 struct reparse_point *reparse; 1002 1003 len = 0; 1004 if (S_ISSOCK(mode)) 1005 reparse_tag = IO_REPARSE_TAG_AF_UNIX; 1006 else if (S_ISFIFO(mode)) 1007 reparse_tag = IO_REPARSE_TAG_LX_FIFO; 1008 else if (S_ISCHR(mode)) 1009 reparse_tag = IO_REPARSE_TAG_LX_CHR; 1010 else if (S_ISBLK(mode)) 1011 reparse_tag = IO_REPARSE_TAG_LX_BLK; 1012 else 1013 return -EOPNOTSUPP; 1014 1015 reparse_len = sizeof(struct reparse_point) + len; 1016 reparse = kvzalloc(reparse_len, GFP_NOFS); 1017 if (!reparse) 1018 err = -ENOMEM; 1019 else { 1020 reparse->reparse_tag = reparse_tag; 1021 reparse->reparse_data_length = cpu_to_le16(len); 1022 reparse->reserved = cpu_to_le16(0); 1023 err = ntfs_set_ntfs_reparse_data(ni, (char *)reparse, 1024 reparse_len); 1025 kvfree(reparse); 1026 if (!err) { 1027 ni->reparse_tag = reparse_tag; 1028 ni->reparse_flags = 0; 1029 } 1030 } 1031 1032 return err; 1033 } 1034