static int netlink_parse_response(const void *data, const int data_len, const unsigned long inode, void *opaque_data) { const char *proto_name = opaque_data; const struct netlink_diag_msg *const diag_msg = data; const char *netlink_proto; char *details; if (data_len < (int) NLMSG_LENGTH(sizeof(*diag_msg))) return -1; if (diag_msg->ndiag_ino != inode) return 0; if (diag_msg->ndiag_family != AF_NETLINK) return -1; netlink_proto = xlookup(netlink_protocols, diag_msg->ndiag_protocol); if (netlink_proto) { netlink_proto = STR_STRIP_PREFIX(netlink_proto, "NETLINK_"); if (asprintf(&details, "%s:[%s:%u]", proto_name, netlink_proto, diag_msg->ndiag_portid) < 0) return -1; } else { if (asprintf(&details, "%s:[%u]", proto_name, (unsigned) diag_msg->ndiag_protocol) < 0) return -1; } return cache_inode_details(inode, details); }
unsigned long getfdinode(struct tcb *tcp, int fd) { char path[PATH_MAX + 1]; if (getfdpath(tcp, fd, path, sizeof(path)) >= 0) { const char *str = STR_STRIP_PREFIX(path, "socket:["); if (str != path) { const size_t str_len = strlen(str); if (str_len && str[str_len - 1] == ']') return strtoul(str, NULL, 10); } } return 0; }
void printfd(struct tcb *tcp, int fd) { char path[PATH_MAX + 1]; if (show_fd_path && getfdpath(tcp, fd, path, sizeof(path)) >= 0) { const char *str; size_t len; unsigned long inode; tprintf("%d<", fd); if (show_fd_path <= 1 || (str = STR_STRIP_PREFIX(path, "socket:[")) == path || !(len = strlen(str)) || str[len - 1] != ']' || !(inode = strtoul(str, NULL, 10)) || !print_sockaddr_by_inode(tcp, fd, inode)) { print_quoted_string(path, strlen(path), QUOTE_OMIT_LEADING_TRAILING_QUOTES); } tprints(">"); } else tprintf("%d", fd); }
static bool parse_inject_token(const char *const token, struct inject_opts *const fopts, struct inject_personality_data *const pdata, const bool fault_tokens_only) { const char *val; int intval; if ((val = STR_STRIP_PREFIX(token, "when=")) != token) { /* * == 1+1 * F == F+0 * F+ == F+1 * F+S */ char *end; intval = string_to_uint_ex(val, &end, 0xffff, "+"); if (intval < 1) return false; fopts->first = intval; if (*end) { val = end + 1; if (*val) { /* F+S */ intval = string_to_uint_upto(val, 0xffff); if (intval < 1) return false; fopts->step = intval; } else { /* F+ == F+1 */ fopts->step = 1; } } else { /* F == F+0 */ fopts->step = 0; } } else if ((val = STR_STRIP_PREFIX(token, "syscall=")) != token) { if (fopts->data.flags & INJECT_F_SYSCALL) return false; for (unsigned int p = 0; p < SUPPORTED_PERSONALITIES; ++p) { kernel_long_t scno = scno_by_name(val, p, 0); if (scno < 0) return false; /* * We want to inject only pure system calls with no side * effects. */ if (!(sysent_vec[p][scno].sys_flags & TRACE_PURE)) return false; pdata[p].scno = scno; } fopts->data.flags |= INJECT_F_SYSCALL; } else if ((val = STR_STRIP_PREFIX(token, "error=")) != token) { if (fopts->data.flags & (INJECT_F_ERROR | INJECT_F_RETVAL)) return false; intval = string_to_uint_upto(val, MAX_ERRNO_VALUE); if (intval < 0) intval = find_errno_by_name(val); if (intval < 1) return false; fopts->data.rval_idx = retval_new(intval); fopts->data.flags |= INJECT_F_ERROR; } else if (!fault_tokens_only && (val = STR_STRIP_PREFIX(token, "retval=")) != token) { if (fopts->data.flags & (INJECT_F_ERROR | INJECT_F_RETVAL)) return false; errno = 0; char *endp; unsigned long long ullval = strtoull(val, &endp, 0); if (endp == val || *endp || (kernel_ulong_t) ullval != ullval || ((ullval == 0 || ullval == ULLONG_MAX) && errno)) return false; #if ANY_WORDSIZE_LESS_THAN_KERNEL_LONG bool inadvertent_fault_injection = false; #endif #if !HAVE_ARCH_DEDICATED_ERR_REG if ((kernel_long_t) ullval < 0 && (kernel_long_t) ullval >= -MAX_ERRNO_VALUE) { # if ANY_WORDSIZE_LESS_THAN_KERNEL_LONG inadvertent_fault_injection = true; # endif error_msg("Inadvertent injection of error %" PRI_kld " is possible for retval=%llu", -(kernel_long_t) ullval, ullval); } # if ANY_WORDSIZE_LESS_THAN_KERNEL_LONG else if ((int) ullval < 0 && (int) ullval >= -MAX_ERRNO_VALUE) { inadvertent_fault_injection = true; error_msg("Inadvertent injection of error %d is" " possible in compat personality for" " retval=%llu", -(int) ullval, ullval); } # endif #endif #if ANY_WORDSIZE_LESS_THAN_KERNEL_LONG if (!inadvertent_fault_injection && (unsigned int) ullval != ullval) { error_msg("Injected return value %llu will be" " clipped to %u in compat personality", ullval, (unsigned int) ullval); } #endif fopts->data.rval_idx = retval_new(ullval); fopts->data.flags |= INJECT_F_RETVAL; } else if (!fault_tokens_only && (val = STR_STRIP_PREFIX(token, "signal=")) != token) { if (fopts->data.flags & INJECT_F_SIGNAL) return false; intval = sigstr_to_uint(val); if (intval < 1 || intval > NSIG_BYTES * 8) return false; fopts->data.signo = intval; fopts->data.flags |= INJECT_F_SIGNAL; } else if (!fault_tokens_only && (val = STR_STRIP_PREFIX(token, "delay_enter=")) != token) { if (!parse_delay_token(val, fopts, true)) return false; } else if (!fault_tokens_only && (val = STR_STRIP_PREFIX(token, "delay_exit=")) != token) { if (!parse_delay_token(val, fopts, false)) return false; } else { return false; } return true; }