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