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: memset_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 #define SECUREC_MEMSET_PARAM_OK(dest, destMax, count) (SECUREC_LIKELY((destMax) <= SECUREC_MEM_MAX_LEN && \
23     (dest) != NULL && (count) <= (destMax)))
24 
25 #if SECUREC_WITH_PERFORMANCE_ADDONS
26 
27 /* Use union to clear strict-aliasing warning */
28 typedef union {
29     SecStrBuf32 buf32;
30     SecStrBuf31 buf31;
31     SecStrBuf30 buf30;
32     SecStrBuf29 buf29;
33     SecStrBuf28 buf28;
34     SecStrBuf27 buf27;
35     SecStrBuf26 buf26;
36     SecStrBuf25 buf25;
37     SecStrBuf24 buf24;
38     SecStrBuf23 buf23;
39     SecStrBuf22 buf22;
40     SecStrBuf21 buf21;
41     SecStrBuf20 buf20;
42     SecStrBuf19 buf19;
43     SecStrBuf18 buf18;
44     SecStrBuf17 buf17;
45     SecStrBuf16 buf16;
46     SecStrBuf15 buf15;
47     SecStrBuf14 buf14;
48     SecStrBuf13 buf13;
49     SecStrBuf12 buf12;
50     SecStrBuf11 buf11;
51     SecStrBuf10 buf10;
52     SecStrBuf9 buf9;
53     SecStrBuf8 buf8;
54     SecStrBuf7 buf7;
55     SecStrBuf6 buf6;
56     SecStrBuf5 buf5;
57     SecStrBuf4 buf4;
58     SecStrBuf3 buf3;
59     SecStrBuf2 buf2;
60 } SecStrBuf32Union;
61 /* C standard initializes the first member of the consortium. */
62 static const SecStrBuf32 g_allZero = {{
63     0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U,
64     0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U,
65     0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U,
66     0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U
67 }};
68 static const SecStrBuf32 g_allFF = {{
69     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
70     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
71     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
72     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
73 }};
74 
75 /* Clear conversion warning strict aliasing" */
SecStrictAliasingCast(const SecStrBuf32 *buf)76 SECUREC_INLINE const SecStrBuf32Union *SecStrictAliasingCast(const SecStrBuf32 *buf)
77 {
78     return (const SecStrBuf32Union *)buf;
79 }
80 
81 #ifndef SECUREC_MEMSET_THRESHOLD_SIZE
82 #define SECUREC_MEMSET_THRESHOLD_SIZE 32UL
83 #endif
84 
85 #define SECUREC_UNALIGNED_SET(dest, c, count) do { \
86     unsigned char *pDest_ = (unsigned char *)(dest); \
87     switch (count) { \
88         case 32: \
89             *(pDest_++) = (unsigned char)(c); \
90             /* fall-through */ /* FALLTHRU */ \
91         case 31: \
92             *(pDest_++) = (unsigned char)(c); \
93             /* fall-through */ /* FALLTHRU */ \
94         case 30: \
95             *(pDest_++) = (unsigned char)(c); \
96             /* fall-through */ /* FALLTHRU */ \
97         case 29: \
98             *(pDest_++) = (unsigned char)(c); \
99             /* fall-through */ /* FALLTHRU */ \
100         case 28: \
101             *(pDest_++) = (unsigned char)(c); \
102             /* fall-through */ /* FALLTHRU */ \
103         case 27: \
104             *(pDest_++) = (unsigned char)(c); \
105             /* fall-through */ /* FALLTHRU */ \
106         case 26: \
107             *(pDest_++) = (unsigned char)(c); \
108             /* fall-through */ /* FALLTHRU */ \
109         case 25: \
110             *(pDest_++) = (unsigned char)(c); \
111             /* fall-through */ /* FALLTHRU */ \
112         case 24: \
113             *(pDest_++) = (unsigned char)(c); \
114             /* fall-through */ /* FALLTHRU */ \
115         case 23: \
116             *(pDest_++) = (unsigned char)(c); \
117             /* fall-through */ /* FALLTHRU */ \
118         case 22: \
119             *(pDest_++) = (unsigned char)(c); \
120             /* fall-through */ /* FALLTHRU */ \
121         case 21: \
122             *(pDest_++) = (unsigned char)(c); \
123             /* fall-through */ /* FALLTHRU */ \
124         case 20: \
125             *(pDest_++) = (unsigned char)(c); \
126             /* fall-through */ /* FALLTHRU */ \
127         case 19: \
128             *(pDest_++) = (unsigned char)(c); \
129             /* fall-through */ /* FALLTHRU */ \
130         case 18: \
131             *(pDest_++) = (unsigned char)(c); \
132             /* fall-through */ /* FALLTHRU */ \
133         case 17: \
134             *(pDest_++) = (unsigned char)(c); \
135             /* fall-through */ /* FALLTHRU */ \
136         case 16: \
137             *(pDest_++) = (unsigned char)(c); \
138             /* fall-through */ /* FALLTHRU */ \
139         case 15: \
140             *(pDest_++) = (unsigned char)(c); \
141             /* fall-through */ /* FALLTHRU */ \
142         case 14: \
143             *(pDest_++) = (unsigned char)(c); \
144             /* fall-through */ /* FALLTHRU */ \
145         case 13: \
146             *(pDest_++) = (unsigned char)(c); \
147             /* fall-through */ /* FALLTHRU */ \
148         case 12: \
149             *(pDest_++) = (unsigned char)(c); \
150             /* fall-through */ /* FALLTHRU */ \
151         case 11: \
152             *(pDest_++) = (unsigned char)(c); \
153             /* fall-through */ /* FALLTHRU */ \
154         case 10: \
155             *(pDest_++) = (unsigned char)(c); \
156             /* fall-through */ /* FALLTHRU */ \
157         case 9: \
158             *(pDest_++) = (unsigned char)(c); \
159             /* fall-through */ /* FALLTHRU */ \
160         case 8: \
161             *(pDest_++) = (unsigned char)(c); \
162             /* fall-through */ /* FALLTHRU */ \
163         case 7: \
164             *(pDest_++) = (unsigned char)(c); \
165             /* fall-through */ /* FALLTHRU */ \
166         case 6: \
167             *(pDest_++) = (unsigned char)(c); \
168             /* fall-through */ /* FALLTHRU */ \
169         case 5: \
170             *(pDest_++) = (unsigned char)(c); \
171             /* fall-through */ /* FALLTHRU */ \
172         case 4: \
173             *(pDest_++) = (unsigned char)(c); \
174             /* fall-through */ /* FALLTHRU */ \
175         case 3: \
176             *(pDest_++) = (unsigned char)(c); \
177             /* fall-through */ /* FALLTHRU */ \
178         case 2: \
179             *(pDest_++) = (unsigned char)(c); \
180             /* fall-through */ /* FALLTHRU */ \
181         case 1: \
182             *(pDest_++) = (unsigned char)(c); \
183             /* fall-through */ /* FALLTHRU */ \
184         default: \
185             /* Do nothing */ \
186             break; \
187     } \
188 } SECUREC_WHILE_ZERO
189 
190 #define SECUREC_SET_VALUE_BY_STRUCT(dest, dataName, n) do { \
191     *(SecStrBuf##n *)(dest) = *(const SecStrBuf##n *)(&((SecStrictAliasingCast(&(dataName)))->buf##n)); \
192 } SECUREC_WHILE_ZERO
193 
194 #define SECUREC_ALIGNED_SET_OPT_ZERO_FF(dest, c, count) do { \
195     switch (c) { \
196         case 0: \
197             switch (count) { \
198                 case 1: \
199                     *(unsigned char *)(dest) = (unsigned char)0; \
200                     break; \
201                 case 2: \
202                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 2); \
203                     break; \
204                 case 3: \
205                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 3); \
206                     break; \
207                 case 4: \
208                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 4); \
209                     break; \
210                 case 5: \
211                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 5); \
212                     break; \
213                 case 6: \
214                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 6); \
215                     break; \
216                 case 7: \
217                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 7); \
218                     break; \
219                 case 8: \
220                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 8); \
221                     break; \
222                 case 9: \
223                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 9); \
224                     break; \
225                 case 10: \
226                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 10); \
227                     break; \
228                 case 11: \
229                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 11); \
230                     break; \
231                 case 12: \
232                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 12); \
233                     break; \
234                 case 13: \
235                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 13); \
236                     break; \
237                 case 14: \
238                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 14); \
239                     break; \
240                 case 15: \
241                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 15); \
242                     break; \
243                 case 16: \
244                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 16); \
245                     break; \
246                 case 17: \
247                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 17); \
248                     break; \
249                 case 18: \
250                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 18); \
251                     break; \
252                 case 19: \
253                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 19); \
254                     break; \
255                 case 20: \
256                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 20); \
257                     break; \
258                 case 21: \
259                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 21); \
260                     break; \
261                 case 22: \
262                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 22); \
263                     break; \
264                 case 23: \
265                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 23); \
266                     break; \
267                 case 24: \
268                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 24); \
269                     break; \
270                 case 25: \
271                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 25); \
272                     break; \
273                 case 26: \
274                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 26); \
275                     break; \
276                 case 27: \
277                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 27); \
278                     break; \
279                 case 28: \
280                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 28); \
281                     break; \
282                 case 29: \
283                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 29); \
284                     break; \
285                 case 30: \
286                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 30); \
287                     break; \
288                 case 31: \
289                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 31); \
290                     break; \
291                 case 32: \
292                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 32); \
293                     break; \
294                 default: \
295                     /* Do nothing */ \
296                     break; \
297             } \
298             break; \
299         case 0xFF: \
300             switch (count) { \
301                 case 1: \
302                     *(unsigned char *)(dest) = (unsigned char)0xffU; \
303                     break; \
304                 case 2: \
305                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 2); \
306                     break; \
307                 case 3: \
308                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 3); \
309                     break; \
310                 case 4: \
311                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 4); \
312                     break; \
313                 case 5: \
314                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 5); \
315                     break; \
316                 case 6: \
317                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 6); \
318                     break; \
319                 case 7: \
320                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 7); \
321                     break; \
322                 case 8: \
323                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 8); \
324                     break; \
325                 case 9: \
326                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 9); \
327                     break; \
328                 case 10: \
329                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 10); \
330                     break; \
331                 case 11: \
332                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 11); \
333                     break; \
334                 case 12: \
335                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 12); \
336                     break; \
337                 case 13: \
338                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 13); \
339                     break; \
340                 case 14: \
341                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 14); \
342                     break; \
343                 case 15: \
344                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 15); \
345                     break; \
346                 case 16: \
347                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 16); \
348                     break; \
349                 case 17: \
350                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 17); \
351                     break; \
352                 case 18: \
353                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 18); \
354                     break; \
355                 case 19: \
356                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 19); \
357                     break; \
358                 case 20: \
359                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 20); \
360                     break; \
361                 case 21: \
362                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 21); \
363                     break; \
364                 case 22: \
365                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 22); \
366                     break; \
367                 case 23: \
368                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 23); \
369                     break; \
370                 case 24: \
371                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 24); \
372                     break; \
373                 case 25: \
374                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 25); \
375                     break; \
376                 case 26: \
377                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 26); \
378                     break; \
379                 case 27: \
380                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 27); \
381                     break; \
382                 case 28: \
383                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 28); \
384                     break; \
385                 case 29: \
386                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 29); \
387                     break; \
388                 case 30: \
389                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 30); \
390                     break; \
391                 case 31: \
392                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 31); \
393                     break; \
394                 case 32: \
395                     SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 32); \
396                     break; \
397                 default: \
398                     /* Do nothing */ \
399                     break; \
400             } \
401             break; \
402         default: \
403             SECUREC_UNALIGNED_SET((dest), (c), (count)); \
404             break; \
405     } /* END switch */ \
406 } SECUREC_WHILE_ZERO
407 
408 #define SECUREC_SMALL_MEM_SET(dest, c, count) do { \
409     if (SECUREC_ADDR_ALIGNED_8((dest))) { \
410         SECUREC_ALIGNED_SET_OPT_ZERO_FF((dest), (c), (count)); \
411     } else { \
412         SECUREC_UNALIGNED_SET((dest), (c), (count)); \
413     } \
414 } SECUREC_WHILE_ZERO
415 
416 /*
417  * Performance optimization
418  */
419 #define SECUREC_MEMSET_OPT(dest, c, count) do { \
420     if ((count) > SECUREC_MEMSET_THRESHOLD_SIZE) { \
421         SECUREC_MEMSET_PREVENT_DSE((dest), (c), (count)); \
422     } else { \
423         SECUREC_SMALL_MEM_SET((dest), (c), (count)); \
424     } \
425 } SECUREC_WHILE_ZERO
426 #endif
427 
428 /*
429  * Handling errors
430  */
SecMemsetError(void *dest, size_t destMax, int c)431 SECUREC_INLINE errno_t SecMemsetError(void *dest, size_t destMax, int c)
432 {
433     /* Check destMax is 0 compatible with _sp macro */
434     if (destMax == 0 || destMax > SECUREC_MEM_MAX_LEN) {
435         SECUREC_ERROR_INVALID_RANGE("memset_s");
436         return ERANGE;
437     }
438     if (dest == NULL) {
439         SECUREC_ERROR_INVALID_PARAMTER("memset_s");
440         return EINVAL;
441     }
442     SECUREC_MEMSET_PREVENT_DSE(dest, c, destMax); /* Set entire buffer to value c */
443     SECUREC_ERROR_INVALID_RANGE("memset_s");
444     return ERANGE_AND_RESET;
445 }
446 
447 /*
448  * <FUNCTION DESCRIPTION>
449  *    The memset_s function copies the value of c (converted to an unsigned char)
450  *     into each of the first count characters of the object pointed to by dest.
451  *
452  * <INPUT PARAMETERS>
453  *    dest                Pointer to destination.
454  *    destMax             The size of the buffer.
455  *    c                   Character to set.
456  *    count               Number of characters.
457  *
458  * <OUTPUT PARAMETERS>
459  *    dest buffer         is updated.
460  *
461  * <RETURN VALUE>
462  *    EOK                 Success
463  *    EINVAL              dest == NULL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN
464  *    ERANGE              destMax > SECUREC_MEM_MAX_LEN or (destMax is 0 and count > destMax)
465  *    ERANGE_AND_RESET    count > destMax and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN and dest != NULL
466  *
467  *    if return ERANGE_AND_RESET then fill dest to c ,fill length is destMax
468  */
memset_s(void *dest, size_t destMax, int c, size_t count)469 errno_t memset_s(void *dest, size_t destMax, int c, size_t count)
470 {
471     if (SECUREC_MEMSET_PARAM_OK(dest, destMax, count)) {
472         SECUREC_MEMSET_PREVENT_DSE(dest, c, count);
473         return EOK;
474     }
475     /* Meet some runtime violation, return error code */
476     return SecMemsetError(dest, destMax, c);
477 }
478 
479 #if SECUREC_EXPORT_KERNEL_SYMBOL
480 EXPORT_SYMBOL(memset_s);
481 #endif
482 
483 #if SECUREC_WITH_PERFORMANCE_ADDONS
484 /*
485  * Performance optimization
486  */
memset_sOptAsm(void *dest, size_t destMax, int c, size_t count)487 errno_t memset_sOptAsm(void *dest, size_t destMax, int c, size_t count)
488 {
489     if (SECUREC_MEMSET_PARAM_OK(dest, destMax, count)) {
490         SECUREC_MEMSET_OPT(dest, c, count);
491         return EOK;
492     }
493     /* Meet some runtime violation, return error code */
494     return SecMemsetError(dest, destMax, c);
495 }
496 
497 /*
498  * Performance optimization, trim judgement on "destMax <= SECUREC_MEM_MAX_LEN"
499  */
memset_sOptTc(void *dest, size_t destMax, int c, size_t count)500 errno_t memset_sOptTc(void *dest, size_t destMax, int c, size_t count)
501 {
502     if (SECUREC_LIKELY(count <= destMax && dest != NULL)) {
503         SECUREC_MEMSET_OPT(dest, c, count);
504         return EOK;
505     }
506     /* Meet some runtime violation, return error code */
507     return SecMemsetError(dest, destMax, c);
508 }
509 #endif
510 
511