• 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 
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