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