Skip to content

Commit f885cbb

Browse files
authored
Merge pull request #1598 from private-octopus/reset-race-condition
Verify processing of stream control frames after reset
2 parents faf73a2 + 81b9726 commit f885cbb

File tree

11 files changed

+505
-15
lines changed

11 files changed

+505
-15
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ else()
88
endif()
99

1010
project(picoquic
11-
VERSION 1.1.16.1
11+
VERSION 1.1.16.2
1212
DESCRIPTION "picoquic library"
1313
LANGUAGES C CXX)
1414

UnitTest1/unittest1.cpp

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ namespace UnitTest1
160160
Assert::AreEqual(ret, 0);
161161
}
162162

163-
TEST_METHOD(test_varints)
163+
TEST_METHOD(varints)
164164
{
165165
int ret = varint_test();
166166

@@ -1621,6 +1621,59 @@ namespace UnitTest1
16211621
Assert::AreEqual(ret, 0);
16221622
}
16231623

1624+
TEST_METHOD(reset_ack_max)
1625+
{
1626+
int ret = reset_ack_max_test();
1627+
1628+
Assert::AreEqual(ret, 0);
1629+
}
1630+
TEST_METHOD(reset_ack_reset)
1631+
{
1632+
int ret = reset_ack_reset_test();
1633+
1634+
Assert::AreEqual(ret, 0);
1635+
}
1636+
1637+
TEST_METHOD(reset_extra_max)
1638+
{
1639+
int ret = reset_extra_max_test();
1640+
1641+
Assert::AreEqual(ret, 0);
1642+
}
1643+
1644+
TEST_METHOD(reset_extra_reset)
1645+
{
1646+
int ret = reset_extra_reset_test();
1647+
1648+
Assert::AreEqual(ret, 0);
1649+
}
1650+
TEST_METHOD(reset_extra_stop)
1651+
{
1652+
int ret = reset_extra_stop_test();
1653+
1654+
Assert::AreEqual(ret, 0);
1655+
}
1656+
1657+
TEST_METHOD(reset_need_max)
1658+
{
1659+
int ret = reset_need_max_test();
1660+
1661+
Assert::AreEqual(ret, 0);
1662+
}
1663+
TEST_METHOD(reset_need_reset)
1664+
{
1665+
int ret = reset_need_reset_test();
1666+
1667+
Assert::AreEqual(ret, 0);
1668+
}
1669+
1670+
TEST_METHOD(reset_need_stop)
1671+
{
1672+
int ret = reset_need_stop_test();
1673+
1674+
Assert::AreEqual(ret, 0);
1675+
}
1676+
16241677
TEST_METHOD(ready_to_send)
16251678
{
16261679
int ret = ready_to_send_test();

picoquic/frames.c

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,15 @@ const uint8_t* picoquic_decode_stream_reset_frame(picoquic_cnx_t* cnx, const uin
267267
picoquic_connection_error(cnx, PICOQUIC_TRANSPORT_FRAME_FORMAT_ERROR,
268268
picoquic_frame_type_reset_stream);
269269
} else if ((stream = picoquic_find_or_create_stream(cnx, stream_id, 1)) == NULL) {
270-
bytes = NULL; // error already signaled
271-
270+
/* Not finding the stream is only an error if the stream
271+
* was expected to be present, or created on demand. If the
272+
* stream was already created and then deleted, there is no harm.
273+
* If the "return NULL" is in a normal scenario, the connection state
274+
* will remain "ready" or "almost ready"
275+
*/
276+
if (cnx->cnx_state > picoquic_state_ready) {
277+
bytes = NULL; /* error already signaled */
278+
}
272279
} else if ((stream->fin_received || stream->reset_received) && final_offset != stream->fin_offset) {
273280
picoquic_connection_error(cnx, PICOQUIC_TRANSPORT_FINAL_OFFSET_ERROR,
274281
picoquic_frame_type_reset_stream);
@@ -319,8 +326,8 @@ int picoquic_process_ack_of_reset_stream_frame(picoquic_cnx_t * cnx, const uint8
319326
ret = -1;
320327
} else {
321328
*consumed = bytes - byte_first;
322-
/* Find the stream */
323-
if ((stream = picoquic_find_or_create_stream(cnx, stream_id, 0)) != NULL) {
329+
/* Find the stream, if it exists. If it was already deleted, do nothing. */
330+
if ((stream = picoquic_find_stream(cnx, stream_id)) != NULL) {
324331
/* mark reset as acked by peer */
325332
stream->reset_acked = 1;
326333
/* Delete stream if closed. */
@@ -347,7 +354,7 @@ int picoquic_check_reset_stream_needs_repeat(picoquic_cnx_t* cnx, const uint8_t*
347354
/* Internal error -- cannot parse the stored packet */
348355
ret = -1;
349356
}
350-
else if ((stream = picoquic_find_or_create_stream(cnx, stream_id, 0)) == NULL ||
357+
else if ((stream = picoquic_find_stream(cnx, stream_id)) == NULL ||
351358
stream->reset_acked) {
352359
*no_need_to_repeat = 1;
353360
}
@@ -837,6 +844,35 @@ const uint8_t* picoquic_skip_stop_sending_frame(const uint8_t* bytes, const uint
837844
}
838845

839846

847+
int picoquic_check_stop_sending_needs_repeat(picoquic_cnx_t* cnx, const uint8_t* bytes, size_t bytes_size, int* no_need_to_repeat)
848+
{
849+
uint64_t stream_id = 0;
850+
uint64_t error_code = 0;
851+
const uint8_t* bytes_max = bytes + bytes_size;
852+
picoquic_stream_head_t* stream;
853+
int ret = 0;
854+
855+
*no_need_to_repeat = 0;
856+
857+
if ((bytes = picoquic_frames_varint_decode(bytes+1, bytes_max, &stream_id)) == NULL ||
858+
(bytes = picoquic_frames_varint_decode(bytes, bytes_max, &error_code)) == NULL)
859+
{
860+
/* If the frame cannot be decoded, do not repeat it */
861+
*no_need_to_repeat = 1;
862+
}
863+
else if ((stream = picoquic_find_stream(cnx, stream_id)) == NULL) {
864+
/* If the stream is deleted, no need to repeat this frame. */
865+
*no_need_to_repeat = 1;
866+
}
867+
else if (stream->fin_received || stream->reset_received) {
868+
/* No point repeating if the stream is closed by the peer */
869+
*no_need_to_repeat = 1;
870+
}
871+
872+
return ret;
873+
}
874+
875+
840876
/*
841877
* STREAM frames implicitly create a stream and carry stream data.
842878
*/
@@ -3123,6 +3159,9 @@ int picoquic_check_frame_needs_repeat(picoquic_cnx_t* cnx, const uint8_t* bytes,
31233159
case picoquic_frame_type_reset_stream:
31243160
ret = picoquic_check_reset_stream_needs_repeat(cnx, bytes, bytes_max, no_need_to_repeat);
31253161
break;
3162+
case picoquic_frame_type_stop_sending:
3163+
ret = picoquic_check_stop_sending_needs_repeat(cnx, bytes, bytes_max, no_need_to_repeat);
3164+
break;
31263165
default: {
31273166
uint64_t frame_id64;
31283167
*no_need_to_repeat = 0;

picoquic/picoquic.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
extern "C" {
4141
#endif
4242

43-
#define PICOQUIC_VERSION "1.1.16.1"
43+
#define PICOQUIC_VERSION "1.1.16.2"
4444
#define PICOQUIC_ERROR_CLASS 0x400
4545
#define PICOQUIC_ERROR_DUPLICATE (PICOQUIC_ERROR_CLASS + 1)
4646
#define PICOQUIC_ERROR_AEAD_CHECK (PICOQUIC_ERROR_CLASS + 3)

picoquic/quicctx.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ static picosplay_node_t* picoquic_registered_token_create(void* value)
539539

540540
static void* picoquic_registered_token_value(picosplay_node_t* node)
541541
{
542-
return (void*)((char*)node - offsetof(struct st_picoquic_registered_token_t, registered_token_node));
542+
return (void*)((node == NULL)?NULL:((char*)node - offsetof(struct st_picoquic_registered_token_t, registered_token_node)));
543543
}
544544

545545
static void picoquic_registered_token_delete(void* tree, picosplay_node_t* node)

picoquic/tls_api.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ void picoquic_aes128_ecb_free(void* v_aesecb);
193193

194194
void picoquic_aes128_ecb_encrypt(void* v_aesecb, uint8_t* output, const uint8_t* input, size_t len);
195195

196+
void picoquic_tls_api_init();
196197
void picoquic_tls_api_unload();
197198
void picoquic_tls_api_reset(uint64_t init_flags);
198199

picoquic_t/picoquic_t.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,14 @@ static const picoquic_test_def_t test_table[] = {
273273
{ "error_reason", error_reason_test },
274274
{ "idle_server", idle_server_test },
275275
{ "idle_timeout", idle_timeout_test },
276+
{ "reset_ack_max", reset_ack_max_test },
277+
{ "reset_ack_reset", reset_ack_reset_test },
278+
{ "reset_extra_max", reset_extra_max_test },
279+
{ "reset_extra_reset", reset_extra_reset_test },
280+
{ "reset_extra_stop", reset_extra_stop_test },
281+
{ "reset_need_max", reset_need_max_test },
282+
{ "reset_need_reset", reset_need_reset_test },
283+
{ "reset_need_stop", reset_need_stop_test },
276284
{ "ready_to_send", ready_to_send_test },
277285
{ "ready_to_skip", ready_to_skip_test },
278286
{ "ready_to_zfin", ready_to_zfin_test },

picoquictest/cleartext_aead_test.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,8 +329,11 @@ int pn_ctr_test()
329329
uint8_t in_bytes[16];
330330
uint8_t out_bytes[16];
331331
uint8_t decoded[16];
332+
333+
picoquic_tls_api_init();
334+
332335
ptls_aead_algorithm_t* aead = (ptls_aead_algorithm_t*)picoquic_get_aes128gcm_v(0);
333-
ptls_cipher_context_t *pn_enc = ptls_cipher_new(aead->ctr_cipher, 1, key);
336+
ptls_cipher_context_t *pn_enc = (aead == NULL)?NULL:ptls_cipher_new(aead->ctr_cipher, 1, key);
334337

335338
if (pn_enc == NULL) {
336339
ret = -1;

0 commit comments

Comments
 (0)