Skip to content
This repository was archived by the owner on Jul 22, 2023. It is now read-only.

Commit 96018ab

Browse files
authored
calloc limits (#119)
Add overflow protection to __iotc_calloc calls, as well as unit tests for the function.
1 parent 7264584 commit 96018ab

File tree

4 files changed

+209
-4
lines changed

4 files changed

+209
-4
lines changed

make/mt-os/mt-freertos-linux.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
CC ?= gcc
1717
AR ?= ar
1818

19-
IOTC_COMMON_COMPILER_FLAGS += -fPIC
19+
IOTC_COMMON_COMPILER_FLAGS += -fPIC -DIOTC_TARGET_FREERTOS=1
2020
IOTC_LIB_FLAGS += $(IOTC_TLS_LIBFLAGS) -lcrypto -lpthread
2121

2222
IOTC_FREERTOS_DIR_PATH = $(LIBIOTC)/third_party/FreeRTOSv10.1.1/FreeRTOS

src/libiotc/memory/iotc_allocator.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright 2018-2020 Google LLC
1+
/* Copyright 2018-2021 Google LLC
22
*
33
* This is part of the Google Cloud IoT Device SDK for Embedded C.
44
* It is licensed under the BSD 3-Clause license; you may not use this file
@@ -15,20 +15,26 @@
1515
*/
1616
#include "iotc_allocator.h"
1717
#include "iotc_bsp_mem.h"
18+
#include <stdint.h>
1819

1920
extern void* memset(void* ptr, int value, size_t num);
2021

2122
void* __iotc_alloc(size_t byte_count) { return iotc_bsp_mem_alloc(byte_count); }
2223

2324
void* __iotc_calloc(size_t num, size_t byte_count) {
2425
const size_t size_to_allocate = num * byte_count;
26+
27+
/* Prevent overflow. */
28+
if (size_to_allocate == 0 || num > SIZE_MAX / byte_count) {
29+
return NULL;
30+
}
31+
2532
void* ret = iotc_bsp_mem_alloc(size_to_allocate);
2633

2734
/* It's unspecified if memset works with NULL pointer. */
2835
if (NULL != ret) {
2936
memset(ret, 0, size_to_allocate);
3037
}
31-
3238
return ret;
3339
}
3440

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
/* Copyright 2021 Google LLC
2+
*
3+
* This is part of the Google Cloud IoT Device SDK for Embedded C.
4+
* It is licensed under the BSD 3-Clause license; you may not use this file
5+
* except in compliance with the License.
6+
*
7+
* You may obtain a copy of the License at:
8+
* https://opensource.org/licenses/BSD-3-Clause
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "iotc_macros.h"
18+
#include "iotc_tt_testcase_management.h"
19+
#include "tinytest.h"
20+
#include "tinytest_macros.h"
21+
22+
#include "iotc.h"
23+
#include "iotc_allocator.h"
24+
25+
#include <errno.h>
26+
#include <stdio.h>
27+
#include <stdlib.h>
28+
#include <string.h>
29+
#include <time.h>
30+
31+
#ifndef IOTC_TT_TESTCASE_ENUMERATION__SECONDPREPROCESSORRUN
32+
33+
#endif // IOTC_TT_TESTCASE_ENUMERATION__SECONDPREPROCESSORRUN
34+
35+
IOTC_TT_TESTGROUP_BEGIN(utest_memory_calloc)
36+
37+
/* Happy cases. */
38+
IOTC_TT_TESTCASE(
39+
utest__iotc_memory_calloc__num_1__size_8,
40+
{
41+
void* ptr = __iotc_calloc( /*num=*/1, /*size=*/8);
42+
tt_want_ptr_op(NULL, !=, ptr);
43+
__iotc_free(ptr);
44+
})
45+
46+
IOTC_TT_TESTCASE(
47+
utest__iotc_memory_calloc___num_255__size_55,
48+
{
49+
void* ptr = __iotc_calloc( /*num=*/255, /*size=*/55);
50+
tt_want_ptr_op(NULL, !=, ptr);
51+
__iotc_free(ptr);
52+
})
53+
54+
IOTC_TT_TESTCASE(
55+
utest__iotc_memory_calloc___num_1000000__size_88,
56+
{
57+
void* ptr = __iotc_calloc( /*num=*/1000000, /*size=*/88);
58+
tt_want_ptr_op(NULL, !=, ptr);
59+
__iotc_free(ptr);
60+
})
61+
62+
/* Edge cases. */
63+
IOTC_TT_TESTCASE(
64+
utest__iotc_memory_calloc__num_0__size_8,
65+
{
66+
void* ptr = __iotc_calloc( /*num=*/0, /*size=*/8);
67+
tt_want_ptr_op(NULL, ==, ptr);
68+
__iotc_free(ptr);
69+
})
70+
71+
IOTC_TT_TESTCASE(
72+
utest__iotc_memory_calloc__num_1__size_0,
73+
{
74+
void* ptr = __iotc_calloc( /*num=*/1, /*size=*/0);
75+
tt_want_ptr_op(NULL, ==, ptr);
76+
__iotc_free(ptr);
77+
})
78+
79+
IOTC_TT_TESTCASE(
80+
utest__iotc_memory_calloc__num_0__size_0,
81+
{
82+
void* ptr = __iotc_calloc( /*num=*/0, /*size=*/0);
83+
tt_want_ptr_op(NULL, ==, ptr);
84+
__iotc_free(ptr);
85+
})
86+
87+
IOTC_TT_TESTCASE(
88+
utest__iotc_memory_calloc__num_max__size_0,
89+
{
90+
void* ptr = __iotc_calloc( /*num=*/SIZE_MAX, /*size=*/0);
91+
tt_want_ptr_op(NULL, ==, ptr);
92+
__iotc_free(ptr);
93+
})
94+
95+
IOTC_TT_TESTCASE(
96+
utest__iotc_memory_calloc__num_0__size_max,
97+
{
98+
void* ptr = __iotc_calloc( /*num=*/0, /*size=*/SIZE_MAX);
99+
tt_want_ptr_op(NULL, ==, ptr);
100+
__iotc_free(ptr);
101+
})
102+
103+
/* Edge cases - SIZE_MAX
104+
Note: FreeRTOS heap size isn't large enough for SIZE_MAX allocations,
105+
so these tests are disabled for those targets. */
106+
#ifndef IOTC_TARGET_FREERTOS
107+
IOTC_TT_TESTCASE(
108+
utest__iotc_memory_calloc__num_1__size_max,
109+
{
110+
void* ptr = __iotc_calloc( /*num=*/1, /*size=*/SIZE_MAX);
111+
tt_want_ptr_op(NULL, ==, ptr);
112+
__iotc_free(ptr);
113+
})
114+
115+
IOTC_TT_TESTCASE(
116+
utest__iotc_memory_calloc__num_max_minus_1__size_1,
117+
{
118+
void* ptr = __iotc_calloc( /*num=*/SIZE_MAX-1, /*size=*/1);
119+
tt_want_ptr_op(NULL, ==, ptr);
120+
__iotc_free(ptr);
121+
})
122+
123+
IOTC_TT_TESTCASE(
124+
utest__iotc_memory_calloc__overflow__num_half_max__size_2,
125+
{
126+
void* ptr = __iotc_calloc( /*num=*/SIZE_MAX/2, /*size=*/2);
127+
tt_want_ptr_op(NULL, ==, ptr);
128+
__iotc_free(ptr);
129+
})
130+
131+
IOTC_TT_TESTCASE(
132+
utest__iotc_memory_calloc__overflow__num_2__size_half_max,
133+
{
134+
void* ptr = __iotc_calloc( /*num=*/2, /*size=*/SIZE_MAX/2);
135+
tt_want_ptr_op(NULL, ==, ptr);
136+
__iotc_free(ptr);
137+
})
138+
139+
IOTC_TT_TESTCASE(
140+
utest__iotc_memory_calloc__num_1__size_max_minus_1,
141+
{
142+
void* ptr = __iotc_calloc( /*num=*/1, /*size=*/SIZE_MAX-1);
143+
tt_want_ptr_op(NULL, ==, ptr);
144+
__iotc_free(ptr);
145+
})
146+
147+
IOTC_TT_TESTCASE(
148+
utest__iotc_memory_calloc__num_size_max_minus_1__size_1,
149+
{
150+
void* ptr = __iotc_calloc( /*num=*/SIZE_MAX-1, /*size=*/1);
151+
tt_want_ptr_op(NULL, ==, ptr);
152+
__iotc_free(ptr);
153+
})
154+
#endif /* IOTC_TARGET_FREERTOS */
155+
156+
/* Overflow cases. */
157+
IOTC_TT_TESTCASE(
158+
utest__iotc_memory_calloc__overflow__num_3__size_half_max,
159+
{
160+
void* ptr = __iotc_calloc( /*num=*/3, /*size=*/SIZE_MAX/2);
161+
tt_want_ptr_op(NULL, ==, ptr);
162+
__iotc_free(ptr);
163+
})
164+
165+
IOTC_TT_TESTCASE(
166+
utest__iotc_memory_calloc__overflow__num_half_max__size_3,
167+
{
168+
void* ptr = __iotc_calloc( /*num=*/SIZE_MAX/2, /*size=*/3) ;
169+
tt_want_ptr_op(NULL, ==, ptr);
170+
__iotc_free(ptr);
171+
})
172+
173+
IOTC_TT_TESTCASE(
174+
utest__iotc_memory_calloc__overflow__num_half_max_plus_1__size_2,
175+
{
176+
void* ptr = __iotc_calloc( /*num=*/SIZE_MAX/2+1, /*size=*/2) ;
177+
tt_want_ptr_op(NULL, ==, ptr);
178+
__iotc_free(ptr);
179+
})
180+
181+
IOTC_TT_TESTCASE(
182+
utest__iotc_memory_calloc__overflow__num_3__size_half_max_plus_1,
183+
{
184+
void* ptr = __iotc_calloc( /*num=*/3, /*size=*/SIZE_MAX/2+1) ;
185+
tt_want_ptr_op(NULL, ==, ptr);
186+
__iotc_free(ptr);
187+
})
188+
189+
IOTC_TT_TESTGROUP_END
190+
191+
#ifndef IOTC_TT_TESTCASE_ENUMERATION__SECONDPREPROCESSORRUN
192+
#define IOTC_TT_TESTCASE_ENUMERATION__SECONDPREPROCESSORRUN
193+
#include __FILE__
194+
#undef IOTC_TT_TESTCASE_ENUMERATION__SECONDPREPROCESSORRUN
195+
#endif // IOTC_TT_TESTCASE_ENUMERATION__SECONDPREPROCESSORRUN

src/tests/utests/iotc_utests.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
#define IOTC_TT_MQTT_LOGIC_LAYER_SUBSCRIBE ( IOTC_TT_MQTT_PARSER << 1 )
3434
#define IOTC_TT_CONTROL_TOPIC ( IOTC_TT_MQTT_LOGIC_LAYER_SUBSCRIBE << 1 )
3535
#define IOTC_TT_MQTT_SERIALIZER ( IOTC_TT_CONTROL_TOPIC << 1 )
36-
#define IOTC_TT_MEMORY_LIMITER ( IOTC_TT_MQTT_SERIALIZER << 1 )
36+
#define IOTC_TT_MEMORY_CALLOC ( IOTC_TT_MQTT_SERIALIZER << 1)
37+
#define IOTC_TT_MEMORY_LIMITER ( IOTC_TT_MEMORY_CALLOC << 1 )
3738
#define IOTC_TT_THREAD ( IOTC_TT_MEMORY_LIMITER << 1 )
3839
#define IOTC_TT_THREAD_WORKERTHREAD ( IOTC_TT_THREAD << 1 )
3940
#define IOTC_TT_THREAD_THREADPOOL ( IOTC_TT_THREAD_WORKERTHREAD << 1 )
@@ -63,6 +64,7 @@ IOTC_TT_TESTCASE_PREDECLARATION(utest_datastructures);
6364
IOTC_TT_TESTCASE_PREDECLARATION(utest_list);
6465
IOTC_TT_TESTCASE_PREDECLARATION(utest_data_desc);
6566
IOTC_TT_TESTCASE_PREDECLARATION(utest_backoff);
67+
IOTC_TT_TESTCASE_PREDECLARATION(utest_memory_calloc);
6668
IOTC_TT_TESTCASE_PREDECLARATION(utest_mqtt_ctors_dtors);
6769
IOTC_TT_TESTCASE_PREDECLARATION(utest_mqtt_parser);
6870
IOTC_TT_TESTCASE_PREDECLARATION(utest_mqtt_logic_layer_subscribe);
@@ -194,6 +196,8 @@ struct testgroup_t groups[] = {
194196

195197
{"utest_timed_task - ", utest_timed_task},
196198

199+
{"utest_memory_calloc - ", utest_memory_calloc},
200+
197201
#if (IOTC_TT_TEST_SET & IOTC_TT_MQTT_CODEC_LAYER_DATA)
198202
{"utest_mqtt_codec_layer_data - ", utest_mqtt_codec_layer_data},
199203
#endif

0 commit comments

Comments
 (0)