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 int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode, 18 struct dentry *dentry, struct cifs_tcon *tcon, 19 const char *full_path, const char *symname) 20 { 21 struct reparse_symlink_data_buffer *buf = NULL; 22 struct cifs_open_info_data data; 23 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 24 struct inode *new; 25 struct kvec iov; 26 __le16 *path; 27 char *sym, sep = CIFS_DIR_SEP(cifs_sb); 28 u16 len, plen; 29 int rc = 0; 30 31 sym = kstrdup(symname, GFP_KERNEL); 32 if (!sym) 33 return -ENOMEM; 34 35 data = (struct cifs_open_info_data) { 36 .reparse_point = true, 37 .reparse = { .tag = IO_REPARSE_TAG_SYMLINK, }, 38 .symlink_target = sym, 39 }; 40 41 convert_delimiter(sym, sep); 42 path = cifs_convert_path_to_utf16(sym, cifs_sb); 43 if (!path) { 44 rc = -ENOMEM; 45 goto out; 46 } 47 48 plen = 2 * UniStrnlen((wchar_t *)path, PATH_MAX); 49 len = sizeof(*buf) + plen * 2; 50 buf = kzalloc(len, GFP_KERNEL); 51 if (!buf) { 52 rc = -ENOMEM; 53 goto out; 54 } 55 56 buf->ReparseTag = cpu_to_le32(IO_REPARSE_TAG_SYMLINK); 57 buf->ReparseDataLength = cpu_to_le16(len - sizeof(struct reparse_data_buffer)); 58 buf->SubstituteNameOffset = cpu_to_le16(plen); 59 buf->SubstituteNameLength = cpu_to_le16(plen); 60 memcpy(&buf->PathBuffer[plen], path, plen); 61 buf->PrintNameOffset = 0; 62 buf->PrintNameLength = cpu_to_le16(plen); 63 memcpy(buf->PathBuffer, path, plen); 64 buf->Flags = cpu_to_le32(*symname != '/' ? SYMLINK_FLAG_RELATIVE : 0); 65 if (*sym != sep) 66 buf->Flags = cpu_to_le32(SYMLINK_FLAG_RELATIVE); 67 68 convert_delimiter(sym, '/'); 69 iov.iov_base = buf; 70 iov.iov_len = len; 71 new = smb2_get_reparse_inode(&data, inode->i_sb, xid, 72 tcon, full_path, &iov, NULL); 73 if (!IS_ERR(new)) 74 d_instantiate(dentry, new); 75 else 76 rc = PTR_ERR(new); 77 out: 78 kfree(path); 79 cifs_free_open_info(&data); 80 kfree(buf); 81 return rc; 82 } 83 84 static int nfs_set_reparse_buf(struct reparse_posix_data *buf, 85 mode_t mode, dev_t dev, 86 struct kvec *iov) 87 { 88 u64 type; 89 u16 len, dlen; 90 91 len = sizeof(*buf); 92 93 switch ((type = reparse_mode_nfs_type(mode))) { 94 case NFS_SPECFILE_BLK: 95 case NFS_SPECFILE_CHR: 96 dlen = sizeof(__le64); 97 break; 98 case NFS_SPECFILE_FIFO: 99 case NFS_SPECFILE_SOCK: 100 dlen = 0; 101 break; 102 default: 103 return -EOPNOTSUPP; 104 } 105 106 buf->ReparseTag = cpu_to_le32(IO_REPARSE_TAG_NFS); 107 buf->Reserved = 0; 108 buf->InodeType = cpu_to_le64(type); 109 buf->ReparseDataLength = cpu_to_le16(len + dlen - 110 sizeof(struct reparse_data_buffer)); 111 *(__le64 *)buf->DataBuffer = cpu_to_le64(((u64)MAJOR(dev) << 32) | 112 MINOR(dev)); 113 iov->iov_base = buf; 114 iov->iov_len = len + dlen; 115 return 0; 116 } 117 118 static int mknod_nfs(unsigned int xid, struct inode *inode, 119 struct dentry *dentry, struct cifs_tcon *tcon, 120 const char *full_path, umode_t mode, dev_t dev) 121 { 122 struct cifs_open_info_data data; 123 struct reparse_posix_data *p; 124 struct inode *new; 125 struct kvec iov; 126 __u8 buf[sizeof(*p) + sizeof(__le64)]; 127 int rc; 128 129 p = (struct reparse_posix_data *)buf; 130 rc = nfs_set_reparse_buf(p, mode, dev, &iov); 131 if (rc) 132 return rc; 133 134 data = (struct cifs_open_info_data) { 135 .reparse_point = true, 136 .reparse = { .tag = IO_REPARSE_TAG_NFS, .posix = p, }, 137 }; 138 139 new = smb2_get_reparse_inode(&data, inode->i_sb, xid, 140 tcon, full_path, &iov, NULL); 141 if (!IS_ERR(new)) 142 d_instantiate(dentry, new); 143 else 144 rc = PTR_ERR(new); 145 cifs_free_open_info(&data); 146 return rc; 147 } 148 149 static int wsl_set_reparse_buf(struct reparse_data_buffer *buf, 150 mode_t mode, struct kvec *iov) 151 { 152 u32 tag; 153 154 switch ((tag = reparse_mode_wsl_tag(mode))) { 155 case IO_REPARSE_TAG_LX_BLK: 156 case IO_REPARSE_TAG_LX_CHR: 157 case IO_REPARSE_TAG_LX_FIFO: 158 case IO_REPARSE_TAG_AF_UNIX: 159 break; 160 default: 161 return -EOPNOTSUPP; 162 } 163 164 buf->ReparseTag = cpu_to_le32(tag); 165 buf->Reserved = 0; 166 buf->ReparseDataLength = 0; 167 iov->iov_base = buf; 168 iov->iov_len = sizeof(*buf); 169 return 0; 170 } 171 172 static struct smb2_create_ea_ctx *ea_create_context(u32 dlen, size_t *cc_len) 173 { 174 struct smb2_create_ea_ctx *cc; 175 176 *cc_len = round_up(sizeof(*cc) + dlen, 8); 177 cc = kzalloc(*cc_len, GFP_KERNEL); 178 if (!cc) 179 return ERR_PTR(-ENOMEM); 180 181 cc->ctx.NameOffset = cpu_to_le16(offsetof(struct smb2_create_ea_ctx, 182 name)); 183 cc->ctx.NameLength = cpu_to_le16(4); 184 memcpy(cc->name, SMB2_CREATE_EA_BUFFER, strlen(SMB2_CREATE_EA_BUFFER)); 185 cc->ctx.DataOffset = cpu_to_le16(offsetof(struct smb2_create_ea_ctx, ea)); 186 cc->ctx.DataLength = cpu_to_le32(dlen); 187 return cc; 188 } 189 190 struct wsl_xattr { 191 const char *name; 192 __le64 value; 193 u16 size; 194 u32 next; 195 }; 196 197 static int wsl_set_xattrs(struct inode *inode, umode_t _mode, 198 dev_t _dev, struct kvec *iov) 199 { 200 struct smb2_file_full_ea_info *ea; 201 struct smb2_create_ea_ctx *cc; 202 struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx; 203 __le64 uid = cpu_to_le64(from_kuid(current_user_ns(), ctx->linux_uid)); 204 __le64 gid = cpu_to_le64(from_kgid(current_user_ns(), ctx->linux_gid)); 205 __le64 dev = cpu_to_le64(((u64)MINOR(_dev) << 32) | MAJOR(_dev)); 206 __le64 mode = cpu_to_le64(_mode); 207 struct wsl_xattr xattrs[] = { 208 { .name = SMB2_WSL_XATTR_UID, .value = uid, .size = SMB2_WSL_XATTR_UID_SIZE, }, 209 { .name = SMB2_WSL_XATTR_GID, .value = gid, .size = SMB2_WSL_XATTR_GID_SIZE, }, 210 { .name = SMB2_WSL_XATTR_MODE, .value = mode, .size = SMB2_WSL_XATTR_MODE_SIZE, }, 211 { .name = SMB2_WSL_XATTR_DEV, .value = dev, .size = SMB2_WSL_XATTR_DEV_SIZE, }, 212 }; 213 size_t cc_len; 214 u32 dlen = 0, next = 0; 215 int i, num_xattrs; 216 u8 name_size = SMB2_WSL_XATTR_NAME_LEN + 1; 217 218 memset(iov, 0, sizeof(*iov)); 219 220 /* Exclude $LXDEV xattr for sockets and fifos */ 221 if (S_ISSOCK(_mode) || S_ISFIFO(_mode)) 222 num_xattrs = ARRAY_SIZE(xattrs) - 1; 223 else 224 num_xattrs = ARRAY_SIZE(xattrs); 225 226 for (i = 0; i < num_xattrs; i++) { 227 xattrs[i].next = ALIGN(sizeof(*ea) + name_size + 228 xattrs[i].size, 4); 229 dlen += xattrs[i].next; 230 } 231 232 cc = ea_create_context(dlen, &cc_len); 233 if (IS_ERR(cc)) 234 return PTR_ERR(cc); 235 236 ea = &cc->ea; 237 for (i = 0; i < num_xattrs; i++) { 238 ea = (void *)((u8 *)ea + next); 239 next = xattrs[i].next; 240 ea->next_entry_offset = cpu_to_le32(next); 241 242 ea->ea_name_length = name_size - 1; 243 ea->ea_value_length = cpu_to_le16(xattrs[i].size); 244 memcpy(ea->ea_data, xattrs[i].name, name_size); 245 memcpy(&ea->ea_data[name_size], 246 &xattrs[i].value, xattrs[i].size); 247 } 248 ea->next_entry_offset = 0; 249 250 iov->iov_base = cc; 251 iov->iov_len = cc_len; 252 return 0; 253 } 254 255 static int mknod_wsl(unsigned int xid, struct inode *inode, 256 struct dentry *dentry, struct cifs_tcon *tcon, 257 const char *full_path, umode_t mode, dev_t dev) 258 { 259 struct cifs_open_info_data data; 260 struct reparse_data_buffer buf; 261 struct smb2_create_ea_ctx *cc; 262 struct inode *new; 263 unsigned int len; 264 struct kvec reparse_iov, xattr_iov; 265 int rc; 266 267 rc = wsl_set_reparse_buf(&buf, mode, &reparse_iov); 268 if (rc) 269 return rc; 270 271 rc = wsl_set_xattrs(inode, mode, dev, &xattr_iov); 272 if (rc) 273 return rc; 274 275 data = (struct cifs_open_info_data) { 276 .reparse_point = true, 277 .reparse = { .tag = le32_to_cpu(buf.ReparseTag), .buf = &buf, }, 278 }; 279 280 cc = xattr_iov.iov_base; 281 len = le32_to_cpu(cc->ctx.DataLength); 282 memcpy(data.wsl.eas, &cc->ea, len); 283 data.wsl.eas_len = len; 284 285 new = smb2_get_reparse_inode(&data, inode->i_sb, 286 xid, tcon, full_path, 287 &reparse_iov, &xattr_iov); 288 if (!IS_ERR(new)) 289 d_instantiate(dentry, new); 290 else 291 rc = PTR_ERR(new); 292 cifs_free_open_info(&data); 293 kfree(xattr_iov.iov_base); 294 return rc; 295 } 296 297 int smb2_mknod_reparse(unsigned int xid, struct inode *inode, 298 struct dentry *dentry, struct cifs_tcon *tcon, 299 const char *full_path, umode_t mode, dev_t dev) 300 { 301 struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx; 302 int rc = -EOPNOTSUPP; 303 304 switch (ctx->reparse_type) { 305 case CIFS_REPARSE_TYPE_NFS: 306 rc = mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev); 307 break; 308 case CIFS_REPARSE_TYPE_WSL: 309 rc = mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev); 310 break; 311 } 312 return rc; 313 } 314 315 /* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */ 316 static int parse_reparse_posix(struct reparse_posix_data *buf, 317 struct cifs_sb_info *cifs_sb, 318 struct cifs_open_info_data *data) 319 { 320 unsigned int len; 321 u64 type; 322 323 len = le16_to_cpu(buf->ReparseDataLength); 324 if (len < sizeof(buf->InodeType)) { 325 cifs_dbg(VFS, "srv returned malformed nfs buffer\n"); 326 return -EIO; 327 } 328 329 len -= sizeof(buf->InodeType); 330 331 switch ((type = le64_to_cpu(buf->InodeType))) { 332 case NFS_SPECFILE_LNK: 333 if (len == 0 || (len % 2)) { 334 cifs_dbg(VFS, "srv returned malformed nfs symlink buffer\n"); 335 return -EIO; 336 } 337 /* 338 * Check that buffer does not contain UTF-16 null codepoint 339 * because Linux cannot process symlink with null byte. 340 */ 341 if (UniStrnlen((wchar_t *)buf->DataBuffer, len/2) != len/2) { 342 cifs_dbg(VFS, "srv returned null byte in nfs symlink target location\n"); 343 return -EIO; 344 } 345 data->symlink_target = cifs_strndup_from_utf16(buf->DataBuffer, 346 len, true, 347 cifs_sb->local_nls); 348 if (!data->symlink_target) 349 return -ENOMEM; 350 cifs_dbg(FYI, "%s: target path: %s\n", 351 __func__, data->symlink_target); 352 break; 353 case NFS_SPECFILE_CHR: 354 case NFS_SPECFILE_BLK: 355 /* DataBuffer for block and char devices contains two 32-bit numbers */ 356 if (len != 8) { 357 cifs_dbg(VFS, "srv returned malformed nfs buffer for type: 0x%llx\n", type); 358 return -EIO; 359 } 360 break; 361 case NFS_SPECFILE_FIFO: 362 case NFS_SPECFILE_SOCK: 363 /* DataBuffer for fifos and sockets is empty */ 364 if (len != 0) { 365 cifs_dbg(VFS, "srv returned malformed nfs buffer for type: 0x%llx\n", type); 366 return -EIO; 367 } 368 break; 369 default: 370 cifs_dbg(VFS, "%s: unhandled inode type: 0x%llx\n", 371 __func__, type); 372 return -EOPNOTSUPP; 373 } 374 return 0; 375 } 376 377 static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym, 378 u32 plen, bool unicode, 379 struct cifs_sb_info *cifs_sb, 380 struct cifs_open_info_data *data) 381 { 382 unsigned int len; 383 unsigned int offs; 384 385 /* We handle Symbolic Link reparse tag here. See: MS-FSCC 2.1.2.4 */ 386 387 offs = le16_to_cpu(sym->SubstituteNameOffset); 388 len = le16_to_cpu(sym->SubstituteNameLength); 389 if (offs + 20 > plen || offs + len + 20 > plen) { 390 cifs_dbg(VFS, "srv returned malformed symlink buffer\n"); 391 return -EIO; 392 } 393 394 data->symlink_target = cifs_strndup_from_utf16(sym->PathBuffer + offs, 395 len, unicode, 396 cifs_sb->local_nls); 397 if (!data->symlink_target) 398 return -ENOMEM; 399 400 convert_delimiter(data->symlink_target, '/'); 401 cifs_dbg(FYI, "%s: target path: %s\n", __func__, data->symlink_target); 402 403 return 0; 404 } 405 406 int parse_reparse_point(struct reparse_data_buffer *buf, 407 u32 plen, struct cifs_sb_info *cifs_sb, 408 bool unicode, struct cifs_open_info_data *data) 409 { 410 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 411 412 data->reparse.buf = buf; 413 414 /* See MS-FSCC 2.1.2 */ 415 switch (le32_to_cpu(buf->ReparseTag)) { 416 case IO_REPARSE_TAG_NFS: 417 return parse_reparse_posix((struct reparse_posix_data *)buf, 418 cifs_sb, data); 419 case IO_REPARSE_TAG_SYMLINK: 420 return parse_reparse_symlink( 421 (struct reparse_symlink_data_buffer *)buf, 422 plen, unicode, cifs_sb, data); 423 case IO_REPARSE_TAG_LX_SYMLINK: 424 case IO_REPARSE_TAG_AF_UNIX: 425 case IO_REPARSE_TAG_LX_FIFO: 426 case IO_REPARSE_TAG_LX_CHR: 427 case IO_REPARSE_TAG_LX_BLK: 428 break; 429 default: 430 cifs_tcon_dbg(VFS | ONCE, "unhandled reparse tag: 0x%08x\n", 431 le32_to_cpu(buf->ReparseTag)); 432 break; 433 } 434 return 0; 435 } 436 437 int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb, 438 struct kvec *rsp_iov, 439 struct cifs_open_info_data *data) 440 { 441 struct reparse_data_buffer *buf; 442 struct smb2_ioctl_rsp *io = rsp_iov->iov_base; 443 u32 plen = le32_to_cpu(io->OutputCount); 444 445 buf = (struct reparse_data_buffer *)((u8 *)io + 446 le32_to_cpu(io->OutputOffset)); 447 return parse_reparse_point(buf, plen, cifs_sb, true, data); 448 } 449 450 static void wsl_to_fattr(struct cifs_open_info_data *data, 451 struct cifs_sb_info *cifs_sb, 452 u32 tag, struct cifs_fattr *fattr) 453 { 454 struct smb2_file_full_ea_info *ea; 455 u32 next = 0; 456 457 switch (tag) { 458 case IO_REPARSE_TAG_LX_SYMLINK: 459 fattr->cf_mode |= S_IFLNK; 460 break; 461 case IO_REPARSE_TAG_LX_FIFO: 462 fattr->cf_mode |= S_IFIFO; 463 break; 464 case IO_REPARSE_TAG_AF_UNIX: 465 fattr->cf_mode |= S_IFSOCK; 466 break; 467 case IO_REPARSE_TAG_LX_CHR: 468 fattr->cf_mode |= S_IFCHR; 469 break; 470 case IO_REPARSE_TAG_LX_BLK: 471 fattr->cf_mode |= S_IFBLK; 472 break; 473 } 474 475 if (!data->wsl.eas_len) 476 goto out; 477 478 ea = (struct smb2_file_full_ea_info *)data->wsl.eas; 479 do { 480 const char *name; 481 void *v; 482 u8 nlen; 483 484 ea = (void *)((u8 *)ea + next); 485 next = le32_to_cpu(ea->next_entry_offset); 486 if (!le16_to_cpu(ea->ea_value_length)) 487 continue; 488 489 name = ea->ea_data; 490 nlen = ea->ea_name_length; 491 v = (void *)((u8 *)ea->ea_data + ea->ea_name_length + 1); 492 493 if (!strncmp(name, SMB2_WSL_XATTR_UID, nlen)) 494 fattr->cf_uid = wsl_make_kuid(cifs_sb, v); 495 else if (!strncmp(name, SMB2_WSL_XATTR_GID, nlen)) 496 fattr->cf_gid = wsl_make_kgid(cifs_sb, v); 497 else if (!strncmp(name, SMB2_WSL_XATTR_MODE, nlen)) 498 fattr->cf_mode = (umode_t)le32_to_cpu(*(__le32 *)v); 499 else if (!strncmp(name, SMB2_WSL_XATTR_DEV, nlen)) 500 fattr->cf_rdev = wsl_mkdev(v); 501 } while (next); 502 out: 503 fattr->cf_dtype = S_DT(fattr->cf_mode); 504 } 505 506 bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, 507 struct cifs_fattr *fattr, 508 struct cifs_open_info_data *data) 509 { 510 struct reparse_posix_data *buf = data->reparse.posix; 511 u32 tag = data->reparse.tag; 512 513 if (tag == IO_REPARSE_TAG_NFS && buf) { 514 if (le16_to_cpu(buf->ReparseDataLength) < sizeof(buf->InodeType)) 515 return false; 516 switch (le64_to_cpu(buf->InodeType)) { 517 case NFS_SPECFILE_CHR: 518 if (le16_to_cpu(buf->ReparseDataLength) != sizeof(buf->InodeType) + 8) 519 return false; 520 fattr->cf_mode |= S_IFCHR; 521 fattr->cf_rdev = reparse_nfs_mkdev(buf); 522 break; 523 case NFS_SPECFILE_BLK: 524 if (le16_to_cpu(buf->ReparseDataLength) != sizeof(buf->InodeType) + 8) 525 return false; 526 fattr->cf_mode |= S_IFBLK; 527 fattr->cf_rdev = reparse_nfs_mkdev(buf); 528 break; 529 case NFS_SPECFILE_FIFO: 530 fattr->cf_mode |= S_IFIFO; 531 break; 532 case NFS_SPECFILE_SOCK: 533 fattr->cf_mode |= S_IFSOCK; 534 break; 535 case NFS_SPECFILE_LNK: 536 fattr->cf_mode |= S_IFLNK; 537 break; 538 default: 539 WARN_ON_ONCE(1); 540 return false; 541 } 542 goto out; 543 } 544 545 switch (tag) { 546 case IO_REPARSE_TAG_INTERNAL: 547 if (!(fattr->cf_cifsattrs & ATTR_DIRECTORY)) 548 return false; 549 fallthrough; 550 case IO_REPARSE_TAG_DFS: 551 case IO_REPARSE_TAG_DFSR: 552 case IO_REPARSE_TAG_MOUNT_POINT: 553 /* See cifs_create_junction_fattr() */ 554 fattr->cf_mode = S_IFDIR | 0711; 555 break; 556 case IO_REPARSE_TAG_LX_SYMLINK: 557 case IO_REPARSE_TAG_LX_FIFO: 558 case IO_REPARSE_TAG_AF_UNIX: 559 case IO_REPARSE_TAG_LX_CHR: 560 case IO_REPARSE_TAG_LX_BLK: 561 wsl_to_fattr(data, cifs_sb, tag, fattr); 562 break; 563 case 0: /* SMB1 symlink */ 564 case IO_REPARSE_TAG_SYMLINK: 565 case IO_REPARSE_TAG_NFS: 566 fattr->cf_mode |= S_IFLNK; 567 break; 568 default: 569 return false; 570 } 571 out: 572 fattr->cf_dtype = S_DT(fattr->cf_mode); 573 return true; 574 } 575