static bool qualify_syscall_name(const char *s, struct number_set *set) { bool found = false; for (unsigned int p = 0; p < SUPPORTED_PERSONALITIES; ++p) { for (kernel_long_t scno = 0; (scno = scno_by_name(s, p, scno)) >= 0; ++scno) { add_number_to_set_array(scno, set, p); found = true; } } return found; }
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; }