• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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: Performance-sensitive
16  * [reason] Always used in the performance critical path,
17  *          and sufficient input validation is performed before calling
18  */
19 
20 #include "securecutil.h"
21 
22 #ifndef SECUREC_STRCOPY_THRESHOLD_SIZE
23 #define SECUREC_STRCOPY_THRESHOLD_SIZE (32UL)
24 #endif
25 
26 /* The purpose of converting to void is to clean up the alarm */
27 #define SECUREC_STRCPY_BY_STRUCT(num) \
28         case num: \
29             *(SecStrBuf##num *)(void *)strDest = *(const SecStrBuf##num *)(const void *)strSrc; \
30             break;
31 
32 #define SECUREC_SMALL_STR_COPY do { \
33         if (SECUREC_ADDR_ALIGNED_8(strDest) && SECUREC_ADDR_ALIGNED_8(strSrc)) { \
34             /* use struct assignment */ \
35             switch (srcStrLen) { \
36                 SECUREC_STRCPY_BY_STRUCT(1) \
37                 SECUREC_STRCPY_BY_STRUCT(2) \
38                 SECUREC_STRCPY_BY_STRUCT(3) \
39                 SECUREC_STRCPY_BY_STRUCT(4) \
40                 SECUREC_STRCPY_BY_STRUCT(5) \
41                 SECUREC_STRCPY_BY_STRUCT(6) \
42                 SECUREC_STRCPY_BY_STRUCT(7) \
43                 SECUREC_STRCPY_BY_STRUCT(8) \
44                 SECUREC_STRCPY_BY_STRUCT(9) \
45                 SECUREC_STRCPY_BY_STRUCT(10) \
46                 SECUREC_STRCPY_BY_STRUCT(11) \
47                 SECUREC_STRCPY_BY_STRUCT(12) \
48                 SECUREC_STRCPY_BY_STRUCT(13) \
49                 SECUREC_STRCPY_BY_STRUCT(14) \
50                 SECUREC_STRCPY_BY_STRUCT(15) \
51                 SECUREC_STRCPY_BY_STRUCT(16) \
52                 SECUREC_STRCPY_BY_STRUCT(17) \
53                 SECUREC_STRCPY_BY_STRUCT(18) \
54                 SECUREC_STRCPY_BY_STRUCT(19) \
55                 SECUREC_STRCPY_BY_STRUCT(20) \
56                 SECUREC_STRCPY_BY_STRUCT(21) \
57                 SECUREC_STRCPY_BY_STRUCT(22) \
58                 SECUREC_STRCPY_BY_STRUCT(23) \
59                 SECUREC_STRCPY_BY_STRUCT(24) \
60                 SECUREC_STRCPY_BY_STRUCT(25) \
61                 SECUREC_STRCPY_BY_STRUCT(26) \
62                 SECUREC_STRCPY_BY_STRUCT(27) \
63                 SECUREC_STRCPY_BY_STRUCT(28) \
64                 SECUREC_STRCPY_BY_STRUCT(29) \
65                 SECUREC_STRCPY_BY_STRUCT(30) \
66                 SECUREC_STRCPY_BY_STRUCT(31) \
67                 SECUREC_STRCPY_BY_STRUCT(32) \
68                 default:break; \
69             } /* END switch */ \
70         }  else { \
71             char *tmpStrDest = (char *)strDest; \
72             const char *tmpStrSrc =  (const char *)strSrc; \
73             switch (srcStrLen) { \
74                 case 32: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
75                 case 31: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
76                 case 30: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
77                 case 29: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
78                 case 28: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
79                 case 27: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
80                 case 26: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
81                 case 25: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
82                 case 24: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
83                 case 23: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
84                 case 22: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
85                 case 21: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
86                 case 20: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
87                 case 19: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
88                 case 18: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
89                 case 17: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
90                 case 16: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
91                 case 15: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
92                 case 14: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
93                 case 13: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
94                 case 12: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
95                 case 11: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
96                 case 10: *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
97                 case 9:  *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
98                 case 8:  *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
99                 case 7:  *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
100                 case 6:  *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
101                 case 5:  *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
102                 case 4:  *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
103                 case 3:  *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
104                 case 2:  *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
105                 case 1:  *tmpStrDest++ = *tmpStrSrc++; /* fall-through */ /* FALLTHRU */ \
106                 default:break; \
107             } \
108         } \
109     } SECUREC_WHILE_ZERO
110 
CheckSrcRange(char * strDest,size_t destMax,const char * strSrc)111 static errno_t CheckSrcRange(char *strDest, size_t destMax, const char *strSrc)
112 {
113     size_t tmpDestMax = destMax;
114     const char *tmpSrc = strSrc;
115     /* use destMax as boundary checker and destMax must be greater than zero */
116     while (*(tmpSrc) != '\0' && tmpDestMax > 0) {
117         ++tmpSrc;
118         --tmpDestMax;
119     }
120     if (tmpDestMax == 0) {
121         strDest[0] = '\0';
122         SECUREC_ERROR_INVALID_RANGE("strcpy_s");
123         return ERANGE_AND_RESET;
124     }
125     return EOK;
126 }
127 
strcpy_error(char * strDest,size_t destMax,const char * strSrc)128 errno_t strcpy_error(char *strDest, size_t destMax, const char *strSrc)
129 {
130     if (destMax == 0 || destMax > SECUREC_STRING_MAX_LEN) {
131         SECUREC_ERROR_INVALID_RANGE("strcpy_s");
132         return ERANGE;
133     } else if (strDest == NULL || strSrc == NULL) {
134         SECUREC_ERROR_INVALID_PARAMTER("strcpy_s");
135         if (strDest != NULL) {
136             strDest[0] = '\0';
137             return EINVAL_AND_RESET;
138         }
139         return EINVAL;
140     }
141     return CheckSrcRange(strDest, destMax, strSrc);
142 }
143 
144 /*******************************************************************************
145  * <FUNCTION DESCRIPTION>
146  *    The strcpy_s function copies the string pointed to  strSrc
147  *          (including the terminating null character) into the array pointed to by strDest
148  *    The destination string must be large enough to hold the source string,
149  *    including the terminating null character. strcpy_s will return EOVERLAP_AND_RESET
150  *    if the source and destination strings overlap.
151  *
152  * <INPUT PARAMETERS>
153  *    strDest                          Location of destination string buffer
154  *    destMax                        Size of the destination string buffer.
155  *    strSrc                            Null-terminated source string buffer.
156  *
157  * <OUTPUT PARAMETERS>
158  *    strDest                         is updated.
159  *
160  * <RETURN VALUE>
161  *    EOK                               Success
162  *    EINVAL                          strDest is  NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN
163  *    EINVAL_AND_RESET       strDest !=  NULL and strSrc is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN
164  *    ERANGE                         destMax is 0 and destMax > SECUREC_STRING_MAX_LEN
165  *    ERANGE_AND_RESET      strDest have not enough space  and all other parameters are valid  and not overlap
166  *    EOVERLAP_AND_RESET   dest buffer and source buffer are overlapped and all  parameters are valid
167  *
168  *    If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
169  *******************************************************************************
170  */
strcpy_s(char * strDest,size_t destMax,const char * strSrc)171 errno_t strcpy_s(char *strDest, size_t destMax, const char *strSrc)
172 {
173     if ((destMax > 0 && destMax <= SECUREC_STRING_MAX_LEN && strDest != NULL && strSrc != NULL && strDest != strSrc)) {
174 #if SECUREC_HAVE_STRNLEN
175         size_t srcStrLen = strnlen(strSrc, destMax) + 1;    /* len  include \0 */
176 #else
177         size_t srcStrLen = destMax; /* use it to store the max length limit */
178         const char *endPos = strSrc;
179         while (*(endPos) != '\0' && srcStrLen > 0) {    /* use srcStrLen as boundary checker */
180             ++endPos;
181             --srcStrLen;
182         }
183         srcStrLen = (size_t)(endPos - strSrc) + 1;  /* len  include \0 */
184 #endif
185         /* le is  high performance to lt */
186         if (srcStrLen <= destMax) {
187             if ((strDest < strSrc && strDest + srcStrLen <= strSrc) ||
188                 (strSrc < strDest && strSrc + srcStrLen <= strDest)) {
189 #if SECUREC_IN_KERNEL
190                 (void)memcpy(strDest, strSrc, srcStrLen);
191 #else
192                 if (srcStrLen > SECUREC_STRCOPY_THRESHOLD_SIZE) {
193                     (void)memcpy(strDest, strSrc, srcStrLen);
194                 } else {
195                     SECUREC_SMALL_STR_COPY;
196                 }
197 #endif
198                 return EOK;
199             } else {
200                 strDest[0] = '\0';
201                 SECUREC_ERROR_BUFFER_OVERLAP("strcpy_s");
202                 return EOVERLAP_AND_RESET;
203             }
204 
205         }
206     }
207     return strcpy_error(strDest, destMax, strSrc);
208 }
209 
210 #if SECUREC_IN_KERNEL
211 EXPORT_SYMBOL(strcpy_s);
212 #endif
213 
214