| # Copyright 2017 syzkaller project authors. All rights reserved. |
| # Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. |
| |
| # These descriptions rely on binderfs being enabled and creating at least binder0 |
| # and binder1 devices right after a mount. |
| # "binder,hwbinder,vndbinder" devices are also supported; this is the kconfig default |
| # and it's what's used on real Android devices (the main user of binder). |
| # Description assumes CONFIG_ANDROID_BINDER_IPC_32BIT is not set. |
| |
| include <linux/android/binder.h> |
| include <linux/fcntl.h> |
| |
| resource fd_binder[fd] |
| resource binder_ptr[int64]: 0 |
| |
| # What's the difference between these node and handle? Do they mean the same? |
| type binder_node int64[0:3] |
| type binder_handle int32[0:3] |
| # It seems that cookies are only checked for inequality and non-matching cookies only cover error paths. |
| type binder_cookie const[0, int64] |
| |
| openat$binder(fd const[AT_FDCWD], file ptr[in, string["/dev/binder"]], flags flags[binder_open_flags], mode const[0]) fd_binder |
| openat$binderfs(fd const[AT_FDCWD], file ptr[in, string[binderfs_devpath]], flags flags[binder_open_flags], mode const[0]) fd_binder |
| openat$hwbinder(fd const[AT_FDCWD], file ptr[in, string["/dev/hwbinder"]], flags flags[binder_open_flags], mode const[0]) fd_binder |
| openat$vndbinder(fd const[AT_FDCWD], file ptr[in, string["/dev/vndbinder"]], flags flags[binder_open_flags], mode const[0]) fd_binder |
| |
| mmap$binder(addr vma, len len[addr], prot const[PROT_READ], flags const[MAP_SHARED], fd fd_binder, offset fileoff) binder_ptr |
| |
| ioctl$BINDER_SET_MAX_THREADS(fd fd_binder, cmd const[BINDER_SET_MAX_THREADS], arg ptr[in, int32]) |
| ioctl$BINDER_SET_CONTEXT_MGR(fd fd_binder, cmd const[BINDER_SET_CONTEXT_MGR], arg const[0]) |
| ioctl$BINDER_SET_CONTEXT_MGR_EXT(fd fd_binder, cmd const[BINDER_SET_CONTEXT_MGR_EXT], arg ptr[in, flat_binder_object_t[BINDER_TYPE_BINDER, binder_node]]) |
| ioctl$BINDER_THREAD_EXIT(fd fd_binder, cmd const[BINDER_THREAD_EXIT], arg const[0]) |
| ioctl$BINDER_GET_NODE_DEBUG_INFO(fd fd_binder, cmd const[BINDER_GET_NODE_DEBUG_INFO], arg ptr[inout, binder_node_debug_info]) |
| ioctl$BINDER_WRITE_READ(fd fd_binder, cmd const[BINDER_WRITE_READ], arg ptr[in, binder_write_read]) |
| ioctl$BINDER_GET_NODE_INFO_FOR_REF(fd fd_binder, cmd const[BINDER_GET_NODE_INFO_FOR_REF], arg ptr[in, binder_node_info_for_ref]) |
| ioctl$BINDER_FREEZE(fd fd_binder, cmd const[BINDER_FREEZE], arg ptr[in, binder_freeze_info]) |
| ioctl$BINDER_GET_FROZEN_INFO(fd fd_binder, cmd const[BINDER_GET_FROZEN_INFO], arg ptr[in, binder_frozen_status_info]) |
| ioctl$BINDER_ENABLE_ONEWAY_SPAM_DETECTION(fd fd_binder, cmd const[BINDER_ENABLE_ONEWAY_SPAM_DETECTION], arg ptr[in, bool32]) |
| ioctl$BINDER_GET_EXTENDED_ERROR(fd fd_binder, cmd const[BINDER_GET_EXTENDED_ERROR], arg ptr[out, binder_extended_error]) |
| |
| openat$binder_debug(fd const[AT_FDCWD], file ptr[in, string[binder_debug_file]], flags const[O_RDONLY], mode const[0]) fd |
| |
| binder_debug_file = "/sys/kernel/debug/binder/failed_transaction_log", "/sys/kernel/debug/binder/state", "/sys/kernel/debug/binder/stats", "/sys/kernel/debug/binder/transaction_log", "/sys/kernel/debug/binder/transactions" |
| |
| binder_open_flags = O_RDWR, O_NONBLOCK |
| _ = __NR_mmap2 |
| |
| binder_freeze_info { |
| pid pid |
| enable bool32 |
| timeout_ms int32 |
| } |
| |
| binder_frozen_status_info { |
| pid pid |
| sync_recv int32 (out) |
| async_recv int32 (out) |
| } |
| |
| binder_node_debug_info { |
| ptr binder_node |
| cookie const[0, int64] |
| has_strong_ref const[0, int32] |
| has_weak_ref const[0, int32] |
| } |
| |
| binder_node_info_for_ref { |
| handle binder_handle |
| strong_count const[0, int32] |
| weak_count const[0, int32] |
| reserved1 const[0, int32] |
| reserved2 const[0, int32] |
| reserved3 const[0, int32] |
| } |
| |
| binder_write_read { |
| write_size bytesize[write_buffer, int64] |
| write_consumed const[0, int64] |
| write_buffer ptr64[in, array[binder_write_cmd]] |
| read_size bytesize[read_buffer, int64] |
| read_consumed const[0, int64] |
| read_buffer ptr64[in, array[int8]] |
| } |
| |
| binder_write_cmd [ |
| transaction binder_cmd_transaction |
| reply binder_cmd_reply |
| transaction_sg binder_cmd_transaction_sg |
| reply_sg binder_cmd_reply_sg |
| free_buffer binder_cmd_free_buffer |
| increfs binder_cmd_increfs |
| acquire binder_cmd_acquire |
| release binder_cmd_release |
| decrefs binder_cmd_decrefs |
| increfs_done binder_cmd_increfs_done |
| acquire_done binder_cmd_acquire_done |
| register_looper binder_cmd_register_looper |
| enter_looper binder_cmd_enter_looper |
| exit_looper binder_cmd_exit_looper |
| request_death binder_cmd_request_death |
| clear_death binder_cmd_clear_death |
| dead_binder_done binder_cmd_dead_binder_done |
| ] [varlen] |
| |
| binder_cmd_transaction { |
| cmd const[BC_TRANSACTION, int32] |
| data binder_transaction_data |
| } [packed] |
| |
| binder_cmd_reply { |
| cmd const[BC_REPLY, int32] |
| data binder_transaction_data |
| } [packed] |
| |
| binder_cmd_transaction_sg { |
| cmd const[BC_TRANSACTION_SG, int32] |
| data binder_transaction_data |
| buffers_size flags[binder_sg_size, int64] |
| } [packed] |
| |
| binder_cmd_reply_sg { |
| cmd const[BC_REPLY_SG, int32] |
| data binder_transaction_data |
| buffers_size flags[binder_sg_size, int64] |
| } [packed] |
| |
| # NEED: buffers_size should be multiple of 8 and must be no less than size of all BINDER_TYPE_PTR buffers. |
| binder_sg_size = 0, 64, 1024, 4096 |
| |
| binder_transaction_data { |
| handle binder_handle |
| # there is a union of handle with binder_uintptr_t |
| pad const[0, int32] |
| cookie binder_cookie |
| code const[0, int32] |
| flags flags[binder_transaction_flags, int32] |
| sender_pid const[0, int32] |
| sender_euid const[0, int32] |
| data_size bytesize[buffer, int64] |
| offsets_size bytesize[offsets, int64] |
| buffer ptr64[in, binder_objects] |
| offsets ptr64[in, binder_offsets] |
| } |
| |
| binder_objects { |
| obj0 binder_object |
| obj1 binder_object |
| obj2 binder_object |
| } [packed, align[8]] |
| |
| binder_offsets { |
| off0 offsetof[binder_transaction_data:buffer:obj0, int64] |
| off1 offsetof[binder_transaction_data:buffer:obj1, int64] |
| off2 offsetof[binder_transaction_data:buffer:obj2, int64] |
| } |
| |
| binder_transaction_flags = TF_ONE_WAY, TF_ACCEPT_FDS, TF_CLEAR_BUF |
| |
| binder_object [ |
| flat flat_binder_object |
| fd binder_fd_object |
| fda binder_fd_array_object |
| ptr binder_buffer_object |
| ] [varlen] |
| |
| flat_binder_object [ |
| binder flat_binder_object_t[BINDER_TYPE_BINDER, binder_node] |
| weak_binder flat_binder_object_t[BINDER_TYPE_WEAK_BINDER, binder_node] |
| handle flat_binder_object_t[BINDER_TYPE_HANDLE, binder_handle] |
| weak_handle flat_binder_object_t[BINDER_TYPE_WEAK_HANDLE, binder_handle] |
| ] |
| |
| type flat_binder_object_t[TYP, DATA] { |
| type const[TYP, int32] |
| flags flags[binder_flat_flags, int32] |
| binder DATA |
| cookie binder_cookie |
| } |
| |
| binder_flat_flags = 1, 10, FLAT_BINDER_FLAG_ACCEPTS_FDS, FLAT_BINDER_FLAG_TXN_SECURITY_CTX |
| |
| binder_fd_object { |
| type const[BINDER_TYPE_FD, int32] |
| pad const[0, int32] |
| fd fd |
| pad2 const[0, int32] |
| cookie binder_cookie |
| } |
| |
| binder_fd_array_object { |
| type const[BINDER_TYPE_FDA, int32] |
| num_fds int64[0:10] |
| parnt int64[0:2] |
| parent_offset int64[0:64] |
| } |
| |
| binder_buffer_object { |
| type const[BINDER_TYPE_PTR, int32] |
| # This is BINDER_BUFFER_FLAG_HAS_PARENT. |
| flags bool32 |
| # The buffer is actually input, but the data is opaque. |
| buffer ptr64[out, array[int8]] |
| length bytesize[buffer, int64] |
| # If flags == BINDER_BUFFER_FLAG_HAS_PARENT, this must point to another BINDER_TYPE_PTR object. |
| parnt int64[0:2] |
| parent_offset int64[0:64] |
| } |
| |
| binder_cmd_free_buffer { |
| cmd const[BC_FREE_BUFFER, int32] |
| ptr binder_ptr |
| } [packed] |
| |
| binder_cmd_increfs { |
| cmd const[BC_INCREFS, int32] |
| ref binder_handle |
| } [packed] |
| |
| binder_cmd_acquire { |
| cmd const[BC_ACQUIRE, int32] |
| ref binder_handle |
| } [packed] |
| |
| binder_cmd_release { |
| cmd const[BC_RELEASE, int32] |
| ref binder_handle |
| } [packed] |
| |
| binder_cmd_decrefs { |
| cmd const[BC_DECREFS, int32] |
| ref binder_handle |
| } [packed] |
| |
| binder_cmd_increfs_done { |
| cmd const[BC_INCREFS_DONE, int32] |
| ptr binder_node |
| cookie binder_cookie |
| } [packed] |
| |
| binder_cmd_acquire_done { |
| cmd const[BC_ACQUIRE_DONE, int32] |
| ptr binder_node |
| cookie binder_cookie |
| } [packed] |
| |
| binder_cmd_register_looper { |
| cmd const[BC_REGISTER_LOOPER, int32] |
| } [packed] |
| |
| binder_cmd_enter_looper { |
| cmd const[BC_ENTER_LOOPER, int32] |
| } [packed] |
| |
| binder_cmd_exit_looper { |
| cmd const[BC_EXIT_LOOPER, int32] |
| } [packed] |
| |
| binder_cmd_request_death { |
| cmd const[BC_REQUEST_DEATH_NOTIFICATION, int32] |
| handle binder_handle |
| cookie binder_cookie |
| } [packed] |
| |
| binder_cmd_clear_death { |
| cmd const[BC_CLEAR_DEATH_NOTIFICATION, int32] |
| handle binder_handle |
| cookie binder_cookie |
| } [packed] |
| |
| binder_cmd_dead_binder_done { |
| cmd const[BC_DEAD_BINDER_DONE, int32] |
| cookie binder_cookie |
| } [packed] |
| |
| binder_extended_error { |
| id int32 |
| command int32 |
| param int32 |
| } |