diff --git a/include/uapi/linux/abi_spec.h b/include/uapi/linux/abi_spec.h index dd8ddc3..21b31f9 100644 --- a/include/uapi/linux/abi_spec.h +++ b/include/uapi/linux/abi_spec.h @@ -80,6 +80,7 @@ struct type { // KIND_ARRAY struct { struct type *type; + u8 length_off; } array; // KIND_STRUCT @@ -110,4 +111,15 @@ struct syscall_spec { struct argument args[ABI_MAX_ARGS]; }; +struct syscall_values { + union { + u8 u8; + u16 u16; + u32 u32; + u64 u64; + void *ptr; + char *str; + }; +}; + #endif diff --git a/kernel/abi_spec.c b/kernel/abi_spec.c index fa249bd..dbafb98 100644 --- a/kernel/abi_spec.c +++ b/kernel/abi_spec.c @@ -7,10 +7,11 @@ #include #include #include +#include -typedef void (*cb_t)(void *ctx, struct type *t, int flags, const void __user *p, int post); +typedef void (*cb_t)(void *ctx, struct type *t, int flags, const void __user *p, struct syscall_values *val, int post); -static size_t handle_type(cb_t cb, void *ctx, struct type *t, int flags, const void __user *p); +static size_t handle_type(cb_t cb, void *ctx, struct type *t, int flags, const void __user *p, struct syscall_values *val); static u64 read_val(struct type *t, int flags, const void __user *p) { @@ -60,27 +61,34 @@ static u64 read_val(struct type *t, int flags, const void __user *p) } } -static size_t handle_type(cb_t cb, void *ctx, struct type *t, int flags, const void __user *p) +static size_t handle_type(cb_t cb, void *ctx, struct type *t, int flags, const void __user *p, struct syscall_values *val) { size_t off; - cb(ctx, t, flags, p, 0); + cb(ctx, t, flags, p, val, 0); switch (t->kind) { case KIND_SCALAR: { off = t->scalar.size; + val->u64 = read_val(t, flags, p); break; } case KIND_PTR: { const void __user* p1; p1 = (const void __user*)read_val(t, flags, p); - handle_type(cb, ctx, t->ptr.type, 0, p1); + handle_type(cb, ctx, t->ptr.type, 0, p1, val); off = sizeof(void *); break; } case KIND_ARRAY: { - // TODO: don't know the size... - // off = handle_array(cb, ctx, t, p); + // length_off == 0 => string + if (t->array.length_off == 0) { + u8 len = strnlen_user(p, 0x10000); + val->ptr = vmalloc(len); + if (WARN_ON(!val->ptr)) + break; + strncpy_from_user(val->ptr, p, len); + } else {} // todo break; } case KIND_STRUCT: { @@ -95,8 +103,8 @@ static size_t handle_type(cb_t cb, void *ctx, struct type *t, int flags, const v if (!f) break; if (i) - cb(ctx, NULL, 0, NULL, 0); - off += handle_type(cb, ctx, f, arg->flags, p + off); + cb(ctx, NULL, 0, NULL, val, 0); + off += handle_type(cb, ctx, f, arg->flags, p + off, val); } break; } @@ -109,13 +117,13 @@ static size_t handle_type(cb_t cb, void *ctx, struct type *t, int flags, const v struct type *t1; for (t1 = t; t1->kind == KIND_RESOURCE; t1 = t1->res.type) {} - off = handle_type(cb, ctx, t1, flags, p); + off = handle_type(cb, ctx, t1, flags, p, val); break; } default: BUG(); } - cb(ctx, t, flags, p, 1); + cb(ctx, t, flags, p, val, 1); return off; } @@ -125,6 +133,7 @@ static void handle_syscall(cb_t cb, void *ctx, struct syscall_spec *s, va_list * struct argument *arg; struct type *f; long v; + struct syscall_values vals[ABI_MAX_ARGS] = { 0 }; for (i = 0; i < ABI_MAX_ARGS; i++) { arg = &s->args[i]; @@ -132,9 +141,9 @@ static void handle_syscall(cb_t cb, void *ctx, struct syscall_spec *s, va_list * if (!f) break; if (i) - cb(ctx, NULL, 0, NULL, 0); + cb(ctx, NULL, 0, NULL, &vals[i], 0); v = va_arg(*ap, long); - handle_type(cb, ctx, f, arg->flags, &v); + handle_type(cb, ctx, f, arg->flags, &v, &vals[i]); } } @@ -148,7 +157,7 @@ static void check_retval(struct syscall_spec *s, long retval) if (s->errno[i] == -retval) return; } - __WARN_printf("syscall %s returned unexpected error %ld", + WARN("syscall %s returned unexpected error %ld", s->name, retval); } @@ -169,7 +178,7 @@ void check_pre_printf(struct check_pre_ctx *ctx, const char *fmt, ...) va_end(args); } -void check_pre_cb(void *ctx, struct type *t, int flags, const void __user *p, int post) +void check_pre_cb(void *ctx, struct type *t, int flags, const void __user *p, struct syscall_values *val, int post) { if (!t) { check_pre_printf(ctx, ", "); @@ -188,7 +197,7 @@ void check_pre_cb(void *ctx, struct type *t, int flags, const void __user *p, in check_pre_printf(ctx, "&%p=", (void*)read_val(t, flags, p)); break; case KIND_ARRAY: - check_pre_printf(ctx, post ? "]" : "["); + check_pre_printf(ctx, post ? " %s ]" : "[", val->ptr); break; case KIND_STRUCT: check_pre_printf(ctx, post ? "}" : "{"); @@ -287,9 +296,16 @@ static struct type type_iptr = { .scalar.size = sizeof(void *), }; +static struct type type_string_i8 = { + .kind = KIND_ARRAY, + .array.type = &type_i8, + .array.length_off = 0, +}; + static struct type type_array_i8 = { .kind = KIND_ARRAY, .array.type = &type_i8, + .array.length_off = 1, }; static struct type type_ptr_array_i8 = { @@ -300,7 +316,7 @@ static struct type type_ptr_array_i8 = { static struct type type_pathname = { .kind = KIND_RESOURCE, .res.res = RES_PATHNAME, - .res.type = &type_array_i8, + .res.type = &type_string_i8, }; static struct type type_ptr_pathname = { @@ -752,5 +768,15 @@ struct syscall_spec syscall_spec_sync_file_range2 = { .name = "sync_file_range2" struct syscall_spec syscall_spec_statfs64 = { .name = "statfs64" }; struct syscall_spec syscall_spec_fstatfs64 = { .name = "fstatfs64" }; struct syscall_spec syscall_spec_bdflush = { .name = "bdflush" }; +struct syscall_spec syscall_spec_sigaction = { .name = "sigaction" }; +struct syscall_spec syscall_spec_old_mmap = { .name = "old_mmap" }; +struct syscall_spec syscall_spec_truncate64 = { .name = "truncate64" }; +struct syscall_spec syscall_spec_ftruncate64 = { .name = "ftruncate64" }; +struct syscall_spec syscall_spec_stat64 = { .name = "stat64" }; +struct syscall_spec syscall_spec_lstat64 = { .name = "lstat64" }; +struct syscall_spec syscall_spec_fstat64 = { .name = "fstat64" }; +struct syscall_spec syscall_spec_fstatat64 = { .name = "fstatat64" }; +struct syscall_spec syscall_spec_fcntl64 = { .name = "fcntl64" }; +struct syscall_spec syscall_spec_old_select = { .name = "old_select" }; #undef $