1
0
mirror of https://github.com/samba-team/samba.git synced 2025-12-12 12:23:50 +03:00

CVE-2018-10858: libsmb: Harden smbc_readdir_internal() against returns from malicious servers.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13453

CVE-2018-10858: Insufficient input validation on client directory
		listing in libsmbclient.

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
This commit is contained in:
Jeremy Allison
2018-06-15 15:08:17 -07:00
committed by Karolin Seeger
parent 6936d3e2f2
commit 2711b6600e
2 changed files with 51 additions and 8 deletions

View File

@@ -930,27 +930,47 @@ SMBC_closedir_ctx(SMBCCTX *context,
} }
static void static int
smbc_readdir_internal(SMBCCTX * context, smbc_readdir_internal(SMBCCTX * context,
struct smbc_dirent *dest, struct smbc_dirent *dest,
struct smbc_dirent *src, struct smbc_dirent *src,
int max_namebuf_len) int max_namebuf_len)
{ {
if (smbc_getOptionUrlEncodeReaddirEntries(context)) { if (smbc_getOptionUrlEncodeReaddirEntries(context)) {
int remaining_len;
/* url-encode the name. get back remaining buffer space */ /* url-encode the name. get back remaining buffer space */
max_namebuf_len = remaining_len =
smbc_urlencode(dest->name, src->name, max_namebuf_len); smbc_urlencode(dest->name, src->name, max_namebuf_len);
/* -1 means no null termination. */
if (remaining_len < 0) {
return -1;
}
/* We now know the name length */ /* We now know the name length */
dest->namelen = strlen(dest->name); dest->namelen = strlen(dest->name);
if (dest->namelen + 1 < 1) {
/* Integer wrap. */
return -1;
}
if (dest->namelen + 1 >= max_namebuf_len) {
/* Out of space for comment. */
return -1;
}
/* Save the pointer to the beginning of the comment */ /* Save the pointer to the beginning of the comment */
dest->comment = dest->name + dest->namelen + 1; dest->comment = dest->name + dest->namelen + 1;
if (remaining_len < 1) {
/* No room for comment null termination. */
return -1;
}
/* Copy the comment */ /* Copy the comment */
strncpy(dest->comment, src->comment, max_namebuf_len - 1); strlcpy(dest->comment, src->comment, remaining_len);
dest->comment[max_namebuf_len - 1] = '\0';
/* Save other fields */ /* Save other fields */
dest->smbc_type = src->smbc_type; dest->smbc_type = src->smbc_type;
@@ -960,10 +980,21 @@ smbc_readdir_internal(SMBCCTX * context,
} else { } else {
/* No encoding. Just copy the entry as is. */ /* No encoding. Just copy the entry as is. */
if (src->dirlen > max_namebuf_len) {
return -1;
}
memcpy(dest, src, src->dirlen); memcpy(dest, src, src->dirlen);
if (src->namelen + 1 < 1) {
/* Integer wrap */
return -1;
}
if (src->namelen + 1 >= max_namebuf_len) {
/* Comment off the end. */
return -1;
}
dest->comment = (char *)(&dest->name + src->namelen + 1); dest->comment = (char *)(&dest->name + src->namelen + 1);
} }
return 0;
} }
/* /*
@@ -975,6 +1006,7 @@ SMBC_readdir_ctx(SMBCCTX *context,
SMBCFILE *dir) SMBCFILE *dir)
{ {
int maxlen; int maxlen;
int ret;
struct smbc_dirent *dirp, *dirent; struct smbc_dirent *dirp, *dirent;
TALLOC_CTX *frame = talloc_stackframe(); TALLOC_CTX *frame = talloc_stackframe();
@@ -1024,7 +1056,12 @@ SMBC_readdir_ctx(SMBCCTX *context,
dirp = &context->internal->dirent; dirp = &context->internal->dirent;
maxlen = sizeof(context->internal->_dirent_name); maxlen = sizeof(context->internal->_dirent_name);
smbc_readdir_internal(context, dirp, dirent, maxlen); ret = smbc_readdir_internal(context, dirp, dirent, maxlen);
if (ret == -1) {
errno = EINVAL;
TALLOC_FREE(frame);
return NULL;
}
dir->dir_next = dir->dir_next->next; dir->dir_next = dir->dir_next->next;
@@ -1082,6 +1119,7 @@ SMBC_getdents_ctx(SMBCCTX *context,
*/ */
while ((dirlist = dir->dir_next)) { while ((dirlist = dir->dir_next)) {
int ret;
struct smbc_dirent *dirent; struct smbc_dirent *dirent;
struct smbc_dirent *currentEntry = (struct smbc_dirent *)ndir; struct smbc_dirent *currentEntry = (struct smbc_dirent *)ndir;
@@ -1096,8 +1134,13 @@ SMBC_getdents_ctx(SMBCCTX *context,
/* Do urlencoding of next entry, if so selected */ /* Do urlencoding of next entry, if so selected */
dirent = &context->internal->dirent; dirent = &context->internal->dirent;
maxlen = sizeof(context->internal->_dirent_name); maxlen = sizeof(context->internal->_dirent_name);
smbc_readdir_internal(context, dirent, ret = smbc_readdir_internal(context, dirent,
dirlist->dirent, maxlen); dirlist->dirent, maxlen);
if (ret == -1) {
errno = EINVAL;
TALLOC_FREE(frame);
return -1;
}
reqd = dirent->dirlen; reqd = dirent->dirlen;

View File

@@ -173,7 +173,7 @@ smbc_urlencode(char *dest,
} }
} }
if (max_dest_len == 0) { if (max_dest_len <= 0) {
/* Ensure we return -1 if no null termination. */ /* Ensure we return -1 if no null termination. */
return -1; return -1;
} }