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:
committed by
Karolin Seeger
parent
6936d3e2f2
commit
2711b6600e
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user