diff options
author | Pavel Shilovsky <pshilovsky@samba.org> | 2016-07-24 03:37:38 -0400 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2016-07-27 23:55:56 -0400 |
commit | 7893242e2465aea6f2cbc2639da8fa5ce96e8cc2 (patch) | |
tree | 1cab64729128945784e3e72ac5796a1671187eb7 | |
parent | a6b5058fafdf508904bbf16c29b24042cef3c496 (diff) |
CIFS: Fix a possible invalid memory access in smb2_query_symlink()
During following a symbolic link we received err_buf from SMB2_open().
While the validity of SMB2 error response is checked previously
in smb2_check_message() a symbolic link payload is not checked at all.
Fix it by adding such checks.
Cc: Dan Carpenter <dan.carpenter@oracle.com>
CC: Stable <stable@vger.kernel.org>
Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org>
Signed-off-by: Steve French <smfrench@gmail.com>
-rw-r--r-- | fs/cifs/smb2ops.c | 30 |
1 files changed, 29 insertions, 1 deletions
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 527d1ac8583b..d203c0329626 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
@@ -1044,6 +1044,9 @@ smb2_new_lease_key(struct cifs_fid *fid) | |||
1044 | get_random_bytes(fid->lease_key, SMB2_LEASE_KEY_SIZE); | 1044 | get_random_bytes(fid->lease_key, SMB2_LEASE_KEY_SIZE); |
1045 | } | 1045 | } |
1046 | 1046 | ||
1047 | #define SMB2_SYMLINK_STRUCT_SIZE \ | ||
1048 | (sizeof(struct smb2_err_rsp) - 1 + sizeof(struct smb2_symlink_err_rsp)) | ||
1049 | |||
1047 | static int | 1050 | static int |
1048 | smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, | 1051 | smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, |
1049 | const char *full_path, char **target_path, | 1052 | const char *full_path, char **target_path, |
@@ -1056,7 +1059,10 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, | |||
1056 | struct cifs_fid fid; | 1059 | struct cifs_fid fid; |
1057 | struct smb2_err_rsp *err_buf = NULL; | 1060 | struct smb2_err_rsp *err_buf = NULL; |
1058 | struct smb2_symlink_err_rsp *symlink; | 1061 | struct smb2_symlink_err_rsp *symlink; |
1059 | unsigned int sub_len, sub_offset; | 1062 | unsigned int sub_len; |
1063 | unsigned int sub_offset; | ||
1064 | unsigned int print_len; | ||
1065 | unsigned int print_offset; | ||
1060 | 1066 | ||
1061 | cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); | 1067 | cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); |
1062 | 1068 | ||
@@ -1077,11 +1083,33 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, | |||
1077 | kfree(utf16_path); | 1083 | kfree(utf16_path); |
1078 | return -ENOENT; | 1084 | return -ENOENT; |
1079 | } | 1085 | } |
1086 | |||
1087 | if (le32_to_cpu(err_buf->ByteCount) < sizeof(struct smb2_symlink_err_rsp) || | ||
1088 | get_rfc1002_length(err_buf) + 4 < SMB2_SYMLINK_STRUCT_SIZE) { | ||
1089 | kfree(utf16_path); | ||
1090 | return -ENOENT; | ||
1091 | } | ||
1092 | |||
1080 | /* open must fail on symlink - reset rc */ | 1093 | /* open must fail on symlink - reset rc */ |
1081 | rc = 0; | 1094 | rc = 0; |
1082 | symlink = (struct smb2_symlink_err_rsp *)err_buf->ErrorData; | 1095 | symlink = (struct smb2_symlink_err_rsp *)err_buf->ErrorData; |
1083 | sub_len = le16_to_cpu(symlink->SubstituteNameLength); | 1096 | sub_len = le16_to_cpu(symlink->SubstituteNameLength); |
1084 | sub_offset = le16_to_cpu(symlink->SubstituteNameOffset); | 1097 | sub_offset = le16_to_cpu(symlink->SubstituteNameOffset); |
1098 | print_len = le16_to_cpu(symlink->PrintNameLength); | ||
1099 | print_offset = le16_to_cpu(symlink->PrintNameOffset); | ||
1100 | |||
1101 | if (get_rfc1002_length(err_buf) + 4 < | ||
1102 | SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) { | ||
1103 | kfree(utf16_path); | ||
1104 | return -ENOENT; | ||
1105 | } | ||
1106 | |||
1107 | if (get_rfc1002_length(err_buf) + 4 < | ||
1108 | SMB2_SYMLINK_STRUCT_SIZE + print_offset + print_len) { | ||
1109 | kfree(utf16_path); | ||
1110 | return -ENOENT; | ||
1111 | } | ||
1112 | |||
1085 | *target_path = cifs_strndup_from_utf16( | 1113 | *target_path = cifs_strndup_from_utf16( |
1086 | (char *)symlink->PathBuffer + sub_offset, | 1114 | (char *)symlink->PathBuffer + sub_offset, |
1087 | sub_len, true, cifs_sb->local_nls); | 1115 | sub_len, true, cifs_sb->local_nls); |