26
26
<!-- Full pattern of correct answer -->
27
27
< script id ="correct0 " type ="plain/text ">
28
28
\s *
29
- if \s + \(
30
- ( 1 \+ 2 \+ 16 | 19 ) > s - > s3 - > rrec \. length \)
31
- \s + RETURN0
29
+ if \( ( NINETEEN > FULL_LENGTH | FULL_LENGTH < NINETEEN ) \)
30
+ RETURN0
32
31
\s *
33
32
</ script >
34
33
< script id ="correct1 " type ="plain/text ">
35
34
\s *
36
- if \s + \ ( ( 1 \ + 2 | 3 ) \ + payload \ + 16 > s - > s3 - > rrec \ . length \)
37
- \ s + RETURN0
35
+ if \( ( PAYLOAD_LENGTH > FULL_LENGTH | FULL_LENGTH < PAYLOAD_LENGTH ) \)
36
+ RETURN0
38
37
\s *
39
38
</ script >
40
- <!--
41
- \s* app \. use \( helmet \( \{
42
- contentSecurityPolicy: \{
43
- directives: \{
44
- "script-src": \[ "'self'" ,
45
- (["'`])https://example\.com\1 \] ,
46
- "style-src": \[ "'self'" \]
47
- \} ,
48
- \}
49
- \} \) \) ;
50
- -->
51
39
52
40
< script id ="info " type ="application/yaml ">
53
41
-- -
60
48
- absent : |
61
49
>
62
50
text : Need comparison "if ( ... > ....)"
51
+ - absent : s - > s3 - > rrec \. length
52
+ text : Need to compare a value with s - > s3 - > rrec . length
63
53
- absent : return
64
54
text : Need "return 0;" to skip attempts to send a too - long response .
65
55
definitions :
56
+ - term : NINETEEN
57
+ value : |
58
+ ( 1 \+ 2 \+ 16 | 19 )
59
+ - term : NINETEEN
60
+ value : |
61
+ ( NINETEEN | \( NINETEEN \) )
62
+ - term : PAYLOAD_LENGTH
63
+ value: ( 1 \+ 2 | 3 ) \+ payload \+ 16
64
+ - term : PAYLOAD_LENGTH
65
+ value: ( PAYLOAD_LENGTH | payload \+ NINETEEN | NINETEEN \+ payload )
66
+ - term : PAYLOAD_LENGTH
67
+ value : |
68
+ ( PAYLOAD_LENGTH | \( PAYLOAD_LENGTH \) )
66
69
- term : RETURN0
67
70
value : |
68
71
return \s + 0 ;
72
+ - term : FULL_LENGTH
73
+ value : |
74
+ s - > s3 - > rrec \. length
69
75
- term : RETURN0
70
76
value: |
71
77
( RETURN0 | \{ RETURN0 \} )
@@ -161,23 +167,32 @@ <h2>Task</h2>
161
167
< p >
162
168
< h2 > Background</ h2 >
163
169
< p >
164
- In almost all programming languages, the default response a program
165
- attempts to read or write outside
166
- of a buffer is either an attempt to resize the buffer or
167
- an error of some kind (e.g., raising an exception).
170
+ In almost all programming languages, if program
171
+ attempts to read or write outside of a buffer,
172
+ the default is always either an attempt to resize the buffer or
173
+ an error of some kind (e.g., by raising an exception).
168
174
That's because it's extremely easy to accidentally attempt to read
169
175
or write outside of a buffer.
170
176
< p >
171
- However, C and the built-in arrays of C++ are different.
172
- In C and C++, attempting to read or write outside a buffer is
173
- < i > undefined behavior</ i > and < i > anything</ i > is allowed to happen
177
+ However, C and C++ are different.
178
+ C++ has evolved to become somewhat safer (e.g., through smart pointers),
179
+ In C and C++, attempting to do actions like read or write outside a buffer is
180
+ in many cases
181
+ < i > undefined behavior</ i > , and when undefined behavior occurs,
182
+ < i > anything</ i > is allowed to happen
174
183
without any kind of protection.
175
184
In practice, what often happens is a read or write (respectively) of
176
185
other data.
186
+ There are
187
+ < a href ="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2771r0.html "
188
+ > proposals to improve C++ memory safety</ a > ,
189
+ but currently many C++ built-in constructs (like arrays) are not memory safe,
190
+ so we will treat the two languages together here.
177
191
< p >
178
192
The 2014 revelation of the Heartbleed vulnerability
179
193
(CVE-2014-0160) is an example of a buffer overread vulnerability.
180
194
Heartbleed was a vulnerability in OpenSSL, a widely-used toolkit
195
+ written in C
181
196
that implements the cryptographic protocol Secure Sockets Layer
182
197
(SSL) and its successor the Transport Layer Security (TLS).
183
198
Heartbleed affected a huge number of popular websites, including
@@ -196,31 +211,35 @@ <h2>Task Information</h2>
196
211
At this point in the code, the construct
197
212
< tt > s-> s3-> rrec.length</ tt >
198
213
indicates how many bytes are available.
199
- Modify the code below in two places.
214
+ If we don't check for the maximum sizes, we could easily cause
215
+ reading beyond a buffer.
216
+ Modify the code below in two places to fix this.
200
217
< p >
201
218
First, modify the code so that
202
219
if the minimum length of a response < tt > (1 + 2 + 16)</ tt > is more than
203
220
the length claimed by
204
221
< tt > s-> s3-> rrec.length</ tt > ,
205
- return return 0 without sending a heartbeat,
222
+ and return 0 without sending a heartbeat,
206
223
This will prevent trying to create a heartbeat when there's not enough
207
- room to create one .
224
+ room to create a heartbeat at all .
208
225
< p >
209
226
Second, modify the code so that
210
227
if the minimum length of a response with a payload
211
228
< tt > (1 + 2 + payload + 16</ tt >
212
229
is more than the total length for a response given in
213
230
< tt > s-> s3-> rrec.length</ tt > then again
214
- return return 0 without sending a heartbeat,
231
+ return 0 without sending a heartbeat,
215
232
< p >
216
233
This will prevent trying to create a heartbeat when there's not enough
217
- room to create one.
234
+ room to create one and there was a payload to return as a heartbeat .
218
235
< p >
219
236
Note that this is not terribly difficult to fix.
237
+ The code we add is short.
220
238
The problem is that reading and writing buffers is extremely common,
221
239
but by default such accesses are unsafe in C and C++.
222
240
In practice it is difficult to < i > always</ i > check all ranges
223
- in all possible cases.
241
+ in all possible cases, which is why memory safety vulnerabilities
242
+ are so common in programs written in C or C++.
224
243
<!--
225
244
if (1 + 2 + 16 > s->s3->rrec.length)
226
245
return 0; /* silently discard */
0 commit comments