CVE-2012-4562: Fix multiple integer overflows in buffer-related functions.

This commit is contained in:
Xi Wang
2011-11-28 04:42:54 -05:00
committed by Andreas Schneider
parent 8489521c0d
commit db81310d71

View File

@@ -21,6 +21,7 @@
* MA 02111-1307, USA. * MA 02111-1307, USA.
*/ */
#include <limits.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -181,6 +182,10 @@ int buffer_reinit(struct ssh_buffer_struct *buffer) {
*/ */
int buffer_add_data(struct ssh_buffer_struct *buffer, const void *data, uint32_t len) { int buffer_add_data(struct ssh_buffer_struct *buffer, const void *data, uint32_t len) {
buffer_verify(buffer); buffer_verify(buffer);
if (buffer->used + len < len)
return -1;
if (buffer->allocated < (buffer->used + len)) { if (buffer->allocated < (buffer->used + len)) {
if(buffer->pos > 0) if(buffer->pos > 0)
buffer_shift(buffer); buffer_shift(buffer);
@@ -319,6 +324,8 @@ int buffer_prepend_data(struct ssh_buffer_struct *buffer, const void *data,
return 0; return 0;
} }
/* pos isn't high enough */ /* pos isn't high enough */
if (buffer->used - buffer->pos + len < len)
return -1;
if (buffer->allocated < (buffer->used - buffer->pos + len)) { if (buffer->allocated < (buffer->used - buffer->pos + len)) {
if (realloc_buffer(buffer, buffer->used - buffer->pos + len) < 0) { if (realloc_buffer(buffer, buffer->used - buffer->pos + len) < 0) {
return -1; return -1;
@@ -430,7 +437,7 @@ uint32_t buffer_get_rest_len(struct ssh_buffer_struct *buffer){
*/ */
uint32_t buffer_pass_bytes(struct ssh_buffer_struct *buffer, uint32_t len){ uint32_t buffer_pass_bytes(struct ssh_buffer_struct *buffer, uint32_t len){
buffer_verify(buffer); buffer_verify(buffer);
if(buffer->used < buffer->pos+len) if (buffer->pos + len < len || buffer->used < buffer->pos + len)
return 0; return 0;
buffer->pos+=len; buffer->pos+=len;
/* if the buffer is empty after having passed the whole bytes into it, we can clean it */ /* if the buffer is empty after having passed the whole bytes into it, we can clean it */
@@ -455,8 +462,11 @@ uint32_t buffer_pass_bytes(struct ssh_buffer_struct *buffer, uint32_t len){
*/ */
uint32_t buffer_pass_bytes_end(struct ssh_buffer_struct *buffer, uint32_t len){ uint32_t buffer_pass_bytes_end(struct ssh_buffer_struct *buffer, uint32_t len){
buffer_verify(buffer); buffer_verify(buffer);
if(buffer->used < buffer->pos + len)
return 0; if (buffer->used < len) {
return 0;
}
buffer->used-=len; buffer->used-=len;
buffer_verify(buffer); buffer_verify(buffer);
return len; return len;
@@ -549,7 +559,7 @@ struct ssh_string_struct *buffer_get_ssh_string(struct ssh_buffer_struct *buffer
} }
hostlen = ntohl(stringlen); hostlen = ntohl(stringlen);
/* verify if there is enough space in buffer to get it */ /* verify if there is enough space in buffer to get it */
if ((buffer->pos + hostlen) > buffer->used) { if (buffer->pos + hostlen < hostlen || buffer->pos + hostlen > buffer->used) {
return NULL; /* it is indeed */ return NULL; /* it is indeed */
} }
str = ssh_string_new(hostlen); str = ssh_string_new(hostlen);
@@ -586,7 +596,7 @@ struct ssh_string_struct *buffer_get_mpint(struct ssh_buffer_struct *buffer) {
} }
bits = ntohs(bits); bits = ntohs(bits);
len = (bits + 7) / 8; len = (bits + 7) / 8;
if ((buffer->pos + len) > buffer->used) { if (buffer->pos + len < len || buffer->pos + len > buffer->used) {
return NULL; return NULL;
} }
str = ssh_string_new(len); str = ssh_string_new(len);