diff options
| -rw-r--r-- | fs/cifs/smb2ops.c | 64 | ||||
| -rw-r--r-- | fs/cifs/smb2pdu.h | 14 |
2 files changed, 73 insertions, 5 deletions
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 3fdc6a41b304..9fd56b0acd7e 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
| @@ -2372,6 +2372,41 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses, | |||
| 2372 | kfree(dfs_rsp); | 2372 | kfree(dfs_rsp); |
| 2373 | return rc; | 2373 | return rc; |
| 2374 | } | 2374 | } |
| 2375 | |||
| 2376 | static int | ||
| 2377 | parse_reparse_symlink(struct reparse_symlink_data_buffer *symlink_buf, | ||
| 2378 | u32 plen, char **target_path, | ||
| 2379 | struct cifs_sb_info *cifs_sb) | ||
| 2380 | { | ||
| 2381 | unsigned int sub_len; | ||
| 2382 | unsigned int sub_offset; | ||
| 2383 | |||
| 2384 | /* We only handle Symbolic Link : MS-FSCC 2.1.2.4 */ | ||
| 2385 | if (le32_to_cpu(symlink_buf->ReparseTag) != IO_REPARSE_TAG_SYMLINK) { | ||
| 2386 | cifs_dbg(VFS, "srv returned invalid symlink buffer\n"); | ||
| 2387 | return -EIO; | ||
| 2388 | } | ||
| 2389 | |||
| 2390 | sub_offset = le16_to_cpu(symlink_buf->SubstituteNameOffset); | ||
| 2391 | sub_len = le16_to_cpu(symlink_buf->SubstituteNameLength); | ||
| 2392 | if (sub_offset + 20 > plen || | ||
| 2393 | sub_offset + sub_len + 20 > plen) { | ||
| 2394 | cifs_dbg(VFS, "srv returned malformed symlink buffer\n"); | ||
| 2395 | return -EIO; | ||
| 2396 | } | ||
| 2397 | |||
| 2398 | *target_path = cifs_strndup_from_utf16( | ||
| 2399 | symlink_buf->PathBuffer + sub_offset, | ||
| 2400 | sub_len, true, cifs_sb->local_nls); | ||
| 2401 | if (!(*target_path)) | ||
| 2402 | return -ENOMEM; | ||
| 2403 | |||
| 2404 | convert_delimiter(*target_path, '/'); | ||
| 2405 | cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path); | ||
| 2406 | |||
| 2407 | return 0; | ||
| 2408 | } | ||
| 2409 | |||
| 2375 | #define SMB2_SYMLINK_STRUCT_SIZE \ | 2410 | #define SMB2_SYMLINK_STRUCT_SIZE \ |
| 2376 | (sizeof(struct smb2_err_rsp) - 1 + sizeof(struct smb2_symlink_err_rsp)) | 2411 | (sizeof(struct smb2_err_rsp) - 1 + sizeof(struct smb2_symlink_err_rsp)) |
| 2377 | 2412 | ||
| @@ -2401,11 +2436,13 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, | |||
| 2401 | struct kvec close_iov[1]; | 2436 | struct kvec close_iov[1]; |
| 2402 | struct smb2_create_rsp *create_rsp; | 2437 | struct smb2_create_rsp *create_rsp; |
| 2403 | struct smb2_ioctl_rsp *ioctl_rsp; | 2438 | struct smb2_ioctl_rsp *ioctl_rsp; |
| 2404 | char *ioctl_buf; | 2439 | struct reparse_data_buffer *reparse_buf; |
| 2405 | u32 plen; | 2440 | u32 plen; |
| 2406 | 2441 | ||
| 2407 | cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); | 2442 | cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); |
| 2408 | 2443 | ||
| 2444 | *target_path = NULL; | ||
| 2445 | |||
| 2409 | if (smb3_encryption_required(tcon)) | 2446 | if (smb3_encryption_required(tcon)) |
| 2410 | flags |= CIFS_TRANSFORM_REQ; | 2447 | flags |= CIFS_TRANSFORM_REQ; |
| 2411 | 2448 | ||
| @@ -2483,17 +2520,36 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, | |||
| 2483 | if ((rc == 0) && (is_reparse_point)) { | 2520 | if ((rc == 0) && (is_reparse_point)) { |
| 2484 | /* See MS-FSCC 2.3.23 */ | 2521 | /* See MS-FSCC 2.3.23 */ |
| 2485 | 2522 | ||
| 2486 | ioctl_buf = (char *)ioctl_rsp + le32_to_cpu(ioctl_rsp->OutputOffset); | 2523 | reparse_buf = (struct reparse_data_buffer *) |
| 2524 | ((char *)ioctl_rsp + | ||
| 2525 | le32_to_cpu(ioctl_rsp->OutputOffset)); | ||
| 2487 | plen = le32_to_cpu(ioctl_rsp->OutputCount); | 2526 | plen = le32_to_cpu(ioctl_rsp->OutputCount); |
| 2488 | 2527 | ||
| 2489 | if (plen + le32_to_cpu(ioctl_rsp->OutputOffset) > | 2528 | if (plen + le32_to_cpu(ioctl_rsp->OutputOffset) > |
| 2490 | rsp_iov[1].iov_len) { | 2529 | rsp_iov[1].iov_len) { |
| 2491 | cifs_dbg(VFS, "srv returned invalid ioctl length: %d\n", plen); | 2530 | cifs_dbg(VFS, "srv returned invalid ioctl len: %d\n", |
| 2531 | plen); | ||
| 2532 | rc = -EIO; | ||
| 2533 | goto querty_exit; | ||
| 2534 | } | ||
| 2535 | |||
| 2536 | if (plen < 8) { | ||
| 2537 | cifs_dbg(VFS, "reparse buffer is too small. Must be " | ||
| 2538 | "at least 8 bytes but was %d\n", plen); | ||
| 2539 | rc = -EIO; | ||
| 2540 | goto querty_exit; | ||
| 2541 | } | ||
| 2542 | |||
| 2543 | if (plen < le16_to_cpu(reparse_buf->ReparseDataLength) + 8) { | ||
| 2544 | cifs_dbg(VFS, "srv returned invalid reparse buf " | ||
| 2545 | "length: %d\n", plen); | ||
| 2492 | rc = -EIO; | 2546 | rc = -EIO; |
| 2493 | goto querty_exit; | 2547 | goto querty_exit; |
| 2494 | } | 2548 | } |
| 2495 | 2549 | ||
| 2496 | /* Do stuff with ioctl_buf/plen */ | 2550 | rc = parse_reparse_symlink( |
| 2551 | (struct reparse_symlink_data_buffer *)reparse_buf, | ||
| 2552 | plen, target_path, cifs_sb); | ||
| 2497 | goto querty_exit; | 2553 | goto querty_exit; |
| 2498 | } | 2554 | } |
| 2499 | 2555 | ||
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index c7d5813bebd8..858353d20c39 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h | |||
| @@ -914,7 +914,19 @@ struct reparse_mount_point_data_buffer { | |||
| 914 | __u8 PathBuffer[0]; /* Variable Length */ | 914 | __u8 PathBuffer[0]; /* Variable Length */ |
| 915 | } __packed; | 915 | } __packed; |
| 916 | 916 | ||
| 917 | /* See MS-FSCC 2.1.2.4 and cifspdu.h for struct reparse_symlink_data */ | 917 | #define SYMLINK_FLAG_RELATIVE 0x00000001 |
| 918 | |||
| 919 | struct reparse_symlink_data_buffer { | ||
| 920 | __le32 ReparseTag; | ||
| 921 | __le16 ReparseDataLength; | ||
| 922 | __u16 Reserved; | ||
| 923 | __le16 SubstituteNameOffset; | ||
| 924 | __le16 SubstituteNameLength; | ||
| 925 | __le16 PrintNameOffset; | ||
| 926 | __le16 PrintNameLength; | ||
| 927 | __le32 Flags; | ||
| 928 | __u8 PathBuffer[0]; /* Variable Length */ | ||
| 929 | } __packed; | ||
| 918 | 930 | ||
| 919 | /* See MS-FSCC 2.1.2.6 and cifspdu.h for struct reparse_posix_data */ | 931 | /* See MS-FSCC 2.1.2.6 and cifspdu.h for struct reparse_posix_data */ |
| 920 | 932 | ||
