1 /*------------------------------------------------------------------
2  * strcpy_s.c
3  *
4  * October 2008, Bo Berry
5  *
6  * Copyright (c) 2008-2011 by Cisco Systems, Inc
7  * All rights reserved.
8  *
9  * Permission is hereby granted, free of charge, to any person
10  * obtaining a copy of this software and associated documentation
11  * files (the "Software"), to deal in the Software without
12  * restriction, including without limitation the rights to use,
13  * copy, modify, merge, publish, distribute, sublicense, and/or
14  * sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following
16  * conditions:
17  *
18  * The above copyright notice and this permission notice shall be
19  * included in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28  * OTHER DEALINGS IN THE SOFTWARE.
29  *------------------------------------------------------------------
30  */
31 
32 #include "safeclib_private.h"
33 #include "safe_str_constraint.h"
34 #include "safe_str_lib.h"
35 
36 /**
37  * NAME
38  *    strcpy_s
39  *
40  * SYNOPSIS
41  *    #include "safe_str_lib.h"
42  *    errno_t
43  *    strcpy_s(char *dest, rsize_t dmax, const char *src)
44  *
45  * DESCRIPTION
46  *    The strcpy_s function copies the string pointed to by src
47  *    (including the terminating null character) into the array
48  *    pointed to by dest. All elements following the terminating
49  *    null character (if any) written by strcpy_s in the array
50  *    of dmax characters pointed to by dest are nulled when
51  *    strcpy_s returns.
52  *
53  * SPECIFIED IN
54  *    ISO/IEC TR 24731, Programming languages, environments
55  *    and system software interfaces, Extensions to the C Library,
56  *    Part I: Bounds-checking interfaces
57  *
58  * INPUT PARAMETERS
59  *    dest      pointer to string that will be replaced by src.
60  *
61  *    dmax      restricted maximum length of dest
62  *
63  *    src       pointer to the string that will be copied
64  *               to dest
65  *
66  * OUTPUT PARAMETERS
67  *    dest      updated
68  *
69  * RUNTIME CONSTRAINTS
70  *    Neither dest nor src shall be a null pointer.
71  *    dmax shall not be greater than RSIZE_MAX_STR.
72  *    dmax shall not equal zero.
73  *    dmax shall be greater than strnlen_s(src, dmax).
74  *    Copying shall not take place between objects that overlap.
75  *    If there is a runtime-constraint violation, then if dest
76  *       is not a null pointer and destmax is greater than zero and
77  *       not greater than RSIZE_MAX_STR, then strcpy_s nulls dest.
78  *
79  * RETURN VALUE
80  *    EOK        successful operation, the characters in src were
81  *               copied into dest and the result is null terminated.
82  *    ESNULLP    NULL pointer
83  *    ESZEROL    zero length
84  *    ESLEMAX    length exceeds max limit
85  *    ESOVRLP    strings overlap
86  *    ESNOSPC    not enough space to copy src
87  *
88  * ALSO SEE
89  *    strcat_s(), strncat_s(), strncpy_s()
90  *
91  */
strcpy_s(char * dest,rsize_t dmax,const char * src)92 errno_t strcpy_s(char *dest, rsize_t dmax, const char *src) {
93     rsize_t     orig_dmax;
94     char *      orig_dest;
95     const char *overlap_bumper;
96 
97     if (dest == NULL) {
98         invoke_safe_str_constraint_handler("strcpy_s: dest is null", NULL, ESNULLP);
99         return RCNEGATE(ESNULLP);
100     }
101 
102     if (dmax == 0) {
103         invoke_safe_str_constraint_handler("strcpy_s: dmax is 0", NULL, ESZEROL);
104         return RCNEGATE(ESZEROL);
105     }
106 
107     if (dmax > RSIZE_MAX_STR) {
108         invoke_safe_str_constraint_handler("strcpy_s: dmax exceeds max", NULL, ESLEMAX);
109         return RCNEGATE(ESLEMAX);
110     }
111 
112     if (src == NULL) {
113 #ifdef SAFECLIB_STR_NULL_SLACK
114         /* null string to clear data */
115         while (dmax) {
116             *dest = '\0';
117             dmax--;
118             dest++;
119         }
120 #else
121         *dest = '\0';
122 #endif
123         invoke_safe_str_constraint_handler("strcpy_s: src is null", NULL, ESNULLP);
124         return RCNEGATE(ESNULLP);
125     }
126 
127     if (dest == src) {
128         return RCNEGATE(EOK);
129     }
130 
131     /* hold base of dest in case src was not copied */
132     orig_dmax = dmax;
133     orig_dest = dest;
134 
135     if (dest < src) {
136         overlap_bumper = src;
137 
138         while (dmax > 0) {
139             if (dest == overlap_bumper) {
140                 handle_error(orig_dest,
141                              orig_dmax,
142                              "strcpy_s: "
143                              "overlapping objects",
144                              ESOVRLP);
145                 return RCNEGATE(ESOVRLP);
146             }
147 
148             *dest = *src;
149             if (*dest == '\0') {
150 #ifdef SAFECLIB_STR_NULL_SLACK
151                 /* null slack to clear any data */
152                 while (dmax) {
153                     *dest = '\0';
154                     dmax--;
155                     dest++;
156                 }
157 #endif
158                 return RCNEGATE(EOK);
159             }
160 
161             dmax--;
162             dest++;
163             src++;
164         }
165 
166     } else {
167         overlap_bumper = dest;
168 
169         while (dmax > 0) {
170             if (src == overlap_bumper) {
171                 handle_error(orig_dest,
172                              orig_dmax,
173                              "strcpy_s: "
174                              "overlapping objects",
175                              ESOVRLP);
176                 return RCNEGATE(ESOVRLP);
177             }
178 
179             *dest = *src;
180             if (*dest == '\0') {
181 #ifdef SAFECLIB_STR_NULL_SLACK
182                 /* null slack to clear any data */
183                 while (dmax) {
184                     *dest = '\0';
185                     dmax--;
186                     dest++;
187                 }
188 #endif
189                 return RCNEGATE(EOK);
190             }
191 
192             dmax--;
193             dest++;
194             src++;
195         }
196     }
197 
198     /*
199      * the entire src must have been copied, if not reset dest
200      * to null the string.
201      */
202     handle_error(orig_dest,
203                  orig_dmax,
204                  "strcpy_s: not "
205                  "enough space for src",
206                  ESNOSPC);
207     return RCNEGATE(ESNOSPC);
208 }
209 EXPORT_SYMBOL(strcpy_s)
210