diff options
-rw-r--r-- | include/cutils/debugger.h | 15 | ||||
-rw-r--r-- | libcutils/debugger.c | 32 | ||||
-rw-r--r-- | sdcard/sdcard.c | 35 |
3 files changed, 78 insertions, 4 deletions
diff --git a/include/cutils/debugger.h b/include/cutils/debugger.h index 4bcc8e6..bae687d 100644 --- a/include/cutils/debugger.h +++ b/include/cutils/debugger.h @@ -64,11 +64,26 @@ typedef struct { */ int dump_tombstone(pid_t tid, char* pathbuf, size_t pathlen); +/* Dumps a process backtrace, registers, and stack to a tombstone file (requires root). + * Stores the tombstone path in the provided buffer. + * If reading debugger data from debuggerd ever takes longer than timeout_secs + * seconds, then stop and return an error. + * Returns 0 on success, -1 on error. + */ +int dump_tombstone_timeout(pid_t tid, char* pathbuf, size_t pathlen, int timeout_secs); + /* Dumps a process backtrace only to the specified file (requires root). * Returns 0 on success, -1 on error. */ int dump_backtrace_to_file(pid_t tid, int fd); +/* Dumps a process backtrace only to the specified file (requires root). + * If reading debugger data from debuggerd ever takes longer than timeout_secs + * seconds, then stop and return an error. + * Returns 0 on success, -1 on error. + */ +int dump_backtrace_to_file_timeout(pid_t tid, int fd, int timeout_secs); + #ifdef __cplusplus } #endif diff --git a/libcutils/debugger.c b/libcutils/debugger.c index 4035ee1..b8a2efc 100644 --- a/libcutils/debugger.c +++ b/libcutils/debugger.c @@ -19,11 +19,16 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/types.h> +#include <sys/socket.h> #include <unistd.h> #include <cutils/debugger.h> #include <cutils/sockets.h> +#define LOG_TAG "DEBUG" +#include <log/log.h> + #if defined(__LP64__) #include <elf.h> @@ -64,7 +69,7 @@ static int send_request(int sock_fd, void* msg_ptr, size_t msg_len) { return result; } -static int make_dump_request(debugger_action_t action, pid_t tid) { +static int make_dump_request(debugger_action_t action, pid_t tid, int timeout_secs) { const char* socket_name; debugger_msg_t msg; size_t msg_len; @@ -98,6 +103,19 @@ static int make_dump_request(debugger_action_t action, pid_t tid) { return -1; } + if (timeout_secs > 0) { + struct timeval tm; + tm.tv_sec = timeout_secs; + tm.tv_usec = 0; + if (setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &tm, sizeof(tm)) == -1) { + ALOGE("WARNING: Cannot set receive timeout value on socket: %s", strerror(errno)); + } + + if (setsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, &tm, sizeof(tm)) == -1) { + ALOGE("WARNING: Cannot set send timeout value on socket: %s", strerror(errno)); + } + } + if (send_request(sock_fd, msg_ptr, msg_len) < 0) { TEMP_FAILURE_RETRY(close(sock_fd)); return -1; @@ -107,7 +125,11 @@ static int make_dump_request(debugger_action_t action, pid_t tid) { } int dump_backtrace_to_file(pid_t tid, int fd) { - int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_BACKTRACE, tid); + return dump_backtrace_to_file_timeout(tid, fd, 0); +} + +int dump_backtrace_to_file_timeout(pid_t tid, int fd, int timeout_secs) { + int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_BACKTRACE, tid, timeout_secs); if (sock_fd < 0) { return -1; } @@ -127,7 +149,11 @@ int dump_backtrace_to_file(pid_t tid, int fd) { } int dump_tombstone(pid_t tid, char* pathbuf, size_t pathlen) { - int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_TOMBSTONE, tid); + return dump_tombstone_timeout(tid, pathbuf, pathlen, 0); +} + +int dump_tombstone_timeout(pid_t tid, char* pathbuf, size_t pathlen, int timeout_secs) { + int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_TOMBSTONE, tid, timeout_secs); if (sock_fd < 0) { return -1; } diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c index 247ddd0..9cfb040 100644 --- a/sdcard/sdcard.c +++ b/sdcard/sdcard.c @@ -168,6 +168,11 @@ struct node { __u32 refcount; __u64 nid; __u64 gen; + /* + * The inode number for this FUSE node. Note that this isn't stable across + * multiple invocations of the FUSE daemon. + */ + __u32 ino; /* State derived based on current position in hierarchy. */ perm_t perm; @@ -224,6 +229,25 @@ struct fuse { struct node root; char obbpath[PATH_MAX]; + /* Used to allocate unique inode numbers for fuse nodes. We use + * a simple counter based scheme where inode numbers from deleted + * nodes aren't reused. Note that inode allocations are not stable + * across multiple invocation of the sdcard daemon, but that shouldn't + * be a huge problem in practice. + * + * Note that we restrict inodes to 32 bit unsigned integers to prevent + * truncation on 32 bit processes when unsigned long long stat.st_ino is + * assigned to an unsigned long ino_t type in an LP32 process. + * + * Also note that fuse_attr and fuse_dirent inode values are 64 bits wide + * on both LP32 and LP64, but the fuse kernel code doesn't squash 64 bit + * inode numbers into 32 bit values on 64 bit kernels (see fuse_squash_ino + * in fs/fuse/inode.c). + * + * Accesses must be guarded by |lock|. + */ + __u32 inode_ctr; + Hashmap* package_to_appid; Hashmap* appid_with_rw; }; @@ -387,7 +411,7 @@ static char* find_file_within(const char* path, const char* name, static void attr_from_stat(struct fuse_attr *attr, const struct stat *s, const struct node* node) { - attr->ino = node->nid; + attr->ino = node->ino; attr->size = s->st_size; attr->blocks = s->st_blocks; attr->atime = s->st_atime; @@ -575,6 +599,13 @@ struct node *create_node_locked(struct fuse* fuse, struct node *node; size_t namelen = strlen(name); + // Detect overflows in the inode counter. "4 billion nodes should be enough + // for everybody". + if (fuse->inode_ctr == 0) { + ERROR("No more inode numbers available"); + return NULL; + } + node = calloc(1, sizeof(struct node)); if (!node) { return NULL; @@ -596,6 +627,7 @@ struct node *create_node_locked(struct fuse* fuse, } node->namelen = namelen; node->nid = ptr_to_id(node); + node->ino = fuse->inode_ctr++; node->gen = fuse->next_generation++; derive_permissions_locked(fuse, parent, node); @@ -700,6 +732,7 @@ static void fuse_init(struct fuse *fuse, int fd, const char *source_path, fuse->derive = derive; fuse->split_perms = split_perms; fuse->write_gid = write_gid; + fuse->inode_ctr = 1; memset(&fuse->root, 0, sizeof(fuse->root)); fuse->root.nid = FUSE_ROOT_ID; /* 1 */ |