OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include <sys/types.h> // Include something that will define __BIONIC__. | |
6 | |
7 #include "nacl_io/kernel_wrap.h" // IRT_EXT is turned on in this header. | |
8 | |
9 // The entire file is wrapped in this #if. We do this so this .cc file can be | |
10 // compiled, even on a non-bionic build. | |
11 | |
12 #if !defined(NACL_IO_IRT_EXT) && defined(__native_client__) && \ | |
13 defined(__BIONIC__) | |
14 | |
15 #include <alloca.h> | |
16 #include <assert.h> | |
17 #include <dirent.h> | |
18 #include <errno.h> | |
19 #include <irt_syscalls.h> | |
20 #include <string.h> | |
21 #include <sys/stat.h> | |
22 #include <sys/time.h> | |
23 | |
24 #include "nacl_io/kernel_intercept.h" | |
25 #include "nacl_io/kernel_wrap_real.h" | |
26 #include "nacl_io/nacl_abi_types.h" | |
27 #include "nacl_io/osmman.h" | |
28 | |
29 namespace { | |
30 | |
31 void stat_to_nacl_stat(const struct stat* buf, nacl_abi_stat* nacl_buf) { | |
32 memset(nacl_buf, 0, sizeof(struct nacl_abi_stat)); | |
33 nacl_buf->nacl_abi_st_dev = buf->st_dev; | |
34 nacl_buf->nacl_abi_st_ino = buf->st_ino; | |
35 nacl_buf->nacl_abi_st_mode = buf->st_mode; | |
36 nacl_buf->nacl_abi_st_nlink = buf->st_nlink; | |
37 nacl_buf->nacl_abi_st_uid = buf->st_uid; | |
38 nacl_buf->nacl_abi_st_gid = buf->st_gid; | |
39 nacl_buf->nacl_abi_st_rdev = buf->st_rdev; | |
40 nacl_buf->nacl_abi_st_size = buf->st_size; | |
41 nacl_buf->nacl_abi_st_blksize = buf->st_blksize; | |
42 nacl_buf->nacl_abi_st_blocks = buf->st_blocks; | |
43 nacl_buf->nacl_abi_st_atime = buf->st_atime; | |
44 nacl_buf->nacl_abi_st_mtime = buf->st_mtime; | |
45 nacl_buf->nacl_abi_st_ctime = buf->st_ctime; | |
46 } | |
47 | |
48 void nacl_stat_to_stat(const nacl_abi_stat* nacl_buf, struct stat* buf) { | |
49 memset(buf, 0, sizeof(struct stat)); | |
50 buf->st_dev = nacl_buf->nacl_abi_st_dev; | |
51 buf->st_ino = nacl_buf->nacl_abi_st_ino; | |
52 buf->st_mode = nacl_buf->nacl_abi_st_mode; | |
53 buf->st_nlink = nacl_buf->nacl_abi_st_nlink; | |
54 buf->st_uid = nacl_buf->nacl_abi_st_uid; | |
55 buf->st_gid = nacl_buf->nacl_abi_st_gid; | |
56 buf->st_rdev = nacl_buf->nacl_abi_st_rdev; | |
57 buf->st_size = nacl_buf->nacl_abi_st_size; | |
58 buf->st_blksize = nacl_buf->nacl_abi_st_blksize; | |
59 buf->st_blocks = nacl_buf->nacl_abi_st_blocks; | |
60 buf->st_atime = nacl_buf->nacl_abi_st_atime; | |
61 buf->st_mtime = nacl_buf->nacl_abi_st_mtime; | |
62 buf->st_ctime = nacl_buf->nacl_abi_st_ctime; | |
63 } | |
64 | |
65 } // namespace | |
66 | |
67 static const int d_name_shift = offsetof (dirent, d_name) - | |
68 offsetof (struct nacl_abi_dirent, nacl_abi_d_name); | |
69 | |
70 EXTERN_C_BEGIN | |
71 | |
72 // Macro to get the REAL function pointer | |
73 #define REAL(name) __nacl_irt_##name##_real | |
74 | |
75 // Macro to get the WRAP function | |
76 #define WRAP(name) __nacl_irt_##name##_wrap | |
77 | |
78 // Declare REAL function pointer. | |
79 #define DECLARE_REAL_PTR(name) typeof(__nacl_irt_##name) REAL(name); | |
80 | |
81 // Assign the REAL function pointer. | |
82 #define ASSIGN_REAL_PTR(name) REAL(name) = __nacl_irt_##name; | |
83 | |
84 // Switch IRT's pointer to the REAL pointer | |
85 #define USE_REAL(name) __nacl_irt_##name = (typeof(__nacl_irt_##name))REAL(name) | |
86 | |
87 // Switch IRT's pointer to the WRAP function | |
88 #define USE_WRAP(name) __nacl_irt_##name = (typeof(__nacl_irt_##name))WRAP(name) | |
89 | |
90 #define EXPAND_SYMBOL_LIST_OPERATION(OP) \ | |
91 OP(chdir); \ | |
92 OP(close); \ | |
93 OP(dup); \ | |
94 OP(dup2); \ | |
95 OP(exit); \ | |
96 OP(fchdir); \ | |
97 OP(fchmod); \ | |
98 OP(fdatasync); \ | |
99 OP(fstat); \ | |
100 OP(fsync); \ | |
101 OP(getcwd); \ | |
102 OP(getdents); \ | |
103 OP(isatty); \ | |
104 OP(lstat); \ | |
105 OP(mkdir); \ | |
106 OP(mmap); \ | |
107 OP(munmap); \ | |
108 OP(open); \ | |
109 OP(open_resource); \ | |
110 OP(poll); \ | |
111 OP(read); \ | |
112 OP(readlink); \ | |
113 OP(rmdir); \ | |
114 OP(seek); \ | |
115 OP(stat); \ | |
116 OP(truncate); \ | |
117 OP(write); | |
118 | |
119 EXPAND_SYMBOL_LIST_OPERATION(DECLARE_REAL_PTR); | |
120 | |
121 int WRAP(chdir)(const char* pathname) { | |
122 ERRNO_RTN(ki_chdir(pathname)); | |
123 } | |
124 | |
125 int WRAP(close)(int fd) { | |
126 ERRNO_RTN(ki_close(fd)); | |
127 } | |
128 | |
129 int WRAP(dup)(int fd, int* newfd) NOTHROW { | |
130 *newfd = ki_dup(fd); | |
131 ERRNO_RTN(*newfd); | |
132 } | |
133 | |
134 int WRAP(dup2)(int fd, int newfd) NOTHROW { | |
135 ERRNO_RTN(ki_dup2(fd, newfd)); | |
136 } | |
137 | |
138 void WRAP(exit)(int status) { | |
139 ki_exit(status); | |
140 } | |
141 | |
142 int WRAP(fchdir)(int fd) NOTHROW { | |
143 ERRNO_RTN(ki_fchdir(fd)); | |
144 } | |
145 | |
146 int WRAP(fchmod)(int fd, mode_t mode) NOTHROW { | |
147 ERRNO_RTN(ki_fchmod(fd, mode)); | |
148 } | |
149 | |
150 int WRAP(fdatasync)(int fd) NOTHROW { | |
151 ERRNO_RTN(ki_fdatasync(fd)); | |
152 } | |
153 | |
154 int WRAP(fstat)(int fd, struct nacl_abi_stat* nacl_buf) { | |
155 struct stat buf; | |
156 memset(&buf, 0, sizeof(struct stat)); | |
157 int res = ki_fstat(fd, &buf); | |
158 RTN_ERRNO_IF(res < 0); | |
159 stat_to_nacl_stat(&buf, nacl_buf); | |
160 return 0; | |
161 } | |
162 | |
163 int WRAP(fsync)(int fd) NOTHROW { | |
164 ERRNO_RTN(ki_fsync(fd)); | |
165 } | |
166 | |
167 int WRAP(getcwd)(char* buf, size_t size) { | |
168 RTN_ERRNO_IF(ki_getcwd(buf, size) == NULL); | |
169 return 0; | |
170 } | |
171 | |
172 int WRAP(getdents)(int fd, dirent* nacl_buf, size_t nacl_count, size_t* nread) { | |
173 int nacl_offset = 0; | |
174 // "buf" contains dirent(s); "nacl_buf" contains nacl_abi_dirent(s). | |
175 // nacl_abi_dirent(s) are smaller than dirent(s), so nacl_count bytes buffer | |
176 // is enough | |
177 char* buf = (char*)alloca(nacl_count); | |
178 int offset = 0; | |
179 int count; | |
180 | |
181 count = ki_getdents(fd, (dirent*)buf, nacl_count); | |
182 RTN_ERRNO_IF(count < 0); | |
183 | |
184 while (offset < count) { | |
185 dirent* d = (dirent*)(buf + offset); | |
186 nacl_abi_dirent* nacl_d = (nacl_abi_dirent*)((char*)nacl_buf + nacl_offset); | |
187 nacl_d->nacl_abi_d_ino = d->d_ino; | |
188 nacl_d->nacl_abi_d_off = d->d_off; | |
189 nacl_d->nacl_abi_d_reclen = d->d_reclen - d_name_shift; | |
190 size_t d_name_len = d->d_reclen - offsetof(dirent, d_name); | |
191 memcpy(nacl_d->nacl_abi_d_name, d->d_name, d_name_len); | |
192 | |
193 offset += d->d_reclen; | |
194 nacl_offset += nacl_d->nacl_abi_d_reclen; | |
195 } | |
196 | |
197 *nread = nacl_offset; | |
198 return 0; | |
199 } | |
200 | |
201 int WRAP(isatty)(int fd, int* result) { | |
202 *result = ki_isatty(fd); | |
203 RTN_ERRNO_IF(*result == 0); | |
204 return 0; | |
205 } | |
206 | |
207 int WRAP(lstat)(const char* path, struct nacl_abi_stat* nacl_buf) { | |
208 struct stat buf; | |
209 memset(&buf, 0, sizeof(struct stat)); | |
210 int res = ki_lstat(path, &buf); | |
211 RTN_ERRNO_IF(res < 0); | |
212 stat_to_nacl_stat(&buf, nacl_buf); | |
213 return 0; | |
214 } | |
215 | |
216 int WRAP(mkdir)(const char* pathname, mode_t mode) { | |
217 ERRNO_RTN(ki_mkdir(pathname, mode)); | |
218 } | |
219 | |
220 int WRAP(mmap)(void** addr, | |
221 size_t length, | |
222 int prot, | |
223 int flags, | |
224 int fd, | |
225 int64_t offset) { | |
226 if (flags & MAP_ANONYMOUS) | |
227 return REAL(mmap)(addr, length, prot, flags, fd, offset); | |
228 | |
229 *addr = ki_mmap(*addr, length, prot, flags, fd, offset); | |
230 RTN_ERRNO_IF(*addr == (void*)-1) | |
231 return 0; | |
232 } | |
233 | |
234 int WRAP(munmap)(void* addr, size_t length) { | |
235 // Always let the real munmap run on the address range. It is not an error if | |
236 // there are no mapped pages in that range. | |
237 ki_munmap(addr, length); | |
238 return REAL(munmap)(addr, length); | |
239 } | |
240 | |
241 int WRAP(open)(const char* pathname, int oflag, mode_t mode, int* newfd) { | |
242 *newfd = ki_open(pathname, oflag, mode); | |
243 ERRNO_RTN(*newfd); | |
244 } | |
245 | |
246 int WRAP(open_resource)(const char* file, int* fd) { | |
247 *fd = ki_open_resource(file); | |
248 ERRNO_RTN(*fd); | |
249 } | |
250 | |
251 int WRAP(poll)(struct pollfd* fds, nfds_t nfds, int timeout, int* count) { | |
252 *count = ki_poll(fds, nfds, timeout); | |
253 ERRNO_RTN(*count); | |
254 } | |
255 | |
256 int WRAP(read)(int fd, void* buf, size_t count, size_t* nread) { | |
257 ssize_t signed_nread = ki_read(fd, buf, count); | |
258 *nread = static_cast<size_t>(signed_nread); | |
259 ERRNO_RTN(signed_nread); | |
260 } | |
261 | |
262 int WRAP(readlink)(const char* path, char* buf, size_t count, size_t* nread) { | |
263 ssize_t signed_nread = ki_readlink(path, buf, count); | |
264 *nread = static_cast<size_t>(signed_nread); | |
265 ERRNO_RTN(signed_nread); | |
266 } | |
267 | |
268 int WRAP(rmdir)(const char* pathname) { | |
269 ERRNO_RTN(ki_rmdir(pathname)); | |
270 } | |
271 | |
272 int WRAP(seek)(int fd, off64_t offset, int whence, int64_t* new_offset) { | |
273 *new_offset = ki_lseek(fd, offset, whence); | |
274 ERRNO_RTN(*new_offset); | |
275 } | |
276 | |
277 int WRAP(select)(int nfds, | |
278 fd_set* readfds, | |
279 fd_set* writefds, | |
280 fd_set* exceptfds, | |
281 struct timeval* timeout, | |
282 int* count) { | |
283 *count = ki_select(nfds, readfds, writefds, exceptfds, timeout); | |
284 ERRNO_RTN(*count); | |
285 } | |
286 | |
287 int WRAP(stat)(const char* pathname, struct nacl_abi_stat* nacl_buf) { | |
288 struct stat buf; | |
289 memset(&buf, 0, sizeof(struct stat)); | |
290 int res = ki_stat(pathname, &buf); | |
291 RTN_ERRNO_IF(res < 0); | |
292 stat_to_nacl_stat(&buf, nacl_buf); | |
293 return 0; | |
294 } | |
295 | |
296 int WRAP(truncate)(const char* name, int64_t len) { | |
297 ERRNO_RTN(ki_truncate(name, len)); | |
298 } | |
299 | |
300 int WRAP(write)(int fd, const void* buf, size_t count, size_t* nwrote) { | |
301 ssize_t signed_nwrote = ki_write(fd, buf, count); | |
302 *nwrote = static_cast<size_t>(signed_nwrote); | |
303 ERRNO_RTN(signed_nwrote); | |
304 } | |
305 | |
306 static void assign_real_pointers() { | |
307 static bool assigned = false; | |
308 if (!assigned) { | |
309 EXPAND_SYMBOL_LIST_OPERATION(ASSIGN_REAL_PTR) | |
310 assigned = true; | |
311 } | |
312 } | |
313 | |
314 #define CHECK_REAL(func) \ | |
315 if (!REAL(func)) { \ | |
316 assign_real_pointers(); \ | |
317 if (!REAL(func)) \ | |
318 return ENOSYS; \ | |
319 } | |
320 | |
321 // "real" functions, i.e. the unwrapped original functions. | |
322 | |
323 int _real_close(int fd) { | |
324 CHECK_REAL(close); | |
325 return REAL(close)(fd); | |
326 } | |
327 | |
328 void _real_exit(int status) { | |
329 REAL(exit)(status); | |
330 } | |
331 | |
332 int _real_fchdir(int fd) { | |
333 CHECK_REAL(fchdir); | |
334 return REAL(fchdir)(fd); | |
335 } | |
336 | |
337 int _real_fchmod(int fd, mode_t mode) { | |
338 CHECK_REAL(fchmod); | |
339 return REAL(fchmod)(fd, mode); | |
340 } | |
341 | |
342 int _real_fdatasync(int fd) { | |
343 CHECK_REAL(fdatasync); | |
344 return REAL(fdatasync)(fd); | |
345 } | |
346 | |
347 int _real_fstat(int fd, struct stat* buf) { | |
348 struct nacl_abi_stat st; | |
349 CHECK_REAL(fstat); | |
350 | |
351 int err = REAL(fstat)(fd, (struct stat*)&st); | |
352 if (err) { | |
353 errno = err; | |
354 return -1; | |
355 } | |
356 | |
357 nacl_stat_to_stat(&st, buf); | |
358 return 0; | |
359 } | |
360 | |
361 int _real_fsync(int fd) { | |
362 CHECK_REAL(fsync); | |
363 return REAL(fsync)(fd); | |
364 } | |
365 | |
366 int _real_getdents(int fd, void* buf, size_t count, size_t* nread) { | |
367 // "buf" contains dirent(s); "nacl_buf" contains nacl_abi_dirent(s). | |
368 // See WRAP(getdents) above. | |
369 char* nacl_buf = (char*)alloca(count); | |
370 size_t offset = 0; | |
371 size_t nacl_offset = 0; | |
372 size_t nacl_nread; | |
373 CHECK_REAL(getdents); | |
374 int err = REAL(getdents)(fd, (dirent*)nacl_buf, count, &nacl_nread); | |
375 if (err) | |
376 return err; | |
377 | |
378 while (nacl_offset < nacl_nread) { | |
379 dirent* d = (dirent*)((char*)buf + offset); | |
380 nacl_abi_dirent* nacl_d = (nacl_abi_dirent*)(nacl_buf + nacl_offset); | |
381 d->d_ino = nacl_d->nacl_abi_d_ino; | |
382 d->d_off = nacl_d->nacl_abi_d_off; | |
383 d->d_reclen = nacl_d->nacl_abi_d_reclen + d_name_shift; | |
384 size_t d_name_len = | |
385 nacl_d->nacl_abi_d_reclen - offsetof(nacl_abi_dirent, nacl_abi_d_name); | |
386 memcpy(d->d_name, nacl_d->nacl_abi_d_name, d_name_len); | |
387 | |
388 offset += d->d_reclen; | |
389 offset += nacl_d->nacl_abi_d_reclen; | |
390 } | |
391 | |
392 *nread = offset; | |
393 return 0; | |
394 } | |
395 | |
396 int _real_isatty(int fd, int* result) { | |
397 *result = isatty(fd); | |
398 return *result ? 0 : -1; | |
399 } | |
400 | |
401 int _real_lseek(int fd, int64_t offset, int whence, int64_t* new_offset) { | |
402 CHECK_REAL(seek); | |
403 nacl_abi_off_t nacl_new_offs; | |
404 int ret = REAL(seek)(fd, offset, whence, &nacl_new_offs); | |
405 *new_offset = static_cast<off_t>(nacl_new_offs); | |
406 return ret; | |
407 } | |
408 | |
409 int _real_lstat(const char* path, struct stat* buf) { | |
410 struct nacl_abi_stat st; | |
411 CHECK_REAL(lstat); | |
412 | |
413 int err = REAL(lstat)(path, (struct stat*)&st); | |
414 if (err) { | |
415 errno = err; | |
416 return -1; | |
417 } | |
418 | |
419 nacl_stat_to_stat(&st, buf); | |
420 return 0; | |
421 } | |
422 | |
423 int _real_mkdir(const char* pathname, mode_t mode) { | |
424 CHECK_REAL(mkdir); | |
425 return REAL(mkdir)(pathname, mode); | |
426 } | |
427 | |
428 int _real_mmap(void** addr, | |
429 size_t length, | |
430 int prot, | |
431 int flags, | |
432 int fd, | |
433 int64_t offset) { | |
434 CHECK_REAL(mmap); | |
435 return REAL(mmap)(addr, length, prot, flags, fd, offset); | |
436 } | |
437 | |
438 int _real_munmap(void* addr, size_t length) { | |
439 CHECK_REAL(munmap); | |
440 return REAL(munmap)(addr, length); | |
441 } | |
442 | |
443 int _real_open(const char* pathname, int oflag, mode_t mode, int* newfd) { | |
444 CHECK_REAL(open); | |
445 return REAL(open)(pathname, oflag, mode, newfd); | |
446 } | |
447 | |
448 int _real_open_resource(const char* file, int* fd) { | |
449 CHECK_REAL(open_resource); | |
450 return REAL(open_resource)(file, fd); | |
451 } | |
452 | |
453 int _real_read(int fd, void* buf, size_t count, size_t* nread) { | |
454 CHECK_REAL(read); | |
455 return REAL(read)(fd, buf, count, nread); | |
456 } | |
457 | |
458 int _real_readlink(const char* path, char* buf, size_t count, size_t* nread) { | |
459 CHECK_REAL(readlink); | |
460 return REAL(readlink)(path, buf, count, nread); | |
461 } | |
462 | |
463 int _real_rmdir(const char* pathname) { | |
464 CHECK_REAL(rmdir); | |
465 return REAL(rmdir)(pathname); | |
466 } | |
467 | |
468 int _real_truncate(const char* pathname, int64_t len) { | |
469 CHECK_REAL(truncate); | |
470 return REAL(truncate)(pathname, len); | |
471 } | |
472 | |
473 int _real_write(int fd, const void* buf, size_t count, size_t* nwrote) { | |
474 CHECK_REAL(write); | |
475 return REAL(write)(fd, buf, count, nwrote); | |
476 } | |
477 | |
478 int _real_getcwd(char* pathname, size_t len) { | |
479 CHECK_REAL(getcwd); | |
480 return REAL(getcwd)(pathname, len); | |
481 } | |
482 | |
483 static bool s_wrapped = false; | |
484 | |
485 void kernel_wrap_init() { | |
486 if (!s_wrapped) { | |
487 assign_real_pointers(); | |
488 EXPAND_SYMBOL_LIST_OPERATION(USE_WRAP) | |
489 s_wrapped = true; | |
490 } | |
491 } | |
492 | |
493 void kernel_wrap_uninit() { | |
494 if (s_wrapped) { | |
495 EXPAND_SYMBOL_LIST_OPERATION(USE_REAL) | |
496 s_wrapped = false; | |
497 } | |
498 } | |
499 | |
500 EXTERN_C_END | |
501 | |
502 #endif // defined(__native_client__) && defined(__BIONIC__) | |
OLD | NEW |