1 /*
2 * Copyright (c) 2022 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 #define _GNU_SOURCE
16 #define _BSD_SOURCE
17
18 #include <fortify/fortify.h>
19 #include <fcntl.h>
20 #include <limits.h>
21 #include <poll.h>
22 #include <stdarg.h>
23 #include <stdbool.h>
24 #include <stddef.h>
25 #include <stdint.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <sys/socket.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33
34 #define FILE_MODE_ALL (0777)
35
__fortify_error(const char * info,...)36 void __fortify_error(const char* info, ...)
37 {
38 va_list ap;
39 va_start(ap, info);
40 fprintf(stderr, FORTIFY_RUNTIME_ERROR_PREFIX);
41 vfprintf(stderr, info, ap);
42 va_end(ap);
43 abort();
44 }
45
__force_O_LARGEFILE(int flags)46 static inline int __force_O_LARGEFILE(int flags)
47 {
48 #if defined(__LP64__)
49 return flags; // No need, and aarch64's strace gets confused.
50 #else
51 return flags | O_LARGEFILE;
52 #endif
53 }
54
__needs_mode(int flags)55 static inline bool __needs_mode(int flags)
56 {
57 return ((flags & O_CREAT) == O_CREAT) || ((flags & O_TMPFILE) == O_TMPFILE);
58 }
59
__open_chk(const char * pathname,int flags)60 int __open_chk(const char* pathname, int flags)
61 {
62 if (__needs_mode(flags)) {
63 __fortify_error("open: " OPEN_TOO_FEW_ARGS_ERROR);
64 }
65 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(open)(pathname, __force_O_LARGEFILE(flags), 0);
66 }
67
__openat_chk(int fd,const char * pathname,int flags)68 int __openat_chk(int fd, const char* pathname, int flags)
69 {
70 if (__needs_mode(flags)) {
71 __fortify_error("openat: " OPEN_TOO_FEW_ARGS_ERROR);
72 }
73 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(openat)(fd, pathname, __force_O_LARGEFILE(flags), 0);
74 }
75
76 #if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE)
__open64_chk(const char * pathname,int flags)77 int __open64_chk(const char* pathname, int flags)
78 {
79 if (__needs_mode(flags)) {
80 __fortify_error("open64: " OPEN_TOO_FEW_ARGS_ERROR);
81 }
82 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(open64)(pathname, __force_O_LARGEFILE(flags), 0);
83 }
84
__openat64_chk(int fd,const char * pathname,int flags)85 int __openat64_chk(int fd, const char* pathname, int flags)
86 {
87 if (__needs_mode(flags)) {
88 __fortify_error("openat64: " OPEN_TOO_FEW_ARGS_ERROR);
89 }
90 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(openat64)(fd, pathname, __force_O_LARGEFILE(flags), 0);
91 }
92 #endif
93
__diagnose_pollfd_array(const char * fn,size_t fds_size,nfds_t fd_count)94 static inline void __diagnose_pollfd_array(const char* fn, size_t fds_size, nfds_t fd_count)
95 {
96 size_t pollfd_array_length = fds_size / sizeof(struct pollfd);
97 if (__DIAGNOSE_PREDICT_FALSE(pollfd_array_length < fd_count)) {
98 __fortify_error("%s: %zu-element pollfd array too small for %u fds\n",
99 fn, pollfd_array_length, fd_count);
100 }
101 }
102
__poll_chk(struct pollfd * fds,nfds_t fd_count,int timeout,size_t fds_size)103 int __poll_chk(struct pollfd* fds, nfds_t fd_count, int timeout, size_t fds_size)
104 {
105 __diagnose_pollfd_array("poll", fds_size, fd_count);
106 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(poll)(fds, fd_count, timeout);
107 }
108
109 #ifdef _GNU_SOURCE
__ppoll_chk(struct pollfd * fds,nfds_t fd_count,const struct timespec * timeout,const sigset_t * mask,size_t fds_size)110 int __ppoll_chk(struct pollfd* fds, nfds_t fd_count, const struct timespec* timeout,
111 const sigset_t* mask, size_t fds_size)
112 {
113 __diagnose_pollfd_array("ppoll", fds_size, fd_count);
114 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(ppoll)(fds, fd_count, timeout, mask);
115 }
116 #endif
117
__diagnose_buffer_access(const char * fn,const char * action,size_t claim,size_t actual)118 static inline void __diagnose_buffer_access(const char* fn, const char* action,
119 size_t claim, size_t actual)
120 {
121 if (__DIAGNOSE_PREDICT_FALSE(claim > actual)) {
122 __fortify_error("%s: avoid %zu-byte %s %zu-byte buffer\n", fn, claim, action, actual);
123 }
124 }
125
__recvfrom_chk(int socket,void * buf,size_t len,size_t buf_size,int flags,struct sockaddr * src_addr,socklen_t * addrlen)126 ssize_t __recvfrom_chk(int socket, void* buf, size_t len, size_t buf_size,
127 int flags, struct sockaddr* src_addr, socklen_t* addrlen)
128 {
129 __diagnose_buffer_access("recvfrom", "write into", len, buf_size);
130 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(recvfrom)(socket, buf, len, flags, src_addr, addrlen);
131 }
132
__sendto_chk(int socket,const void * buf,size_t len,size_t buflen,int flags,const struct sockaddr * dest_addr,socklen_t addrlen)133 ssize_t __sendto_chk(int socket, const void* buf, size_t len, size_t buflen,
134 int flags, const struct sockaddr* dest_addr, socklen_t addrlen)
135 {
136 __diagnose_buffer_access("sendto", "read from", len, buflen);
137 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(sendto)(socket, buf, len, flags, dest_addr, addrlen);
138 }
139
__recv_chk(int socket,void * buf,size_t len,size_t buf_size,int flags)140 ssize_t __recv_chk(int socket, void* buf, size_t len, size_t buf_size, int flags)
141 {
142 __diagnose_buffer_access("recv", "write into", len, buf_size);
143 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(recv)(socket, buf, len, flags);
144 }
145
__send_chk(int socket,const void * buf,size_t len,size_t buflen,int flags)146 ssize_t __send_chk(int socket, const void* buf, size_t len, size_t buflen, int flags)
147 {
148 __diagnose_buffer_access("send", "read from", len, buflen);
149 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(send)(socket, buf, len, flags);
150 }
151
__umask_chk(mode_t mode)152 mode_t __umask_chk(mode_t mode)
153 {
154 if (__DIAGNOSE_PREDICT_FALSE((mode & FILE_MODE_ALL) != mode)) {
155 __fortify_error("umask: called with invalid mask %o\n", mode);
156 }
157 return __umask_real(mode);
158 }
159
160 // Runtime implementation of the string-dependent interface.
161 // Used directly by the compiler, not in a header file.
__diagnose_count(const char * fn,const char * identifier,size_t value)162 static inline void __diagnose_count(const char *fn, const char *identifier, size_t value)
163 {
164 if (__DIAGNOSE_PREDICT_FALSE(value > LONG_MAX)) {
165 __fortify_error("%s: %s %zu > SSIZE_MAX\n", fn, identifier, value);
166 }
167 }
168
__strlen_chk(const char * s,size_t s_len)169 size_t __strlen_chk(const char* s, size_t s_len)
170 {
171 size_t ret = __DIAGNOSE_CALL_BYPASSING_FORTIFY(strlen)(s);
172 if (__DIAGNOSE_PREDICT_FALSE(ret >= s_len)) {
173 __fortify_error("strlen: diagnose read exceed end of buffer\n");
174 }
175 return ret;
176 }
177
__strncat_chk(char * dest,const char * src,size_t len,size_t dst_buf_size)178 char* __strncat_chk(char* dest, const char* src, size_t len, size_t dst_buf_size)
179 {
180 size_t src_len = strlen(src) + strlen(dest);
181 __diagnose_buffer_access("strncat", "write into", src_len, dst_buf_size);
182 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(strncat)(dest, src, len);
183 }
184
__strcat_chk(char * dest,const char * src,size_t dst_buf_size)185 char* __strcat_chk(char* dest, const char* src, size_t dst_buf_size)
186 {
187 size_t src_len = strlen(src) + strlen(dest);
188 __diagnose_buffer_access("strcat", "write into", src_len, dst_buf_size);
189 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(strcat)(dest, src);
190 }
191
__strcpy_chk(char * dest,const char * src,size_t dst_len)192 char* __strcpy_chk(char* dest, const char* src, size_t dst_len)
193 {
194 size_t src_len = strlen(src) + 1;
195 __diagnose_buffer_access("strcpy", "write into", src_len, dst_len);
196 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(strcpy)(dest, src);
197 }
198
__memmove_chk(void * dest,const void * src,size_t len,size_t dst_len)199 void* __memmove_chk(void* dest, const void* src, size_t len, size_t dst_len)
200 {
201 __diagnose_buffer_access("memmove", "write into", len, dst_len);
202 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(memmove)(dest, src, len);
203 }
204
__memcpy_chk(void * dest,const void * src,size_t count,size_t dst_len)205 void* __memcpy_chk(void* dest, const void* src, size_t count, size_t dst_len)
206 {
207 __diagnose_count("memcpy", "count", count);
208 __diagnose_buffer_access("memcpy", "write into", count, dst_len);
209 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(memcpy)(dest, src, count);
210 }
211
212 #ifdef _GNU_SOURCE
__mempcpy_chk(void * dest,const void * src,size_t count,size_t dst_len)213 void* __mempcpy_chk(void* dest, const void* src, size_t count, size_t dst_len)
214 {
215 __diagnose_count("mempcpy", "count", count);
216 __diagnose_buffer_access("mempcpy", "write into", count, dst_len);
217 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(mempcpy)(dest, src, count);
218 }
219 #endif
220
__stpcpy_chk(char * dest,const char * src,size_t dst_len)221 char* __stpcpy_chk(char* dest, const char* src, size_t dst_len)
222 {
223 size_t src_len = strlen(src);
224 __diagnose_buffer_access("stpcpy", "write into", src_len, dst_len);
225 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(stpcpy)(dest, src);
226 }
227
__memchr_chk(const void * s,int c,size_t n,size_t actual_size)228 void* __memchr_chk(const void* s, int c, size_t n, size_t actual_size)
229 {
230 __diagnose_buffer_access("memchr", "read from", n, actual_size);
231 void* const_cast_s = s;
232 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(memchr)(const_cast_s, c, n);
233 }
234
__stpncpy_chk(char * dest,const char * src,size_t len,size_t dst_len)235 char* __stpncpy_chk(char* dest, const char* src, size_t len, size_t dst_len)
236 {
237 __diagnose_buffer_access("stpncpy", "write into", len, dst_len);
238 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(stpncpy)(dest, src, len);
239 }
240
__strncpy_chk(char * dest,const char * src,size_t len,size_t dst_len)241 char *__strncpy_chk(char *dest, const char *src, size_t len, size_t dst_len)
242 {
243 __diagnose_buffer_access("strncpy", "write into", len, dst_len);
244 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(strncpy)(dest, src, len);
245 }
246
__memset_chk(void * dest,int byte,size_t count,size_t dst_len)247 void *__memset_chk(void *dest, int byte, size_t count, size_t dst_len)
248 {
249 __diagnose_count("memset", "count", count);
250 __diagnose_buffer_access("memset", "write into", count, dst_len);
251 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(memset)(dest, byte, count);
252 }
253
254 #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
__strlcpy_chk(char * dest,const char * src,size_t supplied_size,size_t dst_len_from_compiler)255 size_t __strlcpy_chk(char *dest, const char *src,
256 size_t supplied_size, size_t dst_len_from_compiler)
257 {
258 __diagnose_buffer_access("strlcpy", "write into", supplied_size, dst_len_from_compiler);
259 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(strlcpy)(dest, src, supplied_size);
260 }
261
__strlcat_chk(char * dest,const char * src,size_t supplied_size,size_t dst_len_from_compiler)262 size_t __strlcat_chk(char *dest, const char *src,
263 size_t supplied_size, size_t dst_len_from_compiler)
264 {
265 __diagnose_buffer_access("strlcat", "write into", supplied_size, dst_len_from_compiler);
266 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(strlcat)(dest, src, supplied_size);
267 }
268 #endif
269
__strchr_chk(const char * s,int c,size_t s_len)270 char* __strchr_chk(const char *s, int c, size_t s_len)
271 {
272 if (s_len == 0) {
273 __fortify_error("strchr: avoid read exceed end of buffer\n");
274 }
275 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(strchr)(s, c);
276 }
277
__strrchr_chk(const char * s,int c,size_t s_len)278 char *__strrchr_chk(const char *s, int c, size_t s_len)
279 {
280 if (s_len == 0) {
281 __fortify_error("strrchr: avoid read exceed end of buffer\n");
282 }
283 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(strrchr)(s, c);
284 }
285
286 #ifdef _GNU_SOURCE
__memrchr_chk(const void * s,int c,size_t n,size_t actual_size)287 void* __memrchr_chk(const void *s, int c, size_t n, size_t actual_size)
288 {
289 __diagnose_buffer_access("memrchr", "read from", n, actual_size);
290 void *const_cast_s = s;
291 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(memrchr)(const_cast_s, c, n);
292 }
293 #endif
294
__getcwd_chk(char * buf,size_t len,size_t actual_size)295 char* __getcwd_chk(char* buf, size_t len, size_t actual_size)
296 {
297 __diagnose_buffer_access("getcwd", "write into", len, actual_size);
298 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(getcwd)(buf, len);
299 }
300
__pread_chk(int fd,void * buf,size_t count,off_t offset,size_t buf_size)301 ssize_t __pread_chk(int fd, void* buf, size_t count, off_t offset, size_t buf_size)
302 {
303 __diagnose_count("pread", "count", count);
304 __diagnose_buffer_access("pread", "write into", count, buf_size);
305 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(pread)(fd, buf, count, offset);
306 }
307
__pwrite_chk(int fd,const void * buf,size_t count,off_t offset,size_t buf_size)308 ssize_t __pwrite_chk(int fd, const void* buf, size_t count, off_t offset, size_t buf_size)
309 {
310 __diagnose_count("pwrite", "count", count);
311 __diagnose_buffer_access("pwrite", "read from", count, buf_size);
312 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(pwrite)(fd, buf, count, offset);
313 }
314
__read_chk(int fd,void * buf,size_t count,size_t buf_size)315 ssize_t __read_chk(int fd, void* buf, size_t count, size_t buf_size)
316 {
317 __diagnose_count("read", "count", count);
318 __diagnose_buffer_access("read", "write into", count, buf_size);
319 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(read)(fd, buf, count);
320 }
321
__write_chk(int fd,const void * buf,size_t count,size_t buf_size)322 ssize_t __write_chk(int fd, const void* buf, size_t count, size_t buf_size)
323 {
324 __diagnose_count("write", "count", count);
325 __diagnose_buffer_access("write", "read from", count, buf_size);
326 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(write)(fd, buf, count);
327 }
328
__readlink_chk(const char * path,char * buf,size_t size,size_t buf_size)329 ssize_t __readlink_chk(const char* path, char* buf, size_t size, size_t buf_size)
330 {
331 __diagnose_count("readlink", "size", size);
332 __diagnose_buffer_access("readlink", "write into", size, buf_size);
333 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(readlink)(path, buf, size);
334 }
335
__readlinkat_chk(int dirfd,const char * path,char * buf,size_t size,size_t buf_size)336 ssize_t __readlinkat_chk(int dirfd, const char* path, char* buf, size_t size, size_t buf_size)
337 {
338 __diagnose_count("readlinkat", "size", size);
339 __diagnose_buffer_access("readlinkat", "write into", size, buf_size);
340 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(readlinkat)(dirfd, path, buf, size);
341 }
342
__fread_chk(void * buf,size_t size,size_t count,FILE * stream,size_t buf_size)343 size_t __fread_chk(void* buf, size_t size, size_t count, FILE* stream, size_t buf_size)
344 {
345 size_t total;
346 if (__DIAGNOSE_PREDICT_FALSE(__DIAGNOSE__SIZE_MUL_OVERFLOW(size, count, &total))) {
347 // overflow: trigger the error path in fread
348 return fread(buf, size, count, stream);
349 }
350 __diagnose_buffer_access("fread", "write into", total, buf_size);
351 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(fread)(buf, size, count, stream);
352 }
353
__fwrite_chk(const void * buf,size_t size,size_t count,FILE * stream,size_t buf_size)354 size_t __fwrite_chk(const void* buf, size_t size, size_t count, FILE* stream, size_t buf_size)
355 {
356 size_t total;
357 if (__DIAGNOSE_PREDICT_FALSE(__DIAGNOSE__SIZE_MUL_OVERFLOW(size, count, &total))) {
358 // overflow: trigger the error path in fwrite
359 return fwrite(buf, size, count, stream);
360 }
361 __diagnose_buffer_access("fwrite", "read from", total, buf_size);
362 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(fwrite)(buf, size, count, stream);
363 }
364
__fgets_chk(char * dest,int supplied_size,FILE * stream,size_t dst_len_from_compiler)365 char* __fgets_chk(char* dest, int supplied_size, FILE* stream, size_t dst_len_from_compiler)
366 {
367 __diagnose_buffer_access("fgets", "write into", supplied_size, dst_len_from_compiler);
368 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(fgets)(dest, supplied_size, stream);
369 }
370
__vsnprintf_chk(char * dest,size_t supplied_size,int flags,size_t dst_len_from_compiler,const char * format,va_list va)371 int __vsnprintf_chk(char* dest, size_t supplied_size, int flags,
372 size_t dst_len_from_compiler, const char* format, va_list va)
373 {
374 __diagnose_buffer_access("vsnprintf", "write into", supplied_size, dst_len_from_compiler);
375 return __DIAGNOSE_CALL_BYPASSING_FORTIFY(vsnprintf)(dest, supplied_size, format, va);
376 }
377
__vsprintf_chk(char * dest,int flags,size_t dst_len_from_compiler,const char * format,va_list va)378 int __vsprintf_chk(char* dest, int flags,
379 size_t dst_len_from_compiler, const char* format, va_list va)
380 {
381 // The compiler has SIZE_MAX, But vsnprintf cannot use such a large size.
382 int result = __DIAGNOSE_CALL_BYPASSING_FORTIFY(vsnprintf)(dest,
383 dst_len_from_compiler == SIZE_MAX ? SSIZE_MAX : dst_len_from_compiler,
384 format, va);
385
386 // Attempts to find out after the fact fail.
387 __diagnose_buffer_access("vsprintf", "write into", result + 1, dst_len_from_compiler);
388 return result;
389 }
390 #undef SSIZE_MAX
391 #undef SIZE_MAX
392
__snprintf_chk(char * dest,size_t supplied_size,int flags,size_t dst_len_from_compiler,const char * format,...)393 int __snprintf_chk(char* dest, size_t supplied_size, int flags,
394 size_t dst_len_from_compiler, const char* format, ...)
395 {
396 va_list va;
397 va_start(va, format);
398 int result = __vsnprintf_chk(dest, supplied_size, flags, dst_len_from_compiler, format, va);
399 va_end(va);
400 return result;
401 }
402
__sprintf_chk(char * dest,int flags,size_t dst_len_from_compiler,const char * format,...)403 int __sprintf_chk(char* dest, int flags, size_t dst_len_from_compiler, const char* format, ...)
404 {
405 va_list va;
406 va_start(va, format);
407 int result = __vsprintf_chk(dest, flags, dst_len_from_compiler, format, va);
408 va_end(va);
409 return result;
410 }
411