Mercurial > dropbear
annotate dbmalloc.c @ 1788:1fc0012b9c38
Fix handling of replies to global requests (#112)
The current code assumes that all global requests want / need a reply.
This isn't always true and the request itself indicates if it wants a
reply or not.
It causes a specific problem with [email protected] messages.
These are sent by OpenSSH after authentication to inform the client of
potential other host keys for the host. This can be used to add a new
type of host key or to rotate host keys.
The initial information message from the server is sent as a global
request, but with want_reply set to false. This means that the server
doesn't expect an answer to this message. Instead the client needs to
send a prove request as a reply if it wants to receive proof of
ownership for the host keys.
The bug doesn't cause any current problems with due to how OpenSSH
treats receiving the failure message. It instead treats it as a
keepalive message and further ignores it.
Arguably this is a protocol violation though of Dropbear and it is only
accidental that it doesn't cause a problem with OpenSSH.
The bug was found when adding host keys support to libssh, which is more
strict protocol wise and treats the unexpected failure message an error,
also see https://gitlab.com/libssh/libssh-mirror/-/merge_requests/145
for more information.
The fix here is to honor the want_reply flag in the global request and
to only send a reply if the other side expects a reply.
author | Dirkjan Bussink <d.bussink@gmail.com> |
---|---|
date | Thu, 10 Dec 2020 16:13:13 +0100 |
parents | 1051e4eea25a |
children |
rev | line source |
---|---|
1361 | 1 #include "dbmalloc.h" |
2 #include "dbutil.h" | |
3 | |
1569
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
4 |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
5 void * m_calloc(size_t nmemb, size_t size) { |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
6 if (SIZE_T_MAX / nmemb < size) { |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
7 dropbear_exit("m_calloc failed"); |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
8 } |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
9 return m_malloc(nmemb*size); |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
10 } |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
11 |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
12 void * m_strdup(const char * str) { |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
13 char* ret; |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
14 unsigned int len; |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
15 len = strlen(str); |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
16 |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
17 ret = m_malloc(len+1); |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
18 if (ret == NULL) { |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
19 dropbear_exit("m_strdup failed"); |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
20 } |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
21 memcpy(ret, str, len+1); |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
22 return ret; |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
23 } |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
24 |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
25 #if !DROPBEAR_TRACKING_MALLOC |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
26 |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
27 /* Simple wrappers around malloc etc */ |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
28 void * m_malloc(size_t size) { |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
29 |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
30 void* ret; |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
31 |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
32 if (size == 0) { |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
33 dropbear_exit("m_malloc failed"); |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
34 } |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
35 ret = calloc(1, size); |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
36 if (ret == NULL) { |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
37 dropbear_exit("m_malloc failed"); |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
38 } |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
39 return ret; |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
40 |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
41 } |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
42 |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
43 void * m_realloc(void* ptr, size_t size) { |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
44 |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
45 void *ret; |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
46 |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
47 if (size == 0) { |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
48 dropbear_exit("m_realloc failed"); |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
49 } |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
50 ret = realloc(ptr, size); |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
51 if (ret == NULL) { |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
52 dropbear_exit("m_realloc failed"); |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
53 } |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
54 return ret; |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
55 } |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
56 |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
57 |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
58 #else |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
59 |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
60 /* For fuzzing */ |
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
61 |
1361 | 62 struct dbmalloc_header { |
63 unsigned int epoch; | |
1378 | 64 struct dbmalloc_header *prev; |
65 struct dbmalloc_header *next; | |
1361 | 66 }; |
67 | |
1378 | 68 static void put_alloc(struct dbmalloc_header *header); |
69 static void remove_alloc(struct dbmalloc_header *header); | |
70 | |
71 /* end of the linked list */ | |
72 static struct dbmalloc_header* staple; | |
1361 | 73 |
74 unsigned int current_epoch = 0; | |
75 | |
76 void m_malloc_set_epoch(unsigned int epoch) { | |
77 current_epoch = epoch; | |
78 } | |
79 | |
1378 | 80 void m_malloc_free_epoch(unsigned int epoch, int dofree) { |
81 struct dbmalloc_header* header; | |
82 struct dbmalloc_header* nextheader = NULL; | |
83 struct dbmalloc_header* oldstaple = staple; | |
84 staple = NULL; | |
85 /* free allocations from this epoch, create a new staple-anchored list from | |
86 the remainder */ | |
87 for (header = oldstaple; header; header = nextheader) | |
88 { | |
89 nextheader = header->next; | |
90 if (header->epoch == epoch) { | |
91 if (dofree) { | |
92 free(header); | |
1361 | 93 } |
1378 | 94 } else { |
95 header->prev = NULL; | |
96 header->next = NULL; | |
97 put_alloc(header); | |
1361 | 98 } |
99 } | |
100 } | |
101 | |
102 static void put_alloc(struct dbmalloc_header *header) { | |
1378 | 103 assert(header->next == NULL); |
104 assert(header->prev == NULL); | |
105 if (staple) { | |
106 staple->prev = header; | |
1361 | 107 } |
1378 | 108 header->next = staple; |
109 staple = header; | |
1361 | 110 } |
111 | |
112 static void remove_alloc(struct dbmalloc_header *header) { | |
1378 | 113 if (header->prev) { |
114 header->prev->next = header->next; | |
115 } | |
116 if (header->next) { | |
117 header->next->prev = header->prev; | |
118 } | |
119 if (staple == header) { | |
120 staple = header->next; | |
121 } | |
122 header->prev = NULL; | |
123 header->next = NULL; | |
1361 | 124 } |
125 | |
126 static struct dbmalloc_header* get_header(void* ptr) { | |
127 char* bptr = ptr; | |
128 return (struct dbmalloc_header*)&bptr[-sizeof(struct dbmalloc_header)]; | |
129 } | |
130 | |
131 void * m_malloc(size_t size) { | |
132 char* mem = NULL; | |
133 struct dbmalloc_header* header = NULL; | |
134 | |
135 if (size == 0 || size > 1e9) { | |
136 dropbear_exit("m_malloc failed"); | |
137 } | |
138 | |
139 size = size + sizeof(struct dbmalloc_header); | |
140 | |
141 mem = calloc(1, size); | |
142 if (mem == NULL) { | |
143 dropbear_exit("m_malloc failed"); | |
144 } | |
145 header = (struct dbmalloc_header*)mem; | |
146 put_alloc(header); | |
147 header->epoch = current_epoch; | |
148 return &mem[sizeof(struct dbmalloc_header)]; | |
149 } | |
150 | |
151 void * m_realloc(void* ptr, size_t size) { | |
152 char* mem = NULL; | |
153 struct dbmalloc_header* header = NULL; | |
154 if (size == 0 || size > 1e9) { | |
155 dropbear_exit("m_realloc failed"); | |
156 } | |
157 | |
158 header = get_header(ptr); | |
159 remove_alloc(header); | |
160 | |
161 size = size + sizeof(struct dbmalloc_header); | |
162 mem = realloc(header, size); | |
163 if (mem == NULL) { | |
164 dropbear_exit("m_realloc failed"); | |
165 } | |
166 | |
167 header = (struct dbmalloc_header*)mem; | |
168 put_alloc(header); | |
169 return &mem[sizeof(struct dbmalloc_header)]; | |
170 } | |
171 | |
172 void m_free_direct(void* ptr) { | |
173 struct dbmalloc_header* header = NULL; | |
174 if (!ptr) { | |
175 return; | |
176 } | |
177 header = get_header(ptr); | |
178 remove_alloc(header); | |
179 free(header); | |
180 } | |
181 | |
1569
c42e8ff42bd1
Only use malloc wrapper if fuzzing
Matt Johnston <matt@ucc.asn.au>
parents:
1378
diff
changeset
|
182 #endif /* DROPBEAR_TRACKING_MALLOC */ |
1692
1051e4eea25a
Update LibTomMath to 1.2.0 (#84)
Steffen Jaeckel <s@jaeckel.eu>
parents:
1569
diff
changeset
|
183 |
1051e4eea25a
Update LibTomMath to 1.2.0 (#84)
Steffen Jaeckel <s@jaeckel.eu>
parents:
1569
diff
changeset
|
184 void * m_realloc_ltm(void* ptr, size_t oldsize, size_t newsize) { |
1051e4eea25a
Update LibTomMath to 1.2.0 (#84)
Steffen Jaeckel <s@jaeckel.eu>
parents:
1569
diff
changeset
|
185 (void)oldsize; |
1051e4eea25a
Update LibTomMath to 1.2.0 (#84)
Steffen Jaeckel <s@jaeckel.eu>
parents:
1569
diff
changeset
|
186 return m_realloc(ptr, newsize); |
1051e4eea25a
Update LibTomMath to 1.2.0 (#84)
Steffen Jaeckel <s@jaeckel.eu>
parents:
1569
diff
changeset
|
187 } |
1051e4eea25a
Update LibTomMath to 1.2.0 (#84)
Steffen Jaeckel <s@jaeckel.eu>
parents:
1569
diff
changeset
|
188 |
1051e4eea25a
Update LibTomMath to 1.2.0 (#84)
Steffen Jaeckel <s@jaeckel.eu>
parents:
1569
diff
changeset
|
189 void m_free_ltm(void *mem, size_t size) { |
1051e4eea25a
Update LibTomMath to 1.2.0 (#84)
Steffen Jaeckel <s@jaeckel.eu>
parents:
1569
diff
changeset
|
190 (void)size; |
1051e4eea25a
Update LibTomMath to 1.2.0 (#84)
Steffen Jaeckel <s@jaeckel.eu>
parents:
1569
diff
changeset
|
191 m_free_direct(mem); |
1051e4eea25a
Update LibTomMath to 1.2.0 (#84)
Steffen Jaeckel <s@jaeckel.eu>
parents:
1569
diff
changeset
|
192 } |