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
16 #include "securecutil.h"
17
18 #if SECUREC_HAVE_STRNLEN
SecDoStrncat(char * strDest,size_t destMax,const char * strSrc,size_t count)19 static errno_t SecDoStrncat(char *strDest, size_t destMax, const char *strSrc, size_t count)
20 {
21 size_t destLen = strnlen(strDest, destMax);
22 /* The strSrc is no longer optimized. The reason is that when count is small,
23 * the efficiency of strnlen is higher than that of self realization.
24 */
25 size_t srcLen = strnlen(strSrc, count);
26
27 if ((strDest < strSrc && strDest + destLen + srcLen >= strSrc) || \
28 (strSrc < strDest && strSrc + srcLen >= strDest)) {
29 strDest[0] = '\0';
30 if (strDest + destLen <= strSrc && destLen == destMax) {
31 SECUREC_ERROR_INVALID_PARAMTER("strncat_s");
32 return EINVAL_AND_RESET;
33 }
34 SECUREC_ERROR_BUFFER_OVERLAP("strncat_s");
35 return EOVERLAP_AND_RESET;
36 }
37 if (srcLen + destLen >= destMax || strDest == strSrc) {
38 strDest[0] = '\0';
39 if (destLen == destMax) {
40 SECUREC_ERROR_INVALID_PARAMTER("strncat_s");
41 return EINVAL_AND_RESET;
42 }
43 SECUREC_ERROR_INVALID_RANGE("strncat_s");
44 return ERANGE_AND_RESET;
45 }
46 (void)memcpy(strDest + destLen, strSrc, srcLen); /* no terminator */
47 *(strDest + destLen + srcLen) = '\0';
48 return EOK;
49 }
50 #else
SecDoStrncat(char * strDest,size_t destMax,const char * strSrc,size_t count)51 static errno_t SecDoStrncat(char *strDest, size_t destMax, const char *strSrc, size_t count)
52 {
53 char *tmpDest = strDest;
54 const char *tmpSrc = strSrc;
55 size_t availableSize = destMax;
56 size_t maxCount = count;
57 SECUREC_IN_REGISTER const char *overlapGuard = NULL;
58
59 if (tmpDest < tmpSrc) {
60 overlapGuard = tmpSrc;
61 while (availableSize > 0 && *tmpDest != '\0') {
62 if (tmpDest == overlapGuard) {
63 strDest[0] = '\0';
64 SECUREC_ERROR_BUFFER_OVERLAP("strncat_s");
65 return EOVERLAP_AND_RESET;
66 }
67 ++tmpDest;
68 --availableSize;
69 }
70
71 /* strDestination unterminated, return error. */
72 if (availableSize == 0) {
73 strDest[0] = '\0';
74 SECUREC_ERROR_INVALID_PARAMTER("strncat_s");
75 return EINVAL_AND_RESET;
76 }
77 while (maxCount > 0 && (*tmpDest++ = *tmpSrc++) != '\0' && --availableSize > 0) {
78 if (tmpDest == overlapGuard) {
79 strDest[0] = '\0';
80 SECUREC_ERROR_BUFFER_OVERLAP("strncat_s");
81 return EOVERLAP_AND_RESET;
82 }
83 --maxCount;
84 }
85 } else {
86 overlapGuard = tmpDest;
87 while (availableSize > 0 && *tmpDest != '\0') {
88 /* seek to string end, and no need to check overlap */
89 ++tmpDest;
90 --availableSize;
91 }
92
93 /* strDest unterminated, return error. */
94 if (availableSize == 0) {
95 strDest[0] = '\0';
96 SECUREC_ERROR_INVALID_PARAMTER("strncat_s");
97 return EINVAL_AND_RESET;
98 }
99 while (maxCount > 0 && (*tmpDest++ = *tmpSrc++) != '\0' && --availableSize > 0) {
100 if (tmpSrc == overlapGuard) {
101 strDest[0] = '\0';
102 SECUREC_ERROR_BUFFER_OVERLAP("strncat_s");
103 return EOVERLAP_AND_RESET;
104 }
105 --maxCount;
106 }
107 }
108 if (maxCount == 0) {
109 *tmpDest = 0; /* add terminator to strDest */
110 }
111
112 /* strDest have not enough space,return error */
113 if (availableSize == 0) {
114 strDest[0] = '\0';
115 SECUREC_ERROR_INVALID_RANGE("strncat_s");
116 return ERANGE_AND_RESET;
117 }
118
119 return EOK;
120 }
121 #endif
122
123 /*******************************************************************************
124 * <FUNCTION DESCRIPTION>
125 * The strncat_s function appends not more than n successive characters
126 * (not including the terminating null character)
127 * from the array pointed to by strSrc to the end of the string pointed to by strDest
128 * The strncat_s function try to append the first D characters of strSrc to
129 * the end of strDest, where D is the lesser of count and the length of strSrc.
130 * If appending those D characters will fit within strDest (whose size is given
131 * as destMax) and still leave room for a null terminator, then those characters
132 * are appended, starting at the original terminating null of strDest, and a
133 * new terminating null is appended; otherwise, strDest[0] is set to the null
134 * character.
135 *
136 * <INPUT PARAMETERS>
137 * strDest Null-terminated destination string.
138 * destMax Size of the destination buffer.
139 * strSrc Null-terminated source string.
140 * count Number of character to append, or truncate.
141 *
142 * <OUTPUT PARAMETERS>
143 * strDest is updated
144 *
145 * <RETURN VALUE>
146 * EOK Success
147 * EINVAL strDest is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN
148 * EINVAL_AND_RESET (strDest unterminated and all other parameters are valid)or
149 * (strDest != NULL and strSrc is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN)
150 * ERANGE destMax is 0 and destMax > SECUREC_STRING_MAX_LEN
151 * ERANGE_AND_RESET strDest have not enough space and all other parameters are valid and not overlap
152 * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and all parameters are valid
153 *
154 * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
155 ********************************************************************************
156 */
strncat_s(char * strDest,size_t destMax,const char * strSrc,size_t count)157 errno_t strncat_s(char *strDest, size_t destMax, const char *strSrc, size_t count)
158 {
159 if (destMax == 0 || destMax > SECUREC_STRING_MAX_LEN) {
160 SECUREC_ERROR_INVALID_RANGE("strncat_s");
161 return ERANGE;
162 }
163
164 if (strDest == NULL || strSrc == NULL) {
165 SECUREC_ERROR_INVALID_PARAMTER("strncat_s");
166 if (strDest != NULL) {
167 strDest[0] = '\0';
168 return EINVAL_AND_RESET;
169 }
170 return EINVAL;
171 }
172 #ifdef SECUREC_COMPATIBLE_WIN_FORMAT
173 if (count > SECUREC_STRING_MAX_LEN && count != (size_t)-1) {
174 strDest[0] = '\0';
175 SECUREC_ERROR_INVALID_RANGE("strncat_s");
176 return ERANGE_AND_RESET;
177 }
178 #else
179 if (count > SECUREC_STRING_MAX_LEN) {
180 strDest[0] = '\0';
181 SECUREC_ERROR_INVALID_RANGE("strncat_s");
182 return ERANGE_AND_RESET;
183 }
184 #endif
185
186 return SecDoStrncat(strDest, destMax, strSrc, count);
187 }
188
189 #if SECUREC_IN_KERNEL
190 EXPORT_SYMBOL(strncat_s);
191 #endif
192
193