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
CheckSrcCountRange(char * strDest,size_t destMax,const char * strSrc,size_t count)22 static errno_t CheckSrcCountRange(char *strDest, size_t destMax, const char *strSrc, size_t count)
23 {
24 size_t tmpDestMax = destMax;
25 size_t tmpCount = count;
26 const char *endPos = strSrc;
27
28 /* use destMax and count as boundary checker and destMax must be greater than zero */
29 while (*(endPos) != '\0' && tmpDestMax > 0 && tmpCount > 0) {
30 ++endPos;
31 --tmpCount;
32 --tmpDestMax;
33 }
34 if (tmpDestMax == 0) {
35 strDest[0] = '\0';
36 SECUREC_ERROR_INVALID_RANGE("strncpy_s");
37 return ERANGE_AND_RESET;
38 }
39 return EOK;
40 }
41
strncpy_error(char * strDest,size_t destMax,const char * strSrc,size_t count)42 errno_t strncpy_error(char *strDest, size_t destMax, const char *strSrc, size_t count)
43 {
44 if (destMax == 0 || destMax > SECUREC_STRING_MAX_LEN) {
45 SECUREC_ERROR_INVALID_RANGE("strncpy_s");
46 return ERANGE;
47 } else if (strDest == NULL || strSrc == NULL) {
48 SECUREC_ERROR_INVALID_PARAMTER("strncpy_s");
49 if (strDest != NULL) {
50 strDest[0] = '\0';
51 return EINVAL_AND_RESET;
52 }
53 return EINVAL;
54 } else if (count > SECUREC_STRING_MAX_LEN) {
55 strDest[0] = '\0'; /* clear dest string */
56 SECUREC_ERROR_INVALID_RANGE("strncpy_s");
57 return ERANGE_AND_RESET;
58 } else if (count == 0) {
59 strDest[0] = '\0';
60 return EOK;
61 }
62
63 return CheckSrcCountRange(strDest, destMax, strSrc, count);
64 }
65
66 /* The function compiler will be inlined and not placed in other files */
SecMinStrLen(const char * str,size_t maxLen)67 static size_t SecMinStrLen(const char *str, size_t maxLen)
68 {
69 #if SECUREC_HAVE_STRNLEN
70 size_t len = strnlen(str, maxLen); /* no ending terminator */
71 #else
72 size_t len = 0;
73 /* use maxLen as boundary checker */
74 const char *strEnd = str;
75 while (len < maxLen && *(strEnd) != '\0') {
76 ++strEnd;
77 ++len; /* no ending terminator */
78 }
79 #endif
80 return len;
81 }
82
83 /*******************************************************************************
84 * <FUNCTION DESCRIPTION>
85 * The strncpy_s function copies not more than n successive characters (not including the terminating null character)
86 * from the array pointed to by strSrc to the array pointed to by strDest.
87 *
88 * <INPUT PARAMETERS>
89 * strDest Destination string.
90 * destMax The size of the destination string, in characters.
91 * strSrc Source string.
92 * count Number of characters to be copied.
93 *
94 * <OUTPUT PARAMETERS>
95 * strDest is updated
96 *
97 * <RETURN VALUE>
98 * EOK Success
99 * EINVAL strDest is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN
100 * EINVAL_AND_RESET strDest != NULL and strSrc is NULL and destMax != 0 and destMax <= SECUREC_STRING_MAX_LEN
101 * ERANGE destMax is 0 and destMax > SECUREC_STRING_MAX_LEN
102 * ERANGE_AND_RESET strDest have not enough space and all other parameters are valid and not overlap
103 * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and all parameters are valid
104 *
105 * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
106 *******************************************************************************
107 */
strncpy_s(char * strDest,size_t destMax,const char * strSrc,size_t count)108 errno_t strncpy_s(char *strDest, size_t destMax, const char *strSrc, size_t count)
109 {
110 #ifdef SECUREC_COMPATIBLE_WIN_FORMAT
111 if ((destMax > 0 && destMax <= SECUREC_STRING_MAX_LEN && strDest != NULL && strSrc != NULL &&
112 (count <= SECUREC_STRING_MAX_LEN || count == ((size_t)-1)) && count > 0)) {
113 #else
114 if ((destMax > 0 && destMax <= SECUREC_STRING_MAX_LEN && strDest != NULL && strSrc != NULL &&
115 count <= SECUREC_STRING_MAX_LEN && count > 0)) {
116 #endif
117 size_t minCpLen; /* use it to store the maxi length limit */
118
119 if (count < destMax) {
120 minCpLen = SecMinStrLen(strSrc, count); /* no ending terminator */
121 } else {
122 minCpLen = SecMinStrLen(strSrc, destMax);
123 if (minCpLen == destMax) {
124 #ifdef SECUREC_COMPATIBLE_WIN_FORMAT
125 if (count == ((size_t)-1)) {
126 /* Compatible with windows security function features */
127 minCpLen = destMax - 1;
128 } else {
129 strDest[0] = '\0';
130 SECUREC_ERROR_BUFFER_OVERLAP("strncpy_s");
131 return ERANGE_AND_RESET;
132 }
133 #else
134 strDest[0] = '\0';
135 SECUREC_ERROR_BUFFER_OVERLAP("strncpy_s");
136 return ERANGE_AND_RESET;
137 #endif
138 }
139 }
140
141 if ((strDest < strSrc && strDest + minCpLen < strSrc) ||
142 (strSrc < strDest && strSrc + minCpLen < strDest) || strDest == strSrc) {
143 /* Not overlap */
144 (void)memcpy(strDest, strSrc, minCpLen); /* copy string without terminator */
145 strDest[minCpLen] = '\0';
146 return EOK;
147 } else {
148 strDest[0] = '\0';
149 SECUREC_ERROR_BUFFER_OVERLAP("strncpy_s");
150 return EOVERLAP_AND_RESET;
151 }
152 }
153 return strncpy_error(strDest, destMax, strSrc, count);
154 }
155
156 #if SECUREC_IN_KERNEL
157 EXPORT_SYMBOL(strncpy_s);
158 #endif
159
160