1/*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
3 * Licensed under Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 *          http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
8 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
9 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 * Description: memcpy_s function
12 * Create: 2014-02-25
13 */
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#if SECUREC_WITH_PERFORMANCE_ADDONS
23#ifndef SECUREC_MEMCOPY_THRESHOLD_SIZE
24#define SECUREC_MEMCOPY_THRESHOLD_SIZE 64UL
25#endif
26
27#define SECUREC_SMALL_MEM_COPY(dest, src, count) do { \
28    if (SECUREC_ADDR_ALIGNED_8(dest) && SECUREC_ADDR_ALIGNED_8(src)) { \
29        /* Use struct assignment */ \
30        switch (count) { \
31            case 1: \
32                *(unsigned char *)(dest) = *(const unsigned char *)(src); \
33                break; \
34            case 2: \
35                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 2); \
36                break; \
37            case 3: \
38                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 3); \
39                break; \
40            case 4: \
41                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 4); \
42                break; \
43            case 5: \
44                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 5); \
45                break; \
46            case 6: \
47                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 6); \
48                break; \
49            case 7: \
50                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 7); \
51                break; \
52            case 8: \
53                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 8); \
54                break; \
55            case 9: \
56                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 9); \
57                break; \
58            case 10: \
59                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 10); \
60                break; \
61            case 11: \
62                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 11); \
63                break; \
64            case 12: \
65                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 12); \
66                break; \
67            case 13: \
68                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 13); \
69                break; \
70            case 14: \
71                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 14); \
72                break; \
73            case 15: \
74                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 15); \
75                break; \
76            case 16: \
77                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 16); \
78                break; \
79            case 17: \
80                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 17); \
81                break; \
82            case 18: \
83                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 18); \
84                break; \
85            case 19: \
86                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 19); \
87                break; \
88            case 20: \
89                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 20); \
90                break; \
91            case 21: \
92                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 21); \
93                break; \
94            case 22: \
95                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 22); \
96                break; \
97            case 23: \
98                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 23); \
99                break; \
100            case 24: \
101                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 24); \
102                break; \
103            case 25: \
104                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 25); \
105                break; \
106            case 26: \
107                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 26); \
108                break; \
109            case 27: \
110                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 27); \
111                break; \
112            case 28: \
113                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 28); \
114                break; \
115            case 29: \
116                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 29); \
117                break; \
118            case 30: \
119                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 30); \
120                break; \
121            case 31: \
122                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 31); \
123                break; \
124            case 32: \
125                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 32); \
126                break; \
127            case 33: \
128                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 33); \
129                break; \
130            case 34: \
131                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 34); \
132                break; \
133            case 35: \
134                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 35); \
135                break; \
136            case 36: \
137                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 36); \
138                break; \
139            case 37: \
140                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 37); \
141                break; \
142            case 38: \
143                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 38); \
144                break; \
145            case 39: \
146                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 39); \
147                break; \
148            case 40: \
149                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 40); \
150                break; \
151            case 41: \
152                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 41); \
153                break; \
154            case 42: \
155                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 42); \
156                break; \
157            case 43: \
158                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 43); \
159                break; \
160            case 44: \
161                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 44); \
162                break; \
163            case 45: \
164                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 45); \
165                break; \
166            case 46: \
167                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 46); \
168                break; \
169            case 47: \
170                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 47); \
171                break; \
172            case 48: \
173                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 48); \
174                break; \
175            case 49: \
176                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 49); \
177                break; \
178            case 50: \
179                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 50); \
180                break; \
181            case 51: \
182                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 51); \
183                break; \
184            case 52: \
185                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 52); \
186                break; \
187            case 53: \
188                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 53); \
189                break; \
190            case 54: \
191                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 54); \
192                break; \
193            case 55: \
194                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 55); \
195                break; \
196            case 56: \
197                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 56); \
198                break; \
199            case 57: \
200                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 57); \
201                break; \
202            case 58: \
203                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 58); \
204                break; \
205            case 59: \
206                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 59); \
207                break; \
208            case 60: \
209                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 60); \
210                break; \
211            case 61: \
212                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 61); \
213                break; \
214            case 62: \
215                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 62); \
216                break; \
217            case 63: \
218                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 63); \
219                break; \
220            case 64: \
221                SECUREC_COPY_VALUE_BY_STRUCT((dest), (src), 64); \
222                break; \
223            default: \
224                /* Do nothing */ \
225                break; \
226        } /* END switch */ \
227    } else { \
228        unsigned char *tmpDest_ = (unsigned char *)(dest); \
229        const unsigned char *tmpSrc_ = (const unsigned char *)(src); \
230        switch (count) { \
231            case 64: \
232                *(tmpDest_++) = *(tmpSrc_++); \
233                /* fall-through */ /* FALLTHRU */ \
234            case 63: \
235                *(tmpDest_++) = *(tmpSrc_++); \
236                /* fall-through */ /* FALLTHRU */ \
237            case 62: \
238                *(tmpDest_++) = *(tmpSrc_++); \
239                /* fall-through */ /* FALLTHRU */ \
240            case 61: \
241                *(tmpDest_++) = *(tmpSrc_++); \
242                /* fall-through */ /* FALLTHRU */ \
243            case 60: \
244                *(tmpDest_++) = *(tmpSrc_++); \
245                /* fall-through */ /* FALLTHRU */ \
246            case 59: \
247                *(tmpDest_++) = *(tmpSrc_++); \
248                /* fall-through */ /* FALLTHRU */ \
249            case 58: \
250                *(tmpDest_++) = *(tmpSrc_++); \
251                /* fall-through */ /* FALLTHRU */ \
252            case 57: \
253                *(tmpDest_++) = *(tmpSrc_++); \
254                /* fall-through */ /* FALLTHRU */ \
255            case 56: \
256                *(tmpDest_++) = *(tmpSrc_++); \
257                /* fall-through */ /* FALLTHRU */ \
258            case 55: \
259                *(tmpDest_++) = *(tmpSrc_++); \
260                /* fall-through */ /* FALLTHRU */ \
261            case 54: \
262                *(tmpDest_++) = *(tmpSrc_++); \
263                /* fall-through */ /* FALLTHRU */ \
264            case 53: \
265                *(tmpDest_++) = *(tmpSrc_++); \
266                /* fall-through */ /* FALLTHRU */ \
267            case 52: \
268                *(tmpDest_++) = *(tmpSrc_++); \
269                /* fall-through */ /* FALLTHRU */ \
270            case 51: \
271                *(tmpDest_++) = *(tmpSrc_++); \
272                /* fall-through */ /* FALLTHRU */ \
273            case 50: \
274                *(tmpDest_++) = *(tmpSrc_++); \
275                /* fall-through */ /* FALLTHRU */ \
276            case 49: \
277                *(tmpDest_++) = *(tmpSrc_++); \
278                /* fall-through */ /* FALLTHRU */ \
279            case 48: \
280                *(tmpDest_++) = *(tmpSrc_++); \
281                /* fall-through */ /* FALLTHRU */ \
282            case 47: \
283                *(tmpDest_++) = *(tmpSrc_++); \
284                /* fall-through */ /* FALLTHRU */ \
285            case 46: \
286                *(tmpDest_++) = *(tmpSrc_++); \
287                /* fall-through */ /* FALLTHRU */ \
288            case 45: \
289                *(tmpDest_++) = *(tmpSrc_++); \
290                /* fall-through */ /* FALLTHRU */ \
291            case 44: \
292                *(tmpDest_++) = *(tmpSrc_++); \
293                /* fall-through */ /* FALLTHRU */ \
294            case 43: \
295                *(tmpDest_++) = *(tmpSrc_++); \
296                /* fall-through */ /* FALLTHRU */ \
297            case 42: \
298                *(tmpDest_++) = *(tmpSrc_++); \
299                /* fall-through */ /* FALLTHRU */ \
300            case 41: \
301                *(tmpDest_++) = *(tmpSrc_++); \
302                /* fall-through */ /* FALLTHRU */ \
303            case 40: \
304                *(tmpDest_++) = *(tmpSrc_++); \
305                /* fall-through */ /* FALLTHRU */ \
306            case 39: \
307                *(tmpDest_++) = *(tmpSrc_++); \
308                /* fall-through */ /* FALLTHRU */ \
309            case 38: \
310                *(tmpDest_++) = *(tmpSrc_++); \
311                /* fall-through */ /* FALLTHRU */ \
312            case 37: \
313                *(tmpDest_++) = *(tmpSrc_++); \
314                /* fall-through */ /* FALLTHRU */ \
315            case 36: \
316                *(tmpDest_++) = *(tmpSrc_++); \
317                /* fall-through */ /* FALLTHRU */ \
318            case 35: \
319                *(tmpDest_++) = *(tmpSrc_++); \
320                /* fall-through */ /* FALLTHRU */ \
321            case 34: \
322                *(tmpDest_++) = *(tmpSrc_++); \
323                /* fall-through */ /* FALLTHRU */ \
324            case 33: \
325                *(tmpDest_++) = *(tmpSrc_++); \
326                /* fall-through */ /* FALLTHRU */ \
327            case 32: \
328                *(tmpDest_++) = *(tmpSrc_++); \
329                /* fall-through */ /* FALLTHRU */ \
330            case 31: \
331                *(tmpDest_++) = *(tmpSrc_++); \
332                /* fall-through */ /* FALLTHRU */ \
333            case 30: \
334                *(tmpDest_++) = *(tmpSrc_++); \
335                /* fall-through */ /* FALLTHRU */ \
336            case 29: \
337                *(tmpDest_++) = *(tmpSrc_++); \
338                /* fall-through */ /* FALLTHRU */ \
339            case 28: \
340                *(tmpDest_++) = *(tmpSrc_++); \
341                /* fall-through */ /* FALLTHRU */ \
342            case 27: \
343                *(tmpDest_++) = *(tmpSrc_++); \
344                /* fall-through */ /* FALLTHRU */ \
345            case 26: \
346                *(tmpDest_++) = *(tmpSrc_++); \
347                /* fall-through */ /* FALLTHRU */ \
348            case 25: \
349                *(tmpDest_++) = *(tmpSrc_++); \
350                /* fall-through */ /* FALLTHRU */ \
351            case 24: \
352                *(tmpDest_++) = *(tmpSrc_++); \
353                /* fall-through */ /* FALLTHRU */ \
354            case 23: \
355                *(tmpDest_++) = *(tmpSrc_++); \
356                /* fall-through */ /* FALLTHRU */ \
357            case 22: \
358                *(tmpDest_++) = *(tmpSrc_++); \
359                /* fall-through */ /* FALLTHRU */ \
360            case 21: \
361                *(tmpDest_++) = *(tmpSrc_++); \
362                /* fall-through */ /* FALLTHRU */ \
363            case 20: \
364                *(tmpDest_++) = *(tmpSrc_++); \
365                /* fall-through */ /* FALLTHRU */ \
366            case 19: \
367                *(tmpDest_++) = *(tmpSrc_++); \
368                /* fall-through */ /* FALLTHRU */ \
369            case 18: \
370                *(tmpDest_++) = *(tmpSrc_++); \
371                /* fall-through */ /* FALLTHRU */ \
372            case 17: \
373                *(tmpDest_++) = *(tmpSrc_++); \
374                /* fall-through */ /* FALLTHRU */ \
375            case 16: \
376                *(tmpDest_++) = *(tmpSrc_++); \
377                /* fall-through */ /* FALLTHRU */ \
378            case 15: \
379                *(tmpDest_++) = *(tmpSrc_++); \
380                /* fall-through */ /* FALLTHRU */ \
381            case 14: \
382                *(tmpDest_++) = *(tmpSrc_++); \
383                /* fall-through */ /* FALLTHRU */ \
384            case 13: \
385                *(tmpDest_++) = *(tmpSrc_++); \
386                /* fall-through */ /* FALLTHRU */ \
387            case 12: \
388                *(tmpDest_++) = *(tmpSrc_++); \
389                /* fall-through */ /* FALLTHRU */ \
390            case 11: \
391                *(tmpDest_++) = *(tmpSrc_++); \
392                /* fall-through */ /* FALLTHRU */ \
393            case 10: \
394                *(tmpDest_++) = *(tmpSrc_++); \
395                /* fall-through */ /* FALLTHRU */ \
396            case 9: \
397                *(tmpDest_++) = *(tmpSrc_++); \
398                /* fall-through */ /* FALLTHRU */ \
399            case 8: \
400                *(tmpDest_++) = *(tmpSrc_++); \
401                /* fall-through */ /* FALLTHRU */ \
402            case 7: \
403                *(tmpDest_++) = *(tmpSrc_++); \
404                /* fall-through */ /* FALLTHRU */ \
405            case 6: \
406                *(tmpDest_++) = *(tmpSrc_++); \
407                /* fall-through */ /* FALLTHRU */ \
408            case 5: \
409                *(tmpDest_++) = *(tmpSrc_++); \
410                /* fall-through */ /* FALLTHRU */ \
411            case 4: \
412                *(tmpDest_++) = *(tmpSrc_++); \
413                /* fall-through */ /* FALLTHRU */ \
414            case 3: \
415                *(tmpDest_++) = *(tmpSrc_++); \
416                /* fall-through */ /* FALLTHRU */ \
417            case 2: \
418                *(tmpDest_++) = *(tmpSrc_++); \
419                /* fall-through */ /* FALLTHRU */ \
420            case 1: \
421                *(tmpDest_++) = *(tmpSrc_++); \
422                /* fall-through */ /* FALLTHRU */ \
423            default: \
424                /* Do nothing */ \
425                break; \
426        } \
427    } \
428} SECUREC_WHILE_ZERO
429
430/*
431 * Performance optimization
432 */
433#define SECUREC_MEMCPY_OPT(dest, src, count) do { \
434    if ((count) > SECUREC_MEMCOPY_THRESHOLD_SIZE) { \
435        SECUREC_MEMCPY_WARP_OPT((dest), (src), (count)); \
436    } else { \
437        SECUREC_SMALL_MEM_COPY((dest), (src), (count)); \
438    } \
439} SECUREC_WHILE_ZERO
440#endif
441
442/*
443 * Handling errors
444 */
445SECUREC_INLINE errno_t SecMemcpyError(void *dest, size_t destMax, const void *src, size_t count)
446{
447    if (destMax == 0 || destMax > SECUREC_MEM_MAX_LEN) {
448        SECUREC_ERROR_INVALID_RANGE("memcpy_s");
449        return ERANGE;
450    }
451    if (dest == NULL || src == NULL) {
452        SECUREC_ERROR_INVALID_PARAMTER("memcpy_s");
453        if (dest != NULL) {
454            (void)SECUREC_MEMSET_FUNC_OPT(dest, 0, destMax);
455            return EINVAL_AND_RESET;
456        }
457        return EINVAL;
458    }
459    if (count > destMax) {
460        (void)SECUREC_MEMSET_FUNC_OPT(dest, 0, destMax);
461        SECUREC_ERROR_INVALID_RANGE("memcpy_s");
462        return ERANGE_AND_RESET;
463    }
464    if (SECUREC_MEMORY_IS_OVERLAP(dest, src, count)) {
465        (void)SECUREC_MEMSET_FUNC_OPT(dest, 0, destMax);
466        SECUREC_ERROR_BUFFER_OVERLAP("memcpy_s");
467        return EOVERLAP_AND_RESET;
468    }
469    /* Count is 0 or dest equal src also ret EOK */
470    return EOK;
471}
472
473#if defined(SECUREC_COMPATIBLE_WIN_FORMAT)
474    /*
475     * The fread API in windows will call memcpy_s and pass 0xffffffff to destMax.
476     * To avoid the failure of fread, we don't check desMax limit.
477     */
478#define SECUREC_MEMCPY_PARAM_OK(dest, destMax, src, count) (SECUREC_LIKELY((count) <= (destMax) && \
479    (dest) != NULL && (src) != NULL && \
480    (count) > 0 && SECUREC_MEMORY_NO_OVERLAP((dest), (src), (count))))
481#else
482#define SECUREC_MEMCPY_PARAM_OK(dest, destMax, src, count) (SECUREC_LIKELY((count) <= (destMax) && \
483    (dest) != NULL && (src) != NULL && (destMax) <= SECUREC_MEM_MAX_LEN && \
484    (count) > 0 && SECUREC_MEMORY_NO_OVERLAP((dest), (src), (count))))
485#endif
486
487/*
488 * <FUNCTION DESCRIPTION>
489 *    The memcpy_s function copies n characters from the object pointed to by src into the object pointed to by dest
490 *
491 * <INPUT PARAMETERS>
492 *    dest                      Destination buffer.
493 *    destMax                   Size of the destination buffer.
494 *    src                       Buffer to copy from.
495 *    count                     Number of characters to copy
496 *
497 * <OUTPUT PARAMETERS>
498 *    dest buffer               is updated.
499 *
500 * <RETURN VALUE>
501 *    EOK                      Success
502 *    EINVAL                   dest is  NULL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN
503 *    EINVAL_AND_RESET         dest != NULL and src is NULL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN
504 *    ERANGE                   destMax > SECUREC_MEM_MAX_LEN or destMax is 0
505 *    ERANGE_AND_RESET         count > destMax and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN
506 *                             and dest  !=  NULL  and src != NULL
507 *    EOVERLAP_AND_RESET       dest buffer and source buffer are overlapped and
508 *                             count <= destMax destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN and dest  !=  NULL
509 *                             and src != NULL  and dest != src
510 *
511 *    if an error occurred, dest will be filled with 0.
512 *    If the source and destination overlap, the behavior of memcpy_s is undefined.
513 *    Use memmove_s to handle overlapping regions.
514 */
515errno_t memcpy_s(void *dest, size_t destMax, const void *src, size_t count)
516{
517    if (SECUREC_MEMCPY_PARAM_OK(dest, destMax, src, count)) {
518        SECUREC_MEMCPY_WARP_OPT(dest, src, count);
519        return EOK;
520    }
521    /* Meet some runtime violation, return error code */
522    return SecMemcpyError(dest, destMax, src, count);
523}
524
525#if SECUREC_EXPORT_KERNEL_SYMBOL
526EXPORT_SYMBOL(memcpy_s);
527#endif
528
529#if SECUREC_WITH_PERFORMANCE_ADDONS
530/*
531 * Performance optimization
532 */
533errno_t memcpy_sOptAsm(void *dest, size_t destMax, const void *src, size_t count)
534{
535    if (SECUREC_MEMCPY_PARAM_OK(dest, destMax, src, count)) {
536        SECUREC_MEMCPY_OPT(dest, src, count);
537        return EOK;
538    }
539    /* Meet some runtime violation, return error code */
540    return SecMemcpyError(dest, destMax, src, count);
541}
542
543/* Trim judgement on "destMax <= SECUREC_MEM_MAX_LEN" */
544errno_t memcpy_sOptTc(void *dest, size_t destMax, const void *src, size_t count)
545{
546    if (SECUREC_LIKELY(count <= destMax && dest != NULL && src != NULL && \
547                       count > 0 && SECUREC_MEMORY_NO_OVERLAP((dest), (src), (count)))) {
548        SECUREC_MEMCPY_OPT(dest, src, count);
549        return EOK;
550    }
551    /* Meet some runtime violation, return error code */
552    return SecMemcpyError(dest, destMax, src, count);
553}
554#endif
555
556