1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 /* [Standardize-exceptions] Use unsafe function: Portability
16 * [reason] Use unsafe function to implement security function to maintain platform compatibility.
17 * And sufficient input validation is performed before calling
18 */
19
20 #include "securecutil.h"
21
22 #ifndef SECUREC_MEMCOPY_WITH_PERFORMANCE
23 #define SECUREC_MEMCOPY_WITH_PERFORMANCE 0
24 #endif
25
26 #if SECUREC_WITH_PERFORMANCE_ADDONS || SECUREC_MEMCOPY_WITH_PERFORMANCE
27 #ifndef SECUREC_MEMCOPY_THRESHOLD_SIZE
28 #define SECUREC_MEMCOPY_THRESHOLD_SIZE (64UL)
29 #endif
30
31 #define SECUREC_COPY_STRUCT(num) case num:*(SecStrBuf##num *)dest=*(const SecStrBuf##num *) src;break;
32
33 #define SECUREC_SMALL_MEM_COPY do { \
34 if (SECUREC_ADDR_ALIGNED_8(dest) && SECUREC_ADDR_ALIGNED_8(src)) { \
35 /* use struct assignment */ \
36 switch (count) { \
37 SECUREC_COPY_STRUCT(1) \
38 SECUREC_COPY_STRUCT(2) \
39 SECUREC_COPY_STRUCT(3) \
40 SECUREC_COPY_STRUCT(4) \
41 SECUREC_COPY_STRUCT(5) \
42 SECUREC_COPY_STRUCT(6) \
43 SECUREC_COPY_STRUCT(7) \
44 SECUREC_COPY_STRUCT(8) \
45 SECUREC_COPY_STRUCT(9) \
46 SECUREC_COPY_STRUCT(10) \
47 SECUREC_COPY_STRUCT(11) \
48 SECUREC_COPY_STRUCT(12) \
49 SECUREC_COPY_STRUCT(13) \
50 SECUREC_COPY_STRUCT(14) \
51 SECUREC_COPY_STRUCT(15) \
52 SECUREC_COPY_STRUCT(16) \
53 SECUREC_COPY_STRUCT(17) \
54 SECUREC_COPY_STRUCT(18) \
55 SECUREC_COPY_STRUCT(19) \
56 SECUREC_COPY_STRUCT(20) \
57 SECUREC_COPY_STRUCT(21) \
58 SECUREC_COPY_STRUCT(22) \
59 SECUREC_COPY_STRUCT(23) \
60 SECUREC_COPY_STRUCT(24) \
61 SECUREC_COPY_STRUCT(25) \
62 SECUREC_COPY_STRUCT(26) \
63 SECUREC_COPY_STRUCT(27) \
64 SECUREC_COPY_STRUCT(28) \
65 SECUREC_COPY_STRUCT(29) \
66 SECUREC_COPY_STRUCT(30) \
67 SECUREC_COPY_STRUCT(31) \
68 SECUREC_COPY_STRUCT(32) \
69 SECUREC_COPY_STRUCT(33) \
70 SECUREC_COPY_STRUCT(34) \
71 SECUREC_COPY_STRUCT(35) \
72 SECUREC_COPY_STRUCT(36) \
73 SECUREC_COPY_STRUCT(37) \
74 SECUREC_COPY_STRUCT(38) \
75 SECUREC_COPY_STRUCT(39) \
76 SECUREC_COPY_STRUCT(40) \
77 SECUREC_COPY_STRUCT(41) \
78 SECUREC_COPY_STRUCT(42) \
79 SECUREC_COPY_STRUCT(43) \
80 SECUREC_COPY_STRUCT(44) \
81 SECUREC_COPY_STRUCT(45) \
82 SECUREC_COPY_STRUCT(46) \
83 SECUREC_COPY_STRUCT(47) \
84 SECUREC_COPY_STRUCT(48) \
85 SECUREC_COPY_STRUCT(49) \
86 SECUREC_COPY_STRUCT(50) \
87 SECUREC_COPY_STRUCT(51) \
88 SECUREC_COPY_STRUCT(52) \
89 SECUREC_COPY_STRUCT(53) \
90 SECUREC_COPY_STRUCT(54) \
91 SECUREC_COPY_STRUCT(55) \
92 SECUREC_COPY_STRUCT(56) \
93 SECUREC_COPY_STRUCT(57) \
94 SECUREC_COPY_STRUCT(58) \
95 SECUREC_COPY_STRUCT(59) \
96 SECUREC_COPY_STRUCT(60) \
97 SECUREC_COPY_STRUCT(61) \
98 SECUREC_COPY_STRUCT(62) \
99 SECUREC_COPY_STRUCT(63) \
100 SECUREC_COPY_STRUCT(64) \
101 default:break; \
102 } /* END switch */ \
103 } else { \
104 char *tmpDest = (char *)dest; \
105 const char *tmpSrc = (const char *)src; \
106 switch (count) { \
107 case 64: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
108 case 63: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
109 case 62: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
110 case 61: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
111 case 60: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
112 case 59: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
113 case 58: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
114 case 57: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
115 case 56: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
116 case 55: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
117 case 54: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
118 case 53: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
119 case 52: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
120 case 51: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
121 case 50: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
122 case 49: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
123 case 48: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
124 case 47: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
125 case 46: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
126 case 45: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
127 case 44: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
128 case 43: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
129 case 42: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
130 case 41: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
131 case 40: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
132 case 39: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
133 case 38: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
134 case 37: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
135 case 36: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
136 case 35: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
137 case 34: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
138 case 33: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
139 case 32: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
140 case 31: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
141 case 30: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
142 case 29: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
143 case 28: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
144 case 27: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
145 case 26: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
146 case 25: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
147 case 24: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
148 case 23: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
149 case 22: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
150 case 21: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
151 case 20: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
152 case 19: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
153 case 18: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
154 case 17: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
155 case 16: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
156 case 15: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
157 case 14: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
158 case 13: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
159 case 12: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
160 case 11: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
161 case 10: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
162 case 9: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
163 case 8: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
164 case 7: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
165 case 6: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
166 case 5: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
167 case 4: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
168 case 3: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
169 case 2: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
170 case 1: *tmpDest++ = *tmpSrc++; /* fall-through */ /* FALLTHRU */ \
171 default:break; \
172 } \
173 } \
174 } SECUREC_WHILE_ZERO
175 #endif
176
SecMemcpyError(void * dest,size_t destMax,const void * src,size_t count)177 static errno_t SecMemcpyError(void *dest, size_t destMax, const void *src, size_t count)
178 {
179 if (destMax == 0 || destMax > SECUREC_MEM_MAX_LEN) {
180 SECUREC_ERROR_INVALID_RANGE("memcpy_s");
181 return ERANGE;
182 }
183 if (dest == NULL || src == NULL) {
184 SECUREC_ERROR_INVALID_PARAMTER("memcpy_s");
185 if (dest != NULL) {
186 (void)memset(dest, 0, destMax);
187 return EINVAL_AND_RESET;
188 }
189 return EINVAL;
190 }
191 if (count > destMax) {
192 (void)memset(dest, 0, destMax);
193 SECUREC_ERROR_INVALID_RANGE("memcpy_s");
194 return ERANGE_AND_RESET;
195 }
196 if (dest == src) {
197 return EOK;
198 }
199 if ((dest > src && dest < (const void *)((const unsigned char *)src + count)) ||
200 (src > dest && src < (void *)((unsigned char *)dest + count))) {
201 (void)memset(dest, 0, destMax);
202 SECUREC_ERROR_BUFFER_OVERLAP("memcpy_s");
203 return EOVERLAP_AND_RESET;
204 }
205 /* count == 0 also return EOK */
206 return EOK;
207 }
208
209 #if SECUREC_WITH_PERFORMANCE_ADDONS || SECUREC_MEMCOPY_WITH_PERFORMANCE
SecDoMemcpyOpt(void * dest,const void * src,size_t count)210 static void SecDoMemcpyOpt(void *dest, const void *src, size_t count)
211 {
212 if (count > SECUREC_MEMCOPY_THRESHOLD_SIZE) {
213 /*
214 * if SECUREC_USE_ASM macro is enabled, it will call assembly language function to improve performance.
215 */
216 #ifdef SECUREC_USE_ASM
217 (void)memcpy_opt(dest, src, count);
218 #else
219 /* large enough, let system API do it */
220 (void)memcpy(dest, src, count);
221 #endif
222
223 } else {
224 SECUREC_SMALL_MEM_COPY;
225 }
226 return;
227 }
228 #endif
229
230 /*******************************************************************************
231 * <FUNCTION DESCRIPTION>
232 * The memcpy_s function copies n characters from the object pointed to by src into the object pointed to by dest
233 *
234 * <INPUT PARAMETERS>
235 * dest Destination buffer.
236 * destMax Size of the destination buffer.
237 * src Buffer to copy from.
238 * count Number of characters to copy
239 *
240 * <OUTPUT PARAMETERS>
241 * dest buffer is updated.
242 *
243 * <RETURN VALUE>
244 * EOK Success
245 * EINVAL dest is NULL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN
246 * EINVAL_AND_RESET dest != NULL and src is NULL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN
247 * ERANGE destMax > SECUREC_MEM_MAX_LEN or destMax is 0
248 * ERANGE_AND_RESET count > destMax and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN
249 * and dest != NULL and src != NULL
250 * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and
251 * count <= destMax destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN and dest != NULL
252 * and src != NULL and dest != src
253 *
254 * if an error occurred, dest will be filled with 0.
255 * If the source and destination overlap, the behavior of memcpy_s is undefined.
256 * Use memmove_s to handle overlapping regions.
257 *******************************************************************************
258 */
memcpy_s(void * dest,size_t destMax,const void * src,size_t count)259 errno_t memcpy_s(void *dest, size_t destMax, const void *src, size_t count)
260 {
261 #if defined(SECUREC_COMPATIBLE_WIN_FORMAT)
262 /* fread API in windows will call memcpy_s and pass 0xffffffff to destMax.
263 * To avoid the failure of fread, we don't check desMax limit.
264 */
265 if (SECUREC_LIKELY(count <= destMax && dest != NULL && src != NULL &&
266 count > 0 &&
267 ((dest > src && (void *)((const unsigned char *)src + count) <= dest) ||
268 (src > dest && (void *)((unsigned char *)dest + count) <= src)))) {
269 #else
270 if (SECUREC_LIKELY(count <= destMax && dest != NULL && src != NULL &&
271 destMax <= SECUREC_MEM_MAX_LEN &&
272 count > 0 &&
273 ((dest > src && (const void *)((const unsigned char *)src + count) <= dest) ||
274 (src > dest && (void *)((unsigned char *)dest + count) <= src)))) {
275 #endif
276 #if SECUREC_MEMCOPY_WITH_PERFORMANCE
277 SecDoMemcpyOpt(dest, src, count);
278 #else
279 #ifdef SECUREC_USE_ASM
280 (void)memcpy_opt(dest, src, count);
281 #else
282 (void)memcpy(dest, src, count);
283 #endif
284 #endif
285 return EOK;
286 }
287
288 /* meet some runtime violation, return error code */
289 return SecMemcpyError(dest, destMax, src, count);
290
291 }
292
293 #if SECUREC_IN_KERNEL
294 EXPORT_SYMBOL(memcpy_s);
295 #endif
296
297 #if SECUREC_WITH_PERFORMANCE_ADDONS
298
299 errno_t memcpy_sOptAsm(void *dest, size_t destMax, const void *src, size_t count)
300 {
301 if (SECUREC_LIKELY(count <= destMax && dest != NULL && src != NULL &&
302 destMax <= SECUREC_MEM_MAX_LEN &&
303 count > 0 &&
304 ((dest > src && (const void *)((const unsigned char *)src + count) <= dest) ||
305 (src > dest && (const void *)((const unsigned char *)dest + count) <= src)))) {
306 SecDoMemcpyOpt(dest, src, count);
307 return EOK;
308 }
309 /* meet some runtime violation, return error code */
310 return SecMemcpyError(dest, destMax, src, count);
311 }
312
313 /* trim judgement on "destMax <= SECUREC_MEM_MAX_LEN" */
314 errno_t memcpy_sOptTc(void *dest, size_t destMax, const void *src, size_t count)
315 {
316 if (SECUREC_LIKELY(count <= destMax && dest != NULL && src != NULL &&
317 count > 0 &&
318 ((dest > src && (const void *)((const unsigned char *)src + count) <= dest) ||
319 (src > dest && (void *)((unsigned char *)dest + count) <= src)))) {
320 SecDoMemcpyOpt(dest, src, count);
321 return EOK;
322 }
323 /* meet some runtime violation, return error code */
324 return SecMemcpyError(dest, destMax, src, count);
325 }
326 #endif
327
328