1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
Description: Fix buffer overflows that could lead to denial of service or code execution (CVE-2012-4561)
Origin: backport, http://git.libssh.org/projects/libssh.git/commit/?h=v0-5&id=8489521c0d7a9d1336b23a4a64e5df2d0f3ba57a
Origin: backport, http://git.libssh.org/projects/libssh.git/commit/?h=v0-5&id=db81310d719878cc04b23e4033fbe19fa0b1f8a3
Origin: backport, http://git.libssh.org/projects/libssh.git/commit/?h=v0-5&id=1699adfa036ffc66c62fdbb784610445cbebfc6e
Origin: backport, http://git.libssh.org/projects/libssh.git/commit/?h=v0-5&id=e3d9501b31a11b427afe1cc1cba5208adc2c3c39
--- a/libssh/buffer.c
+++ b/libssh/buffer.c
@@ -21,6 +21,7 @@
* MA 02111-1307, USA.
*/
+#include <limits.h>
#include <stdlib.h>
#include <string.h>
@@ -99,12 +100,17 @@ void buffer_free(struct ssh_buffer_struc
SAFE_FREE(buffer);
}
-static int realloc_buffer(struct ssh_buffer_struct *buffer, int needed) {
- int smallest = 1;
- char *new = NULL;
+static int realloc_buffer(struct ssh_buffer_struct *buffer, size_t needed) {
+ size_t smallest = 1;
+ char *new;
+
buffer_verify(buffer);
+
/* Find the smallest power of two which is greater or equal to needed */
while(smallest < needed) {
+ if (smallest == 0) {
+ return -1;
+ }
smallest <<= 1;
}
needed = smallest;
@@ -145,6 +151,10 @@ int buffer_reinit(struct ssh_buffer_stru
*/
int buffer_add_data(struct ssh_buffer_struct *buffer, const void *data, uint32_t len) {
buffer_verify(buffer);
+
+ if (buffer->used + len < len)
+ return -1;
+
if (buffer->allocated < (buffer->used + len)) {
if (realloc_buffer(buffer, buffer->used + len) < 0) {
return -1;
@@ -240,6 +250,8 @@ int buffer_add_u8(struct ssh_buffer_stru
int buffer_prepend_data(struct ssh_buffer_struct *buffer, const void *data,
uint32_t len) {
buffer_verify(buffer);
+ if (buffer->used + len < len)
+ return -1;
if (buffer->allocated < (buffer->used + len)) {
if (realloc_buffer(buffer, buffer->used + len) < 0) {
return -1;
@@ -318,7 +330,7 @@ uint32_t buffer_get_rest_len(struct ssh_
*/
uint32_t buffer_pass_bytes(struct ssh_buffer_struct *buffer, uint32_t len){
buffer_verify(buffer);
- if(buffer->used < buffer->pos+len)
+ if (buffer->pos + len < len || buffer->used < buffer->pos + len)
return 0;
buffer->pos+=len;
/* if the buffer is empty after having passed the whole bytes into it, we can clean it */
@@ -338,8 +350,11 @@ uint32_t buffer_pass_bytes(struct ssh_bu
*/
uint32_t buffer_pass_bytes_end(struct ssh_buffer_struct *buffer, uint32_t len){
buffer_verify(buffer);
- if(buffer->used < buffer->pos + len)
- return 0;
+
+ if (buffer->used < len) {
+ return 0;
+ }
+
buffer->used-=len;
buffer_verify(buffer);
return len;
@@ -412,7 +427,7 @@ struct ssh_string_struct *buffer_get_ssh
}
hostlen = ntohl(stringlen);
/* 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 */
}
str = string_new(hostlen);
@@ -445,7 +460,7 @@ struct ssh_string_struct *buffer_get_mpi
}
bits = ntohs(bits);
len = (bits + 7) / 8;
- if ((buffer->pos + len) > buffer->used) {
+ if (buffer->pos + len < len || buffer->pos + len > buffer->used) {
return NULL;
}
str = string_new(len);
--- a/libssh/dh.c
+++ b/libssh/dh.c
@@ -44,6 +44,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
#ifndef _WIN32
#include <arpa/inet.h>
@@ -188,6 +189,9 @@ char *ssh_get_hexa(const unsigned char *
char *hexa = NULL;
size_t i;
+ if (len > (UINT_MAX - 1) / 3)
+ return NULL;
+
hexa = malloc(len * 3 + 1);
if (hexa == NULL) {
return NULL;
--- a/libssh/string.c
+++ b/libssh/string.c
@@ -21,6 +21,7 @@
* MA 02111-1307, USA.
*/
+#include <limits.h>
#include <stdlib.h>
#include <string.h>
@@ -44,7 +45,11 @@
struct ssh_string_struct *string_new(size_t size) {
struct ssh_string_struct *str = NULL;
- str = malloc(size + 4);
+ if (size > UINT_MAX - sizeof(struct ssh_string_struct)) {
+ return NULL;
+ }
+
+ str = malloc(sizeof(struct ssh_string_struct) + size);
if (str == NULL) {
return NULL;
}
@@ -115,14 +120,24 @@ size_t string_len(struct ssh_string_stru
* the output string may not be readable with regular libc functions.
*/
char *string_to_char(struct ssh_string_struct *s) {
- size_t len = ntohl(s->size) + 1;
- char *new = malloc(len);
+ size_t len;
+ char *new;
+ if (s == NULL || s->string == NULL) {
+ return NULL;
+ }
+ len = string_len(s);
+ if (len + 1 < len) {
+ return NULL;
+ }
+
+ new = malloc(len + 1);
if (new == NULL) {
return NULL;
}
- memcpy(new, s->string, len - 1);
- new[len - 1] = '\0';
+ memcpy(new, s->string, len);
+ new[len] = '\0';
+
return new;
}
|