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