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 data->symlink_target = cifs_strndup_from_utf16(buf->DataBuffer, 334 len, true, 335 cifs_sb->local_nls); 336 if (!data->symlink_target) 337 return -ENOMEM; 338 cifs_dbg(FYI, "%s: target path: %s\n", 339 __func__, data->symlink_target); 340 break; 341 case NFS_SPECFILE_CHR: 342 case NFS_SPECFILE_BLK: 343 case NFS_SPECFILE_FIFO: 344 case NFS_SPECFILE_SOCK: 345 break; 346 default: 347 cifs_dbg(VFS, "%s: unhandled inode type: 0x%llx\n", 348 __func__, type); 349 return -EOPNOTSUPP; 350 } 351 return 0; 352 } 353 354 static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym, 355 u32 plen, bool unicode, 356 struct cifs_sb_info *cifs_sb, 357 struct cifs_open_info_data *data) 358 { 359 unsigned int len; 360 unsigned int offs; 361 362 /* We handle Symbolic Link reparse tag here. See: MS-FSCC 2.1.2.4 */ 363 364 offs = le16_to_cpu(sym->SubstituteNameOffset); 365 len = le16_to_cpu(sym->SubstituteNameLength); 366 if (offs + 20 > plen || offs + len + 20 > plen) { 367 cifs_dbg(VFS, "srv returned malformed symlink buffer\n"); 368 return -EIO; 369 } 370 371 data->symlink_target = cifs_strndup_from_utf16(sym->PathBuffer + offs, 372 len, unicode, 373 cifs_sb->local_nls); 374 if (!data->symlink_target) 375 return -ENOMEM; 376 377 convert_delimiter(data->symlink_target, '/'); 378 cifs_dbg(FYI, "%s: target path: %s\n", __func__, data->symlink_target); 379 380 return 0; 381 } 382 383 int parse_reparse_point(struct reparse_data_buffer *buf, 384 u32 plen, struct cifs_sb_info *cifs_sb, 385 bool unicode, struct cifs_open_info_data *data) 386 { 387 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 388 389 data->reparse.buf = buf; 390 391 /* See MS-FSCC 2.1.2 */ 392 switch (le32_to_cpu(buf->ReparseTag)) { 393 case IO_REPARSE_TAG_NFS: 394 return parse_reparse_posix((struct reparse_posix_data *)buf, 395 cifs_sb, data); 396 case IO_REPARSE_TAG_SYMLINK: 397 return parse_reparse_symlink( 398 (struct reparse_symlink_data_buffer *)buf, 399 plen, unicode, cifs_sb, data); 400 case IO_REPARSE_TAG_LX_SYMLINK: 401 case IO_REPARSE_TAG_AF_UNIX: 402 case IO_REPARSE_TAG_LX_FIFO: 403 case IO_REPARSE_TAG_LX_CHR: 404 case IO_REPARSE_TAG_LX_BLK: 405 break; 406 default: 407 cifs_tcon_dbg(VFS | ONCE, "unhandled reparse tag: 0x%08x\n", 408 le32_to_cpu(buf->ReparseTag)); 409 break; 410 } 411 return 0; 412 } 413 414 int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb, 415 struct kvec *rsp_iov, 416 struct cifs_open_info_data *data) 417 { 418 struct reparse_data_buffer *buf; 419 struct smb2_ioctl_rsp *io = rsp_iov->iov_base; 420 u32 plen = le32_to_cpu(io->OutputCount); 421 422 buf = (struct reparse_data_buffer *)((u8 *)io + 423 le32_to_cpu(io->OutputOffset)); 424 return parse_reparse_point(buf, plen, cifs_sb, true, data); 425 } 426 427 static void wsl_to_fattr(struct cifs_open_info_data *data, 428 struct cifs_sb_info *cifs_sb, 429 u32 tag, struct cifs_fattr *fattr) 430 { 431 struct smb2_file_full_ea_info *ea; 432 u32 next = 0; 433 434 switch (tag) { 435 case IO_REPARSE_TAG_LX_SYMLINK: 436 fattr->cf_mode |= S_IFLNK; 437 break; 438 case IO_REPARSE_TAG_LX_FIFO: 439 fattr->cf_mode |= S_IFIFO; 440 break; 441 case IO_REPARSE_TAG_AF_UNIX: 442 fattr->cf_mode |= S_IFSOCK; 443 break; 444 case IO_REPARSE_TAG_LX_CHR: 445 fattr->cf_mode |= S_IFCHR; 446 break; 447 case IO_REPARSE_TAG_LX_BLK: 448 fattr->cf_mode |= S_IFBLK; 449 break; 450 } 451 452 if (!data->wsl.eas_len) 453 goto out; 454 455 ea = (struct smb2_file_full_ea_info *)data->wsl.eas; 456 do { 457 const char *name; 458 void *v; 459 u8 nlen; 460 461 ea = (void *)((u8 *)ea + next); 462 next = le32_to_cpu(ea->next_entry_offset); 463 if (!le16_to_cpu(ea->ea_value_length)) 464 continue; 465 466 name = ea->ea_data; 467 nlen = ea->ea_name_length; 468 v = (void *)((u8 *)ea->ea_data + ea->ea_name_length + 1); 469 470 if (!strncmp(name, SMB2_WSL_XATTR_UID, nlen)) 471 fattr->cf_uid = wsl_make_kuid(cifs_sb, v); 472 else if (!strncmp(name, SMB2_WSL_XATTR_GID, nlen)) 473 fattr->cf_gid = wsl_make_kgid(cifs_sb, v); 474 else if (!strncmp(name, SMB2_WSL_XATTR_MODE, nlen)) 475 fattr->cf_mode = (umode_t)le32_to_cpu(*(__le32 *)v); 476 else if (!strncmp(name, SMB2_WSL_XATTR_DEV, nlen)) 477 fattr->cf_rdev = wsl_mkdev(v); 478 } while (next); 479 out: 480 fattr->cf_dtype = S_DT(fattr->cf_mode); 481 } 482 483 bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, 484 struct cifs_fattr *fattr, 485 struct cifs_open_info_data *data) 486 { 487 struct reparse_posix_data *buf = data->reparse.posix; 488 u32 tag = data->reparse.tag; 489 490 if (tag == IO_REPARSE_TAG_NFS && buf) { 491 if (le16_to_cpu(buf->ReparseDataLength) < sizeof(buf->InodeType)) 492 return false; 493 switch (le64_to_cpu(buf->InodeType)) { 494 case NFS_SPECFILE_CHR: 495 if (le16_to_cpu(buf->ReparseDataLength) != sizeof(buf->InodeType) + 8) 496 return false; 497 fattr->cf_mode |= S_IFCHR; 498 fattr->cf_rdev = reparse_nfs_mkdev(buf); 499 break; 500 case NFS_SPECFILE_BLK: 501 if (le16_to_cpu(buf->ReparseDataLength) != sizeof(buf->InodeType) + 8) 502 return false; 503 fattr->cf_mode |= S_IFBLK; 504 fattr->cf_rdev = reparse_nfs_mkdev(buf); 505 break; 506 case NFS_SPECFILE_FIFO: 507 fattr->cf_mode |= S_IFIFO; 508 break; 509 case NFS_SPECFILE_SOCK: 510 fattr->cf_mode |= S_IFSOCK; 511 break; 512 case NFS_SPECFILE_LNK: 513 fattr->cf_mode |= S_IFLNK; 514 break; 515 default: 516 WARN_ON_ONCE(1); 517 return false; 518 } 519 goto out; 520 } 521 522 switch (tag) { 523 case IO_REPARSE_TAG_INTERNAL: 524 if (!(fattr->cf_cifsattrs & ATTR_DIRECTORY)) 525 return false; 526 fallthrough; 527 case IO_REPARSE_TAG_DFS: 528 case IO_REPARSE_TAG_DFSR: 529 case IO_REPARSE_TAG_MOUNT_POINT: 530 /* See cifs_create_junction_fattr() */ 531 fattr->cf_mode = S_IFDIR | 0711; 532 break; 533 case IO_REPARSE_TAG_LX_SYMLINK: 534 case IO_REPARSE_TAG_LX_FIFO: 535 case IO_REPARSE_TAG_AF_UNIX: 536 case IO_REPARSE_TAG_LX_CHR: 537 case IO_REPARSE_TAG_LX_BLK: 538 wsl_to_fattr(data, cifs_sb, tag, fattr); 539 break; 540 case 0: /* SMB1 symlink */ 541 case IO_REPARSE_TAG_SYMLINK: 542 case IO_REPARSE_TAG_NFS: 543 fattr->cf_mode |= S_IFLNK; 544 break; 545 default: 546 return false; 547 } 548 out: 549 fattr->cf_dtype = S_DT(fattr->cf_mode); 550 return true; 551 } 552