1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Broadcom Secure Standard Library.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2020, Broadcom.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Unless you and Broadcom execute a separate written software license
7*4882a593Smuzhiyun * agreement governing use of this software, this software is licensed to you
8*4882a593Smuzhiyun * under the terms of the GNU General Public License version 2 (the "GPL"),
9*4882a593Smuzhiyun * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10*4882a593Smuzhiyun * following added to such license:
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * As a special exception, the copyright holders of this software give you
13*4882a593Smuzhiyun * permission to link this software with independent modules, and to copy and
14*4882a593Smuzhiyun * distribute the resulting executable under terms of your choice, provided that
15*4882a593Smuzhiyun * you also meet, for each linked independent module, the terms and conditions of
16*4882a593Smuzhiyun * the license of that module. An independent module is a module which is not
17*4882a593Smuzhiyun * derived from this software. The special exception does not apply to any
18*4882a593Smuzhiyun * modifications of the software.
19*4882a593Smuzhiyun *
20*4882a593Smuzhiyun *
21*4882a593Smuzhiyun * <<Broadcom-WL-IPTag/Dual:>>
22*4882a593Smuzhiyun */
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #include <typedefs.h>
25*4882a593Smuzhiyun #include <bcmdefs.h>
26*4882a593Smuzhiyun #ifdef BCMDRIVER
27*4882a593Smuzhiyun #include <osl.h>
28*4882a593Smuzhiyun #else /* BCMDRIVER */
29*4882a593Smuzhiyun #include <stddef.h>
30*4882a593Smuzhiyun #include <string.h>
31*4882a593Smuzhiyun #endif /* else BCMDRIVER */
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #include <bcmstdlib_s.h>
34*4882a593Smuzhiyun #include <bcmutils.h>
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun /* Don't use compiler builtins for stdlib APIs within the implementation of the stdlib itself. */
37*4882a593Smuzhiyun #if defined(BCM_STDLIB_S_BUILTINS_TEST)
38*4882a593Smuzhiyun #undef memmove_s
39*4882a593Smuzhiyun #undef memcpy_s
40*4882a593Smuzhiyun #undef memset_s
41*4882a593Smuzhiyun #undef strlcpy
42*4882a593Smuzhiyun #undef strlcat_s
43*4882a593Smuzhiyun #endif /* BCM_STDLIB_S_BUILTINS_TEST */
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun /*
46*4882a593Smuzhiyun * __SIZE_MAX__ value is depending on platform:
47*4882a593Smuzhiyun * Firmware Dongle: RAMSIZE (Dongle Specific Limit).
48*4882a593Smuzhiyun * LINUX NIC/Windows/MACOSX/Application: OS Native or
49*4882a593Smuzhiyun * 0xFFFFFFFFu if not defined.
50*4882a593Smuzhiyun */
51*4882a593Smuzhiyun #ifndef SIZE_MAX
52*4882a593Smuzhiyun #ifndef __SIZE_MAX__
53*4882a593Smuzhiyun #ifdef DONGLEBUILD
54*4882a593Smuzhiyun #define __SIZE_MAX__ RAMSIZE
55*4882a593Smuzhiyun #else
56*4882a593Smuzhiyun #define __SIZE_MAX__ 0xFFFFFFFFu
57*4882a593Smuzhiyun #endif /* DONGLEBUILD */
58*4882a593Smuzhiyun #endif /* __SIZE_MAX__ */
59*4882a593Smuzhiyun #define SIZE_MAX __SIZE_MAX__
60*4882a593Smuzhiyun #endif /* SIZE_MAX */
61*4882a593Smuzhiyun #define RSIZE_MAX (SIZE_MAX >> 1u)
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun #if !defined(__STDC_WANT_SECURE_LIB__) && \
64*4882a593Smuzhiyun !(defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__))
65*4882a593Smuzhiyun /*
66*4882a593Smuzhiyun * memmove_s - secure memmove
67*4882a593Smuzhiyun * dest : pointer to the object to copy to
68*4882a593Smuzhiyun * destsz : size of the destination buffer
69*4882a593Smuzhiyun * src : pointer to the object to copy from
70*4882a593Smuzhiyun * n : number of bytes to copy
71*4882a593Smuzhiyun * Return Value : zero on success and non-zero on error
72*4882a593Smuzhiyun * Also on error, if dest is not a null pointer and destsz not greater
73*4882a593Smuzhiyun * than RSIZE_MAX, writes destsz zero bytes into the dest object.
74*4882a593Smuzhiyun */
75*4882a593Smuzhiyun int
memmove_s(void * dest,size_t destsz,const void * src,size_t n)76*4882a593Smuzhiyun memmove_s(void *dest, size_t destsz, const void *src, size_t n)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun int err = BCME_OK;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun if ((!dest) || (((char *)dest + destsz) < (char *)dest)) {
81*4882a593Smuzhiyun err = BCME_BADARG;
82*4882a593Smuzhiyun goto exit;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun if (destsz > RSIZE_MAX) {
86*4882a593Smuzhiyun err = BCME_BADLEN;
87*4882a593Smuzhiyun goto exit;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun if (destsz < n) {
91*4882a593Smuzhiyun memset(dest, 0, destsz);
92*4882a593Smuzhiyun err = BCME_BADLEN;
93*4882a593Smuzhiyun goto exit;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun if ((!src) || (((const char *)src + n) < (const char *)src)) {
97*4882a593Smuzhiyun memset(dest, 0, destsz);
98*4882a593Smuzhiyun err = BCME_BADARG;
99*4882a593Smuzhiyun goto exit;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun memmove(dest, src, n);
103*4882a593Smuzhiyun exit:
104*4882a593Smuzhiyun return err;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun /*
108*4882a593Smuzhiyun * memcpy_s - secure memcpy
109*4882a593Smuzhiyun * dest : pointer to the object to copy to
110*4882a593Smuzhiyun * destsz : size of the destination buffer
111*4882a593Smuzhiyun * src : pointer to the object to copy from
112*4882a593Smuzhiyun * n : number of bytes to copy
113*4882a593Smuzhiyun * Return Value : zero on success and non-zero on error
114*4882a593Smuzhiyun * Also on error, if dest is not a null pointer and destsz not greater
115*4882a593Smuzhiyun * than RSIZE_MAX, writes destsz zero bytes into the dest object.
116*4882a593Smuzhiyun */
117*4882a593Smuzhiyun int
BCMPOSTTRAPFN(memcpy_s)118*4882a593Smuzhiyun BCMPOSTTRAPFN(memcpy_s)(void *dest, size_t destsz, const void *src, size_t n)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun int err = BCME_OK;
121*4882a593Smuzhiyun char *d = dest;
122*4882a593Smuzhiyun const char *s = src;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun if ((!d) || ((d + destsz) < d)) {
125*4882a593Smuzhiyun err = BCME_BADARG;
126*4882a593Smuzhiyun goto exit;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun if (destsz > RSIZE_MAX) {
130*4882a593Smuzhiyun err = BCME_BADLEN;
131*4882a593Smuzhiyun goto exit;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun if (destsz < n) {
135*4882a593Smuzhiyun memset(dest, 0, destsz);
136*4882a593Smuzhiyun err = BCME_BADLEN;
137*4882a593Smuzhiyun goto exit;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun if ((!s) || ((s + n) < s)) {
141*4882a593Smuzhiyun memset(dest, 0, destsz);
142*4882a593Smuzhiyun err = BCME_BADARG;
143*4882a593Smuzhiyun goto exit;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun /* overlap checking between dest and src */
147*4882a593Smuzhiyun if (!(((d + destsz) <= s) || (d >= (s + n)))) {
148*4882a593Smuzhiyun memset(dest, 0, destsz);
149*4882a593Smuzhiyun err = BCME_BADARG;
150*4882a593Smuzhiyun goto exit;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun (void)memcpy(dest, src, n);
154*4882a593Smuzhiyun exit:
155*4882a593Smuzhiyun return err;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun /*
159*4882a593Smuzhiyun * memset_s - secure memset
160*4882a593Smuzhiyun * dest : pointer to the object to be set
161*4882a593Smuzhiyun * destsz : size of the destination buffer
162*4882a593Smuzhiyun * c : byte value
163*4882a593Smuzhiyun * n : number of bytes to be set
164*4882a593Smuzhiyun * Return Value : zero on success and non-zero on error
165*4882a593Smuzhiyun * Also on error, if dest is not a null pointer and destsz not greater
166*4882a593Smuzhiyun * than RSIZE_MAX, writes destsz bytes with value c into the dest object.
167*4882a593Smuzhiyun */
168*4882a593Smuzhiyun int
BCMPOSTTRAPFN(memset_s)169*4882a593Smuzhiyun BCMPOSTTRAPFN(memset_s)(void *dest, size_t destsz, int c, size_t n)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun int err = BCME_OK;
172*4882a593Smuzhiyun if ((!dest) || (((char *)dest + destsz) < (char *)dest)) {
173*4882a593Smuzhiyun err = BCME_BADARG;
174*4882a593Smuzhiyun goto exit;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun if (destsz > RSIZE_MAX) {
178*4882a593Smuzhiyun err = BCME_BADLEN;
179*4882a593Smuzhiyun goto exit;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun if (destsz < n) {
183*4882a593Smuzhiyun (void)memset(dest, c, destsz);
184*4882a593Smuzhiyun err = BCME_BADLEN;
185*4882a593Smuzhiyun goto exit;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun (void)memset(dest, c, n);
189*4882a593Smuzhiyun exit:
190*4882a593Smuzhiyun return err;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun #endif /* !__STDC_WANT_SECURE_LIB__ && !(__STDC_LIB_EXT1__ && __STDC_WANT_LIB_EXT1__) */
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun #if !defined(FREEBSD) && !defined(MACOSX) && !defined(BCM_USE_PLATFORM_STRLCPY)
195*4882a593Smuzhiyun /**
196*4882a593Smuzhiyun * strlcpy - Copy a %NUL terminated string into a sized buffer
197*4882a593Smuzhiyun * @dest: Where to copy the string to
198*4882a593Smuzhiyun * @src: Where to copy the string from
199*4882a593Smuzhiyun * @size: size of destination buffer 0 if input parameters are NOK
200*4882a593Smuzhiyun * return: string leng of src (which is always < size) on success or size on failure
201*4882a593Smuzhiyun *
202*4882a593Smuzhiyun * Compatible with *BSD: the result is always a valid
203*4882a593Smuzhiyun * NUL-terminated string that fits in the buffer (unless,
204*4882a593Smuzhiyun * of course, the buffer size is zero). It does not pad
205*4882a593Smuzhiyun * out the result like strncpy() does.
206*4882a593Smuzhiyun */
strlcpy(char * dest,const char * src,size_t size)207*4882a593Smuzhiyun size_t strlcpy(char *dest, const char *src, size_t size)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun size_t i;
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun if (dest == NULL || size == 0) {
212*4882a593Smuzhiyun return 0;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun if (src == NULL) {
216*4882a593Smuzhiyun *dest = '\0';
217*4882a593Smuzhiyun return 0;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun for (i = 0; i < size; i++) {
221*4882a593Smuzhiyun dest[i] = src[i];
222*4882a593Smuzhiyun if (dest[i] == '\0') {
223*4882a593Smuzhiyun /* success - src string copied */
224*4882a593Smuzhiyun return i;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun /* NULL terminate since not found in src */
229*4882a593Smuzhiyun dest[size - 1u] = '\0';
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun /* fail - src string truncated */
232*4882a593Smuzhiyun return size;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun #endif /* !defined(FREEBSD) && !defined(MACOSX) && !defined(BCM_USE_PLATFORM_STRLCPY) */
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun /**
237*4882a593Smuzhiyun * strlcat_s - Concatenate a %NUL terminated string with a sized buffer
238*4882a593Smuzhiyun * @dest: Where to concatenate the string to
239*4882a593Smuzhiyun * @src: Where to copy the string from
240*4882a593Smuzhiyun * @size: size of destination buffer
241*4882a593Smuzhiyun * return: string length of created string (i.e. the initial length of dest plus the length of src)
242*4882a593Smuzhiyun * not including the NUL char, up until size
243*4882a593Smuzhiyun *
244*4882a593Smuzhiyun * Unlike strncat(), strlcat() take the full size of the buffer (not just the number of bytes to
245*4882a593Smuzhiyun * copy) and guarantee to NUL-terminate the result (even when there's nothing to concat).
246*4882a593Smuzhiyun * If the length of dest string concatinated with the src string >= size, truncation occurs.
247*4882a593Smuzhiyun *
248*4882a593Smuzhiyun * Compatible with *BSD: the result is always a valid NUL-terminated string that fits in the buffer
249*4882a593Smuzhiyun * (unless, of course, the buffer size is zero).
250*4882a593Smuzhiyun *
251*4882a593Smuzhiyun * If either src or dest is not NUL-terminated, dest[size-1] will be set to NUL.
252*4882a593Smuzhiyun * If size < strlen(dest) + strlen(src), dest[size-1] will be set to NUL.
253*4882a593Smuzhiyun * If size == 0, dest[0] will be set to NUL.
254*4882a593Smuzhiyun */
255*4882a593Smuzhiyun size_t
strlcat_s(char * dest,const char * src,size_t size)256*4882a593Smuzhiyun strlcat_s(char *dest, const char *src, size_t size)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun char *d = dest;
259*4882a593Smuzhiyun const char *s = src; /* point to the start of the src string */
260*4882a593Smuzhiyun size_t n = size;
261*4882a593Smuzhiyun size_t dlen;
262*4882a593Smuzhiyun size_t bytes_to_copy = 0;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun if (dest == NULL) {
265*4882a593Smuzhiyun return 0;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun /* set d to point to the end of dest string (up to size) */
269*4882a593Smuzhiyun while (n != 0 && *d != '\0') {
270*4882a593Smuzhiyun d++;
271*4882a593Smuzhiyun n--;
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun dlen = (size_t)(d - dest);
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun if (s != NULL) {
276*4882a593Smuzhiyun size_t slen = 0;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun /* calculate src len in case it's not null-terminated */
279*4882a593Smuzhiyun n = size;
280*4882a593Smuzhiyun while (n-- != 0 && *(s + slen) != '\0') {
281*4882a593Smuzhiyun ++slen;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun n = size - dlen; /* maximum num of chars to copy */
285*4882a593Smuzhiyun if (n != 0) {
286*4882a593Smuzhiyun /* copy relevant chars (until end of src buf or given size is reached) */
287*4882a593Smuzhiyun bytes_to_copy = MIN(slen - (size_t)(s - src), n - 1);
288*4882a593Smuzhiyun (void)memcpy(d, s, bytes_to_copy);
289*4882a593Smuzhiyun d += bytes_to_copy;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun if (n == 0 && dlen != 0) {
293*4882a593Smuzhiyun --d; /* nothing to copy, but NUL-terminate dest anyway */
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun *d = '\0'; /* NUL-terminate dest */
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun return (dlen + bytes_to_copy);
298*4882a593Smuzhiyun }
299