1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2024 Paulo Alcantara <pc@manguebit.com> 4 */ 5 6 #include <linux/fs.h> 7 #include <linux/stat.h> 8 #include <linux/slab.h> 9 #include "cifsglob.h" 10 #include "smb2proto.h" 11 #include "cifsproto.h" 12 #include "cifs_unicode.h" 13 #include "cifs_debug.h" 14 #include "fs_context.h" 15 #include "reparse.h" 16 17 static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb, 18 const unsigned int xid, 19 const char *full_path, 20 const char *symname, 21 bool *directory); 22 23 int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode, 24 struct dentry *dentry, struct cifs_tcon *tcon, 25 const char *full_path, const char *symname) 26 { 27 struct reparse_symlink_data_buffer *buf = NULL; 28 struct cifs_open_info_data data; 29 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 30 struct inode *new; 31 struct kvec iov; 32 __le16 *path; 33 bool directory; 34 char *sym, sep = CIFS_DIR_SEP(cifs_sb); 35 u16 len, plen; 36 int rc = 0; 37 38 if (strlen(symname) > REPARSE_SYM_PATH_MAX) 39 return -ENAMETOOLONG; 40 41 sym = kstrdup(symname, GFP_KERNEL); 42 if (!sym) 43 return -ENOMEM; 44 45 data = (struct cifs_open_info_data) { 46 .reparse_point = true, 47 .reparse = { .tag = IO_REPARSE_TAG_SYMLINK, }, 48 .symlink_target = sym, 49 }; 50 51 convert_delimiter(sym, sep); 52 path = cifs_convert_path_to_utf16(sym, cifs_sb); 53 if (!path) { 54 rc = -ENOMEM; 55 goto out; 56 } 57 58 /* 59 * SMB distinguish between symlink to directory and symlink to file. 60 * They cannot be exchanged (symlink of file type which points to 61 * directory cannot be resolved and vice-versa). Try to detect if 62 * the symlink target could be a directory or not. When detection 63 * fails then treat symlink as a file (non-directory) symlink. 64 */ 65 directory = false; 66 rc = detect_directory_symlink_target(cifs_sb, xid, full_path, symname, &directory); 67 if (rc < 0) 68 goto out; 69 70 plen = 2 * UniStrnlen((wchar_t *)path, REPARSE_SYM_PATH_MAX); 71 len = sizeof(*buf) + plen * 2; 72 buf = kzalloc(len, GFP_KERNEL); 73 if (!buf) { 74 rc = -ENOMEM; 75 goto out; 76 } 77 78 buf->ReparseTag = cpu_to_le32(IO_REPARSE_TAG_SYMLINK); 79 buf->ReparseDataLength = cpu_to_le16(len - sizeof(struct reparse_data_buffer)); 80 buf->SubstituteNameOffset = cpu_to_le16(plen); 81 buf->SubstituteNameLength = cpu_to_le16(plen); 82 memcpy(&buf->PathBuffer[plen], path, plen); 83 buf->PrintNameOffset = 0; 84 buf->PrintNameLength = cpu_to_le16(plen); 85 memcpy(buf->PathBuffer, path, plen); 86 buf->Flags = cpu_to_le32(*symname != '/' ? SYMLINK_FLAG_RELATIVE : 0); 87 if (*sym != sep) 88 buf->Flags = cpu_to_le32(SYMLINK_FLAG_RELATIVE); 89 90 convert_delimiter(sym, '/'); 91 iov.iov_base = buf; 92 iov.iov_len = len; 93 new = smb2_get_reparse_inode(&data, inode->i_sb, xid, 94 tcon, full_path, directory, 95 &iov, NULL); 96 if (!IS_ERR(new)) 97 d_instantiate(dentry, new); 98 else 99 rc = PTR_ERR(new); 100 out: 101 kfree(path); 102 cifs_free_open_info(&data); 103 kfree(buf); 104 return rc; 105 } 106 107 static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb, 108 const unsigned int xid, 109 const char *full_path, 110 const char *symname, 111 bool *directory) 112 { 113 char sep = CIFS_DIR_SEP(cifs_sb); 114 struct cifs_open_parms oparms; 115 struct tcon_link *tlink; 116 struct cifs_tcon *tcon; 117 const char *basename; 118 struct cifs_fid fid; 119 char *resolved_path; 120 int full_path_len; 121 int basename_len; 122 int symname_len; 123 char *path_sep; 124 __u32 oplock; 125 int open_rc; 126 127 /* 128 * First do some simple check. If the original Linux symlink target ends 129 * with slash, or last path component is dot or dot-dot then it is for 130 * sure symlink to the directory. 131 */ 132 basename = kbasename(symname); 133 basename_len = strlen(basename); 134 if (basename_len == 0 || /* symname ends with slash */ 135 (basename_len == 1 && basename[0] == '.') || /* last component is "." */ 136 (basename_len == 2 && basename[0] == '.' && basename[1] == '.')) { /* or ".." */ 137 *directory = true; 138 return 0; 139 } 140 141 /* 142 * For absolute symlinks it is not possible to determinate 143 * if it should point to directory or file. 144 */ 145 if (symname[0] == '/') { 146 cifs_dbg(FYI, 147 "%s: cannot determinate if the symlink target path '%s' " 148 "is directory or not, creating '%s' as file symlink\n", 149 __func__, symname, full_path); 150 return 0; 151 } 152 153 /* 154 * If it was not detected as directory yet and the symlink is relative 155 * then try to resolve the path on the SMB server, check if the path 156 * exists and determinate if it is a directory or not. 157 */ 158 159 full_path_len = strlen(full_path); 160 symname_len = strlen(symname); 161 162 tlink = cifs_sb_tlink(cifs_sb); 163 if (IS_ERR(tlink)) 164 return PTR_ERR(tlink); 165 166 resolved_path = kzalloc(full_path_len + symname_len + 1, GFP_KERNEL); 167 if (!resolved_path) { 168 cifs_put_tlink(tlink); 169 return -ENOMEM; 170 } 171 172 /* 173 * Compose the resolved SMB symlink path from the SMB full path 174 * and Linux target symlink path. 175 */ 176 memcpy(resolved_path, full_path, full_path_len+1); 177 path_sep = strrchr(resolved_path, sep); 178 if (path_sep) 179 path_sep++; 180 else 181 path_sep = resolved_path; 182 memcpy(path_sep, symname, symname_len+1); 183 if (sep == '\\') 184 convert_delimiter(path_sep, sep); 185 186 tcon = tlink_tcon(tlink); 187 oparms = CIFS_OPARMS(cifs_sb, tcon, resolved_path, 188 FILE_READ_ATTRIBUTES, FILE_OPEN, 0, ACL_NO_MODE); 189 oparms.fid = &fid; 190 191 /* Try to open as a directory (NOT_FILE) */ 192 oplock = 0; 193 oparms.create_options = cifs_create_options(cifs_sb, 194 CREATE_NOT_FILE | OPEN_REPARSE_POINT); 195 open_rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL); 196 if (open_rc == 0) { 197 /* Successful open means that the target path is definitely a directory. */ 198 *directory = true; 199 tcon->ses->server->ops->close(xid, tcon, &fid); 200 } else if (open_rc == -ENOTDIR) { 201 /* -ENOTDIR means that the target path is definitely a file. */ 202 *directory = false; 203 } else if (open_rc == -ENOENT) { 204 /* -ENOENT means that the target path does not exist. */ 205 cifs_dbg(FYI, 206 "%s: symlink target path '%s' does not exist, " 207 "creating '%s' as file symlink\n", 208 __func__, symname, full_path); 209 } else { 210 /* Try to open as a file (NOT_DIR) */ 211 oplock = 0; 212 oparms.create_options = cifs_create_options(cifs_sb, 213 CREATE_NOT_DIR | OPEN_REPARSE_POINT); 214 open_rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL); 215 if (open_rc == 0) { 216 /* Successful open means that the target path is definitely a file. */ 217 *directory = false; 218 tcon->ses->server->ops->close(xid, tcon, &fid); 219 } else if (open_rc == -EISDIR) { 220 /* -EISDIR means that the target path is definitely a directory. */ 221 *directory = true; 222 } else { 223 /* 224 * This code branch is called when we do not have a permission to 225 * open the resolved_path or some other client/process denied 226 * opening the resolved_path. 227 * 228 * TODO: Try to use ops->query_dir_first on the parent directory 229 * of resolved_path, search for basename of resolved_path and 230 * check if the ATTR_DIRECTORY is set in fi.Attributes. In some 231 * case this could work also when opening of the path is denied. 232 */ 233 cifs_dbg(FYI, 234 "%s: cannot determinate if the symlink target path '%s' " 235 "is directory or not, creating '%s' as file symlink\n", 236 __func__, symname, full_path); 237 } 238 } 239 240 kfree(resolved_path); 241 cifs_put_tlink(tlink); 242 return 0; 243 } 244 245 static int nfs_set_reparse_buf(struct reparse_posix_data *buf, 246 mode_t mode, dev_t dev, 247 struct kvec *iov) 248 { 249 u64 type; 250 u16 len, dlen; 251 252 len = sizeof(*buf); 253 254 switch ((type = reparse_mode_nfs_type(mode))) { 255 case NFS_SPECFILE_BLK: 256 case NFS_SPECFILE_CHR: 257 dlen = sizeof(__le64); 258 break; 259 case NFS_SPECFILE_FIFO: 260 case NFS_SPECFILE_SOCK: 261 dlen = 0; 262 break; 263 default: 264 return -EOPNOTSUPP; 265 } 266 267 buf->ReparseTag = cpu_to_le32(IO_REPARSE_TAG_NFS); 268 buf->Reserved = 0; 269 buf->InodeType = cpu_to_le64(type); 270 buf->ReparseDataLength = cpu_to_le16(len + dlen - 271 sizeof(struct reparse_data_buffer)); 272 *(__le64 *)buf->DataBuffer = cpu_to_le64(((u64)MINOR(dev) << 32) | 273 MAJOR(dev)); 274 iov->iov_base = buf; 275 iov->iov_len = len + dlen; 276 return 0; 277 } 278 279 static int mknod_nfs(unsigned int xid, struct inode *inode, 280 struct dentry *dentry, struct cifs_tcon *tcon, 281 const char *full_path, umode_t mode, dev_t dev) 282 { 283 struct cifs_open_info_data data; 284 struct reparse_posix_data *p; 285 struct inode *new; 286 struct kvec iov; 287 __u8 buf[sizeof(*p) + sizeof(__le64)]; 288 int rc; 289 290 p = (struct reparse_posix_data *)buf; 291 rc = nfs_set_reparse_buf(p, mode, dev, &iov); 292 if (rc) 293 return rc; 294 295 data = (struct cifs_open_info_data) { 296 .reparse_point = true, 297 .reparse = { .tag = IO_REPARSE_TAG_NFS, .posix = p, }, 298 }; 299 300 new = smb2_get_reparse_inode(&data, inode->i_sb, xid, 301 tcon, full_path, false, &iov, NULL); 302 if (!IS_ERR(new)) 303 d_instantiate(dentry, new); 304 else 305 rc = PTR_ERR(new); 306 cifs_free_open_info(&data); 307 return rc; 308 } 309 310 static int wsl_set_reparse_buf(struct reparse_data_buffer *buf, 311 mode_t mode, struct kvec *iov) 312 { 313 u32 tag; 314 315 switch ((tag = reparse_mode_wsl_tag(mode))) { 316 case IO_REPARSE_TAG_LX_BLK: 317 case IO_REPARSE_TAG_LX_CHR: 318 case IO_REPARSE_TAG_LX_FIFO: 319 case IO_REPARSE_TAG_AF_UNIX: 320 break; 321 default: 322 return -EOPNOTSUPP; 323 } 324 325 buf->ReparseTag = cpu_to_le32(tag); 326 buf->Reserved = 0; 327 buf->ReparseDataLength = 0; 328 iov->iov_base = buf; 329 iov->iov_len = sizeof(*buf); 330 return 0; 331 } 332 333 static struct smb2_create_ea_ctx *ea_create_context(u32 dlen, size_t *cc_len) 334 { 335 struct smb2_create_ea_ctx *cc; 336 337 *cc_len = round_up(sizeof(*cc) + dlen, 8); 338 cc = kzalloc(*cc_len, GFP_KERNEL); 339 if (!cc) 340 return ERR_PTR(-ENOMEM); 341 342 cc->ctx.NameOffset = cpu_to_le16(offsetof(struct smb2_create_ea_ctx, 343 name)); 344 cc->ctx.NameLength = cpu_to_le16(4); 345 memcpy(cc->name, SMB2_CREATE_EA_BUFFER, strlen(SMB2_CREATE_EA_BUFFER)); 346 cc->ctx.DataOffset = cpu_to_le16(offsetof(struct smb2_create_ea_ctx, ea)); 347 cc->ctx.DataLength = cpu_to_le32(dlen); 348 return cc; 349 } 350 351 struct wsl_xattr { 352 const char *name; 353 __le64 value; 354 u16 size; 355 u32 next; 356 }; 357 358 static int wsl_set_xattrs(struct inode *inode, umode_t _mode, 359 dev_t _dev, struct kvec *iov) 360 { 361 struct smb2_file_full_ea_info *ea; 362 struct smb2_create_ea_ctx *cc; 363 struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx; 364 __le64 uid = cpu_to_le64(from_kuid(current_user_ns(), ctx->linux_uid)); 365 __le64 gid = cpu_to_le64(from_kgid(current_user_ns(), ctx->linux_gid)); 366 __le64 dev = cpu_to_le64(((u64)MINOR(_dev) << 32) | MAJOR(_dev)); 367 __le64 mode = cpu_to_le64(_mode); 368 struct wsl_xattr xattrs[] = { 369 { .name = SMB2_WSL_XATTR_UID, .value = uid, .size = SMB2_WSL_XATTR_UID_SIZE, }, 370 { .name = SMB2_WSL_XATTR_GID, .value = gid, .size = SMB2_WSL_XATTR_GID_SIZE, }, 371 { .name = SMB2_WSL_XATTR_MODE, .value = mode, .size = SMB2_WSL_XATTR_MODE_SIZE, }, 372 { .name = SMB2_WSL_XATTR_DEV, .value = dev, .size = SMB2_WSL_XATTR_DEV_SIZE, }, 373 }; 374 size_t cc_len; 375 u32 dlen = 0, next = 0; 376 int i, num_xattrs; 377 u8 name_size = SMB2_WSL_XATTR_NAME_LEN + 1; 378 379 memset(iov, 0, sizeof(*iov)); 380 381 /* Exclude $LXDEV xattr for sockets and fifos */ 382 if (S_ISSOCK(_mode) || S_ISFIFO(_mode)) 383 num_xattrs = ARRAY_SIZE(xattrs) - 1; 384 else 385 num_xattrs = ARRAY_SIZE(xattrs); 386 387 for (i = 0; i < num_xattrs; i++) { 388 xattrs[i].next = ALIGN(sizeof(*ea) + name_size + 389 xattrs[i].size, 4); 390 dlen += xattrs[i].next; 391 } 392 393 cc = ea_create_context(dlen, &cc_len); 394 if (IS_ERR(cc)) 395 return PTR_ERR(cc); 396 397 ea = &cc->ea; 398 for (i = 0; i < num_xattrs; i++) { 399 ea = (void *)((u8 *)ea + next); 400 next = xattrs[i].next; 401 ea->next_entry_offset = cpu_to_le32(next); 402 403 ea->ea_name_length = name_size - 1; 404 ea->ea_value_length = cpu_to_le16(xattrs[i].size); 405 memcpy(ea->ea_data, xattrs[i].name, name_size); 406 memcpy(&ea->ea_data[name_size], 407 &xattrs[i].value, xattrs[i].size); 408 } 409 ea->next_entry_offset = 0; 410 411 iov->iov_base = cc; 412 iov->iov_len = cc_len; 413 return 0; 414 } 415 416 static int mknod_wsl(unsigned int xid, struct inode *inode, 417 struct dentry *dentry, struct cifs_tcon *tcon, 418 const char *full_path, umode_t mode, dev_t dev) 419 { 420 struct cifs_open_info_data data; 421 struct reparse_data_buffer buf; 422 struct smb2_create_ea_ctx *cc; 423 struct inode *new; 424 unsigned int len; 425 struct kvec reparse_iov, xattr_iov; 426 int rc; 427 428 rc = wsl_set_reparse_buf(&buf, mode, &reparse_iov); 429 if (rc) 430 return rc; 431 432 rc = wsl_set_xattrs(inode, mode, dev, &xattr_iov); 433 if (rc) 434 return rc; 435 436 data = (struct cifs_open_info_data) { 437 .reparse_point = true, 438 .reparse = { .tag = le32_to_cpu(buf.ReparseTag), .buf = &buf, }, 439 }; 440 441 cc = xattr_iov.iov_base; 442 len = le32_to_cpu(cc->ctx.DataLength); 443 memcpy(data.wsl.eas, &cc->ea, len); 444 data.wsl.eas_len = len; 445 446 new = smb2_get_reparse_inode(&data, inode->i_sb, 447 xid, tcon, full_path, false, 448 &reparse_iov, &xattr_iov); 449 if (!IS_ERR(new)) 450 d_instantiate(dentry, new); 451 else 452 rc = PTR_ERR(new); 453 cifs_free_open_info(&data); 454 kfree(xattr_iov.iov_base); 455 return rc; 456 } 457 458 int smb2_mknod_reparse(unsigned int xid, struct inode *inode, 459 struct dentry *dentry, struct cifs_tcon *tcon, 460 const char *full_path, umode_t mode, dev_t dev) 461 { 462 struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx; 463 int rc = -EOPNOTSUPP; 464 465 switch (ctx->reparse_type) { 466 case CIFS_REPARSE_TYPE_NFS: 467 rc = mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev); 468 break; 469 case CIFS_REPARSE_TYPE_WSL: 470 rc = mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev); 471 break; 472 } 473 return rc; 474 } 475 476 /* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */ 477 static int parse_reparse_posix(struct reparse_posix_data *buf, 478 struct cifs_sb_info *cifs_sb, 479 struct cifs_open_info_data *data) 480 { 481 unsigned int len; 482 u64 type; 483 484 len = le16_to_cpu(buf->ReparseDataLength); 485 if (len < sizeof(buf->InodeType)) { 486 cifs_dbg(VFS, "srv returned malformed nfs buffer\n"); 487 return -EIO; 488 } 489 490 len -= sizeof(buf->InodeType); 491 492 switch ((type = le64_to_cpu(buf->InodeType))) { 493 case NFS_SPECFILE_LNK: 494 if (len == 0 || (len % 2)) { 495 cifs_dbg(VFS, "srv returned malformed nfs symlink buffer\n"); 496 return -EIO; 497 } 498 /* 499 * Check that buffer does not contain UTF-16 null codepoint 500 * because Linux cannot process symlink with null byte. 501 */ 502 if (UniStrnlen((wchar_t *)buf->DataBuffer, len/2) != len/2) { 503 cifs_dbg(VFS, "srv returned null byte in nfs symlink target location\n"); 504 return -EIO; 505 } 506 data->symlink_target = cifs_strndup_from_utf16(buf->DataBuffer, 507 len, true, 508 cifs_sb->local_nls); 509 if (!data->symlink_target) 510 return -ENOMEM; 511 cifs_dbg(FYI, "%s: target path: %s\n", 512 __func__, data->symlink_target); 513 break; 514 case NFS_SPECFILE_CHR: 515 case NFS_SPECFILE_BLK: 516 /* DataBuffer for block and char devices contains two 32-bit numbers */ 517 if (len != 8) { 518 cifs_dbg(VFS, "srv returned malformed nfs buffer for type: 0x%llx\n", type); 519 return -EIO; 520 } 521 break; 522 case NFS_SPECFILE_FIFO: 523 case NFS_SPECFILE_SOCK: 524 /* DataBuffer for fifos and sockets is empty */ 525 if (len != 0) { 526 cifs_dbg(VFS, "srv returned malformed nfs buffer for type: 0x%llx\n", type); 527 return -EIO; 528 } 529 break; 530 default: 531 cifs_dbg(VFS, "%s: unhandled inode type: 0x%llx\n", 532 __func__, type); 533 return -EOPNOTSUPP; 534 } 535 return 0; 536 } 537 538 int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len, 539 bool unicode, bool relative, 540 const char *full_path, 541 struct cifs_sb_info *cifs_sb) 542 { 543 char sep = CIFS_DIR_SEP(cifs_sb); 544 char *linux_target = NULL; 545 char *smb_target = NULL; 546 int levels; 547 int rc; 548 int i; 549 550 smb_target = cifs_strndup_from_utf16(buf, len, unicode, cifs_sb->local_nls); 551 if (!smb_target) { 552 rc = -ENOMEM; 553 goto out; 554 } 555 556 if (smb_target[0] == sep && relative) { 557 /* 558 * This is a relative SMB symlink from the top of the share, 559 * which is the top level directory of the Linux mount point. 560 * Linux does not support such relative symlinks, so convert 561 * it to the relative symlink from the current directory. 562 * full_path is the SMB path to the symlink (from which is 563 * extracted current directory) and smb_target is the SMB path 564 * where symlink points, therefore full_path must always be on 565 * the SMB share. 566 */ 567 int smb_target_len = strlen(smb_target)+1; 568 levels = 0; 569 for (i = 1; full_path[i]; i++) { /* i=1 to skip leading sep */ 570 if (full_path[i] == sep) 571 levels++; 572 } 573 linux_target = kmalloc(levels*3 + smb_target_len, GFP_KERNEL); 574 if (!linux_target) { 575 rc = -ENOMEM; 576 goto out; 577 } 578 for (i = 0; i < levels; i++) { 579 linux_target[i*3 + 0] = '.'; 580 linux_target[i*3 + 1] = '.'; 581 linux_target[i*3 + 2] = sep; 582 } 583 memcpy(linux_target + levels*3, smb_target+1, smb_target_len); /* +1 to skip leading sep */ 584 } else { 585 linux_target = smb_target; 586 smb_target = NULL; 587 } 588 589 if (sep == '\\') 590 convert_delimiter(linux_target, '/'); 591 592 rc = 0; 593 *target = linux_target; 594 595 cifs_dbg(FYI, "%s: symlink target: %s\n", __func__, *target); 596 597 out: 598 if (rc != 0) 599 kfree(linux_target); 600 kfree(smb_target); 601 return rc; 602 } 603 604 static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym, 605 u32 plen, bool unicode, 606 struct cifs_sb_info *cifs_sb, 607 const char *full_path, 608 struct cifs_open_info_data *data) 609 { 610 unsigned int len; 611 unsigned int offs; 612 613 /* We handle Symbolic Link reparse tag here. See: MS-FSCC 2.1.2.4 */ 614 615 offs = le16_to_cpu(sym->SubstituteNameOffset); 616 len = le16_to_cpu(sym->SubstituteNameLength); 617 if (offs + 20 > plen || offs + len + 20 > plen) { 618 cifs_dbg(VFS, "srv returned malformed symlink buffer\n"); 619 return -EIO; 620 } 621 622 return smb2_parse_native_symlink(&data->symlink_target, 623 sym->PathBuffer + offs, 624 len, 625 unicode, 626 le32_to_cpu(sym->Flags) & SYMLINK_FLAG_RELATIVE, 627 full_path, 628 cifs_sb); 629 } 630 631 int parse_reparse_point(struct reparse_data_buffer *buf, 632 u32 plen, struct cifs_sb_info *cifs_sb, 633 const char *full_path, 634 bool unicode, struct cifs_open_info_data *data) 635 { 636 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 637 638 data->reparse.buf = buf; 639 640 /* See MS-FSCC 2.1.2 */ 641 switch (le32_to_cpu(buf->ReparseTag)) { 642 case IO_REPARSE_TAG_NFS: 643 return parse_reparse_posix((struct reparse_posix_data *)buf, 644 cifs_sb, data); 645 case IO_REPARSE_TAG_SYMLINK: 646 return parse_reparse_symlink( 647 (struct reparse_symlink_data_buffer *)buf, 648 plen, unicode, cifs_sb, full_path, data); 649 case IO_REPARSE_TAG_LX_SYMLINK: 650 case IO_REPARSE_TAG_AF_UNIX: 651 case IO_REPARSE_TAG_LX_FIFO: 652 case IO_REPARSE_TAG_LX_CHR: 653 case IO_REPARSE_TAG_LX_BLK: 654 break; 655 default: 656 cifs_tcon_dbg(VFS | ONCE, "unhandled reparse tag: 0x%08x\n", 657 le32_to_cpu(buf->ReparseTag)); 658 break; 659 } 660 return 0; 661 } 662 663 int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb, 664 const char *full_path, 665 struct kvec *rsp_iov, 666 struct cifs_open_info_data *data) 667 { 668 struct reparse_data_buffer *buf; 669 struct smb2_ioctl_rsp *io = rsp_iov->iov_base; 670 u32 plen = le32_to_cpu(io->OutputCount); 671 672 buf = (struct reparse_data_buffer *)((u8 *)io + 673 le32_to_cpu(io->OutputOffset)); 674 return parse_reparse_point(buf, plen, cifs_sb, full_path, true, data); 675 } 676 677 static void wsl_to_fattr(struct cifs_open_info_data *data, 678 struct cifs_sb_info *cifs_sb, 679 u32 tag, struct cifs_fattr *fattr) 680 { 681 struct smb2_file_full_ea_info *ea; 682 u32 next = 0; 683 684 switch (tag) { 685 case IO_REPARSE_TAG_LX_SYMLINK: 686 fattr->cf_mode |= S_IFLNK; 687 break; 688 case IO_REPARSE_TAG_LX_FIFO: 689 fattr->cf_mode |= S_IFIFO; 690 break; 691 case IO_REPARSE_TAG_AF_UNIX: 692 fattr->cf_mode |= S_IFSOCK; 693 break; 694 case IO_REPARSE_TAG_LX_CHR: 695 fattr->cf_mode |= S_IFCHR; 696 break; 697 case IO_REPARSE_TAG_LX_BLK: 698 fattr->cf_mode |= S_IFBLK; 699 break; 700 } 701 702 if (!data->wsl.eas_len) 703 goto out; 704 705 ea = (struct smb2_file_full_ea_info *)data->wsl.eas; 706 do { 707 const char *name; 708 void *v; 709 u8 nlen; 710 711 ea = (void *)((u8 *)ea + next); 712 next = le32_to_cpu(ea->next_entry_offset); 713 if (!le16_to_cpu(ea->ea_value_length)) 714 continue; 715 716 name = ea->ea_data; 717 nlen = ea->ea_name_length; 718 v = (void *)((u8 *)ea->ea_data + ea->ea_name_length + 1); 719 720 if (!strncmp(name, SMB2_WSL_XATTR_UID, nlen)) 721 fattr->cf_uid = wsl_make_kuid(cifs_sb, v); 722 else if (!strncmp(name, SMB2_WSL_XATTR_GID, nlen)) 723 fattr->cf_gid = wsl_make_kgid(cifs_sb, v); 724 else if (!strncmp(name, SMB2_WSL_XATTR_MODE, nlen)) 725 fattr->cf_mode = (umode_t)le32_to_cpu(*(__le32 *)v); 726 else if (!strncmp(name, SMB2_WSL_XATTR_DEV, nlen)) 727 fattr->cf_rdev = reparse_mkdev(v); 728 } while (next); 729 out: 730 fattr->cf_dtype = S_DT(fattr->cf_mode); 731 } 732 733 bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, 734 struct cifs_fattr *fattr, 735 struct cifs_open_info_data *data) 736 { 737 struct reparse_posix_data *buf = data->reparse.posix; 738 u32 tag = data->reparse.tag; 739 740 if (tag == IO_REPARSE_TAG_NFS && buf) { 741 if (le16_to_cpu(buf->ReparseDataLength) < sizeof(buf->InodeType)) 742 return false; 743 switch (le64_to_cpu(buf->InodeType)) { 744 case NFS_SPECFILE_CHR: 745 if (le16_to_cpu(buf->ReparseDataLength) != sizeof(buf->InodeType) + 8) 746 return false; 747 fattr->cf_mode |= S_IFCHR; 748 fattr->cf_rdev = reparse_mkdev(buf->DataBuffer); 749 break; 750 case NFS_SPECFILE_BLK: 751 if (le16_to_cpu(buf->ReparseDataLength) != sizeof(buf->InodeType) + 8) 752 return false; 753 fattr->cf_mode |= S_IFBLK; 754 fattr->cf_rdev = reparse_mkdev(buf->DataBuffer); 755 break; 756 case NFS_SPECFILE_FIFO: 757 fattr->cf_mode |= S_IFIFO; 758 break; 759 case NFS_SPECFILE_SOCK: 760 fattr->cf_mode |= S_IFSOCK; 761 break; 762 case NFS_SPECFILE_LNK: 763 fattr->cf_mode |= S_IFLNK; 764 break; 765 default: 766 WARN_ON_ONCE(1); 767 return false; 768 } 769 goto out; 770 } 771 772 switch (tag) { 773 case IO_REPARSE_TAG_INTERNAL: 774 if (!(fattr->cf_cifsattrs & ATTR_DIRECTORY)) 775 return false; 776 fallthrough; 777 case IO_REPARSE_TAG_DFS: 778 case IO_REPARSE_TAG_DFSR: 779 case IO_REPARSE_TAG_MOUNT_POINT: 780 /* See cifs_create_junction_fattr() */ 781 fattr->cf_mode = S_IFDIR | 0711; 782 break; 783 case IO_REPARSE_TAG_LX_SYMLINK: 784 case IO_REPARSE_TAG_LX_FIFO: 785 case IO_REPARSE_TAG_AF_UNIX: 786 case IO_REPARSE_TAG_LX_CHR: 787 case IO_REPARSE_TAG_LX_BLK: 788 wsl_to_fattr(data, cifs_sb, tag, fattr); 789 break; 790 case 0: /* SMB1 symlink */ 791 case IO_REPARSE_TAG_SYMLINK: 792 case IO_REPARSE_TAG_NFS: 793 fattr->cf_mode |= S_IFLNK; 794 break; 795 default: 796 return false; 797 } 798 out: 799 fattr->cf_dtype = S_DT(fattr->cf_mode); 800 return true; 801 } 802