Re: [RFC 1/3] abi_spec: basic definitions of constraints, args and syscalls
From: Dmitry Vyukov
Date: Mon Nov 21 2016 - 09:48:44 EST
On Wed, Nov 16, 2016 at 6:37 PM, <alexander.levin@xxxxxxxxxxx> wrote:
> This is a very simple definition of the syscall ABI we can build on. The idea
> is to have a generic description of syscalls, their arguments and return
> values we can use to audit the kernel's implementation vs the specs.
>
> Signed-off-by: Sasha Levin <alexander.levin@xxxxxxxxxxx>
> ---
> include/uapi/linux/abi_spec.h | 58 +++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 58 insertions(+)
> create mode 100644 include/uapi/linux/abi_spec.h
>
> diff --git a/include/uapi/linux/abi_spec.h b/include/uapi/linux/abi_spec.h
> new file mode 100644
> index 0000000..ad1a992
> --- /dev/null
> +++ b/include/uapi/linux/abi_spec.h
> @@ -0,0 +1,58 @@
> +#ifndef ABI_SPEC_H_
> +#define ABI_SPEC_H_
> +
> +#include <linux/fcntl.h>
> +#include <linux/stat.h>
> +#define MAX_CONSTRAINTS 10
> +#define MAX_ARGS 10
> +
> +#define TYPE_FD 1
> +#define TYPE_INT 2
> +#define TYPE_PTR 3
> +#define TYPE_STRING 4
> +/* ... */
> +
> +#define CONSTRAINT_NON_NULL (1<<0)
> +#define CONSTRAINT_RANGE (1<<1)
> +#define CONSTRAINT_ADDRESS_TYPE (1<<2)
> +#define CONSTRAINT_FD_TYPE (1<<3)
> +#define CONSTRAINT_ERRNO (1<<4)
> +#define CONSTRAINT_BITMASK (1<<5)
> +#define CONSTRAINT_PATH (1<<6)
> +/* ... */
> +/* A generic constraint on an argument or a return value */
> +struct constraint {
> + unsigned int flags; /* bitmask of applied constraints */
> + union {
> + struct { /* int range */
> + int int_min;
> + int int_max;
> + };
> + unsigned long bitmask; /* allowed flags bitmask */
> + unsigned long address_flags; /* Type of allowed addr */
> + unsigned long fd_flags; /* Type of allowed fd */
> + };
> +};
> +
> +/* A generic argument (or return value) */
> +struct argument {
> + const char *name;
> + int type; /* should be a nicer way to do this */
> +
> + unsigned int nconstraints; /* can there be more than 1-2? */
> + struct constraint constraints[MAX_CONSTRAINTS];
> +};
Several observations based on my experience with syzkaller descriptions:
- there are 2 levels: physical and logical;
on physical level there are int, pointer, array, struct, union;
and that's pretty much it.
on logical level there are flags, bitmasks, file paths, sctp socket fds,
unix socket names, etc.
These levels are almost completely orthogonal. It would be useful to
clearly separate them on description level. E.g. now you have TYPE_PTR and
TYPE_INT which is physical level; and then TYPE_FD which is also an int.
- logical types won't fit into 64 bits, there are more of them
- we need support for recursive types (yes, there are linked lists in
kernel APIs)
- we need support for input/output data
currently syzkaller does this only on pointer level, i.e. you
attach direction to pointer target
but that's not enough, frequently there is a struct where one field
is input and another is output
- we may need support for reusing types in several arguments
e.g. you may have a pretty complex type, and you don't want to
write it out a dozen of times
- we need some support for discriminated syscalls
if we want to support strace usecase, the support needs to be more
extensive than what syzkaller has;
i.e. syzkaller can't restore discrimination having actual argument
values (it can do it only in the other direction)
- I would not create a special support for arguments;
rather I would create support for structs and struct fields,
and then pretend that a syscalls effectively accepts a struct by value
How would you like us to collaborate on this?
If you share your git repo, I could form it into something that would
be suitable for syzkaller and incorporate most of the above.
> +/* A generic syscall */
> +struct syscall_spec {
> + const char *name;
> + struct argument retval;
> +
> + unsigned int nargs;
> + struct argument args[MAX_ARGS];
> +};
> +
> +void abispec_check_pre(const struct syscall_spec *s, ...);
> +void abispec_check_post(const struct syscall_spec *s, long retval, ...);
> +
> +#endif
> --
> 2.7.4