From b2c5a234aeb69e981c6e7ad120b49d37a86c6cae Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Mon, 2 Dec 2024 10:57:36 +0100 Subject: tools/syz-declextract: rewrite syz-declextract accumulated a bunch of code health problems so that now it's hard to change/extend it, lots of new features can only be added in in hacky ways and cause lots of code duplication. It's also completly untested. Rewrite the tool to: - move as much code as possible to Go (working with the clang tool is painful for a number of reasons) - allow testing and add unit tests (first layer of tests test what information is produced by the clang tool, second layer of tests test how that information is transformed to descriptions) - allow extending the clang tool output to export arbitrary info in non-hacky way (now it produces arbitrary JSON instead of a mix of incomplete descriptions and interfaces) - remove code duplication in the clang tool and provide common infrastructure to add new analysis w/o causing more duplication - provide more convinient primitives in the clang tool - improve code style consistency and stick to the LLVM code style (in particular, variable names must start with a capital letter, single-statement blocks are not surrounded with {}) - remove intermixing of code that works on different levels (currently we have AST analysis + busness logic + printfs all intermixed with each other) - provide several helper Go packages for better code structuring (e.g. pkg/clangtool just runs the tool on source files in parallel and returns results, this already separates a bunch of low-level logic from the rest of the code under a simple abstraction) I've tried to make the output match the current output as much as possible so that the diff is managable (in some cases at the cost of code quality, this should be fixed in future commits). There are still some differences, but hopefully they are managable for review (more includes/defines, reordered some netlink attributes). Fixed minor bugs are fixed along the way, but mostly NFC: 1. Some unions were incorrectly emitted as [varlen] (C unions are never varlen). 2. Only a of [packed], [align[N]] attributes was emitted for struct (both couldn't be emitted). --- tools/syz-declextract/testdata/README.md | 28 ++ .../syz-declextract/testdata/arch/arm/syscalls.tbl | 0 .../testdata/arch/arm64/syscalls.tbl | 0 .../testdata/arch/mips/syscalls.tbl | 0 .../testdata/arch/powerpc/syscalls.tbl | 0 .../testdata/arch/riscv/syscalls.tbl | 0 .../testdata/arch/s390/syscalls.tbl | 0 .../syz-declextract/testdata/arch/x86/syscalls.tbl | 6 + tools/syz-declextract/testdata/include/netlink.h | 86 ++++ tools/syz-declextract/testdata/include/syscall.h | 7 + tools/syz-declextract/testdata/include/types.h | 13 + .../testdata/include/uapi/io_uring.h | 9 + .../testdata/include/uapi/netlink_family.h | 27 + tools/syz-declextract/testdata/io_uring.c | 36 ++ tools/syz-declextract/testdata/io_uring.c.info | 3 + tools/syz-declextract/testdata/io_uring.c.json | 22 + tools/syz-declextract/testdata/io_uring.c.txt | 10 + tools/syz-declextract/testdata/manual.txt | 50 ++ tools/syz-declextract/testdata/netlink.c | 87 ++++ tools/syz-declextract/testdata/netlink.c.info | 3 + tools/syz-declextract/testdata/netlink.c.json | 197 ++++++++ tools/syz-declextract/testdata/netlink.c.txt | 51 ++ tools/syz-declextract/testdata/syscall.c | 12 + tools/syz-declextract/testdata/syscall.c.info | 2 + tools/syz-declextract/testdata/syscall.c.json | 77 +++ tools/syz-declextract/testdata/syscall.c.txt | 12 + tools/syz-declextract/testdata/types.c | 55 ++ tools/syz-declextract/testdata/types.c.info | 1 + tools/syz-declextract/testdata/types.c.json | 555 +++++++++++++++++++++ tools/syz-declextract/testdata/types.c.txt | 87 ++++ 30 files changed, 1436 insertions(+) create mode 100644 tools/syz-declextract/testdata/README.md create mode 100644 tools/syz-declextract/testdata/arch/arm/syscalls.tbl create mode 100644 tools/syz-declextract/testdata/arch/arm64/syscalls.tbl create mode 100644 tools/syz-declextract/testdata/arch/mips/syscalls.tbl create mode 100644 tools/syz-declextract/testdata/arch/powerpc/syscalls.tbl create mode 100644 tools/syz-declextract/testdata/arch/riscv/syscalls.tbl create mode 100644 tools/syz-declextract/testdata/arch/s390/syscalls.tbl create mode 100644 tools/syz-declextract/testdata/arch/x86/syscalls.tbl create mode 100644 tools/syz-declextract/testdata/include/netlink.h create mode 100644 tools/syz-declextract/testdata/include/syscall.h create mode 100644 tools/syz-declextract/testdata/include/types.h create mode 100644 tools/syz-declextract/testdata/include/uapi/io_uring.h create mode 100644 tools/syz-declextract/testdata/include/uapi/netlink_family.h create mode 100644 tools/syz-declextract/testdata/io_uring.c create mode 100644 tools/syz-declextract/testdata/io_uring.c.info create mode 100644 tools/syz-declextract/testdata/io_uring.c.json create mode 100644 tools/syz-declextract/testdata/io_uring.c.txt create mode 100644 tools/syz-declextract/testdata/manual.txt create mode 100644 tools/syz-declextract/testdata/netlink.c create mode 100644 tools/syz-declextract/testdata/netlink.c.info create mode 100644 tools/syz-declextract/testdata/netlink.c.json create mode 100644 tools/syz-declextract/testdata/netlink.c.txt create mode 100644 tools/syz-declextract/testdata/syscall.c create mode 100644 tools/syz-declextract/testdata/syscall.c.info create mode 100644 tools/syz-declextract/testdata/syscall.c.json create mode 100644 tools/syz-declextract/testdata/syscall.c.txt create mode 100644 tools/syz-declextract/testdata/types.c create mode 100644 tools/syz-declextract/testdata/types.c.info create mode 100644 tools/syz-declextract/testdata/types.c.json create mode 100644 tools/syz-declextract/testdata/types.c.txt (limited to 'tools/syz-declextract/testdata') diff --git a/tools/syz-declextract/testdata/README.md b/tools/syz-declextract/testdata/README.md new file mode 100644 index 000000000..494ddac6a --- /dev/null +++ b/tools/syz-declextract/testdata/README.md @@ -0,0 +1,28 @@ +This dir contains sources of a fake kernel that resembles Linux for testing of the `syz-declextract` tool. + +For each `*.c` file there 3 golden files: + - `*.c.json` with the expected output of the clang tool + - `*.c.txt` with the expected syzlang descriptions + - `*.c.info` with the expected kernel interface list + +Testing is done by `tools/syz-declextract` tests. + +`TestClangTool` invokes the clang tool and verifies `*.c.json` contents. +The test requires the clang tool binary specified in the `-bin`, otherwise it skips testing. +You also want to run it with `-count=1` flag since the Go tool does not detect changes in the tool binary, +and will cache and reuse test results: +``` +go test -count=1 ./tools/syz-declextract -bin=llvm/build/bin/syz-declextract +``` + +`TestDeclextract` verifies `*.c.txt` and `*.c.info` using `*.c.json` files as inputs +(it does not involve the clang tool and runs always). + +All tests also support `-update` flag, which updates the golden files. +Generally you don't need to update them manually. + +Since the test covers multiple packages, it's useful to run coverage as follows: +``` +go test -count=1 -coverprofile=/tmp/cover -coverpkg="github.com/google/syzkaller/tools/syz-declextract,github.com/google/syzkaller/pkg/declextract,github.com/google/syzkaller/pkg/clangtool" ./tools/syz-declextract -bin=llvm/build/bin/syz-declextract +go tool cover -html /tmp/cover +``` diff --git a/tools/syz-declextract/testdata/arch/arm/syscalls.tbl b/tools/syz-declextract/testdata/arch/arm/syscalls.tbl new file mode 100644 index 000000000..e69de29bb diff --git a/tools/syz-declextract/testdata/arch/arm64/syscalls.tbl b/tools/syz-declextract/testdata/arch/arm64/syscalls.tbl new file mode 100644 index 000000000..e69de29bb diff --git a/tools/syz-declextract/testdata/arch/mips/syscalls.tbl b/tools/syz-declextract/testdata/arch/mips/syscalls.tbl new file mode 100644 index 000000000..e69de29bb diff --git a/tools/syz-declextract/testdata/arch/powerpc/syscalls.tbl b/tools/syz-declextract/testdata/arch/powerpc/syscalls.tbl new file mode 100644 index 000000000..e69de29bb diff --git a/tools/syz-declextract/testdata/arch/riscv/syscalls.tbl b/tools/syz-declextract/testdata/arch/riscv/syscalls.tbl new file mode 100644 index 000000000..e69de29bb diff --git a/tools/syz-declextract/testdata/arch/s390/syscalls.tbl b/tools/syz-declextract/testdata/arch/s390/syscalls.tbl new file mode 100644 index 000000000..e69de29bb diff --git a/tools/syz-declextract/testdata/arch/x86/syscalls.tbl b/tools/syz-declextract/testdata/arch/x86/syscalls.tbl new file mode 100644 index 000000000..19309c4ef --- /dev/null +++ b/tools/syz-declextract/testdata/arch/x86/syscalls.tbl @@ -0,0 +1,6 @@ +# Copyright 2024 syzkaller project authors. All rights reserved. +# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +1 64 open sys_open +2 64 chmod sys_chmod +3 64 types_syscall sys_types_syscall diff --git a/tools/syz-declextract/testdata/include/netlink.h b/tools/syz-declextract/testdata/include/netlink.h new file mode 100644 index 000000000..ee8091290 --- /dev/null +++ b/tools/syz-declextract/testdata/include/netlink.h @@ -0,0 +1,86 @@ +// Copyright 2024 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +#include "types.h" + +enum { + NLA_UNSPEC, + NLA_U8, + NLA_U16, + NLA_U32, + NLA_U64, + NLA_STRING, + NLA_FLAG, + NLA_MSECS, + NLA_NESTED, + NLA_NESTED_ARRAY, + NLA_NUL_STRING, + NLA_BINARY, + NLA_S8, + NLA_S16, + NLA_S32, + NLA_S64, + NLA_BITFIELD32, + NLA_REJECT, + NLA_BE16, + NLA_BE32, + NLA_SINT, + NLA_UINT, + __NLA_TYPE_MAX, +}; + +struct nla_policy { + u8 type; + u8 validation_type; + u16 len; + union { + const u32 bitfield32_valid; + const u32 mask; + const struct nla_policy *nested_policy; + struct { s16 min, max; }; + }; +}; + +#define NLA_POLICY_NESTED(policy) { .type = NLA_NESTED, .nested_policy = policy, .len = sizeof(policy)/sizeof(policy[0]) } + +#define GENL_ADMIN_PERM 0x01 +#define GENL_UNS_ADMIN_PERM 0x10 + +struct genl_ops { + u8 cmd; + u8 flags; + const struct nla_policy* policy; + void (*doit)(void); + void (*dumpit)(void); +}; + +struct genl_split_ops { + u8 cmd; + u8 flags; + const struct nla_policy *policy; + union { + struct { + void (*pre_doit)(void); + void (*doit)(void); + void (*post_doit)(void); + }; + struct { + void (*start)(void); + void (*dumpit)(void); + void (*done)(void); + }; + }; +}; + +struct genl_small_ops {}; + +struct genl_family { + char name[64]; + u8 n_ops; + u8 n_small_ops; + u8 n_split_ops; + const struct nla_policy* policy; + const struct genl_ops* ops; + const struct genl_small_ops* mall_ops; + const struct genl_split_ops* split_ops; +}; diff --git a/tools/syz-declextract/testdata/include/syscall.h b/tools/syz-declextract/testdata/include/syscall.h new file mode 100644 index 000000000..601480cb4 --- /dev/null +++ b/tools/syz-declextract/testdata/include/syscall.h @@ -0,0 +1,7 @@ +// Copyright 2024 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +#define SYSCALL_DEFINE1(NAME, ...) SYSCALL_DEFINEx(1, NAME, __VA_ARGS__) +#define SYSCALL_DEFINE2(NAME, ...) SYSCALL_DEFINEx(2, NAME, __VA_ARGS__) +#define SYSCALL_DEFINEx(NARGS, NAME, ...) long __do_sys_##NAME(__VA_ARGS__); \ +long __do_sys_##NAME(__VA_ARGS__) diff --git a/tools/syz-declextract/testdata/include/types.h b/tools/syz-declextract/testdata/include/types.h new file mode 100644 index 000000000..5b1d6303c --- /dev/null +++ b/tools/syz-declextract/testdata/include/types.h @@ -0,0 +1,13 @@ +// Copyright 2024 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +typedef signed char s8; +typedef short s16; +typedef int s32; +typedef long long s64; +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) diff --git a/tools/syz-declextract/testdata/include/uapi/io_uring.h b/tools/syz-declextract/testdata/include/uapi/io_uring.h new file mode 100644 index 000000000..cdc5a372a --- /dev/null +++ b/tools/syz-declextract/testdata/include/uapi/io_uring.h @@ -0,0 +1,9 @@ +// Copyright 2024 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +enum io_uring_op { + IORING_OP_NOP, + IORING_OP_READV, + IORING_OP_WRITEV, + IORING_OP_NOT_SUPPORTED, +}; diff --git a/tools/syz-declextract/testdata/include/uapi/netlink_family.h b/tools/syz-declextract/testdata/include/uapi/netlink_family.h new file mode 100644 index 000000000..ffaf66bf7 --- /dev/null +++ b/tools/syz-declextract/testdata/include/uapi/netlink_family.h @@ -0,0 +1,27 @@ +// Copyright 2024 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +// Description of some hypothetic netlink family. + +enum netlink_foo_cmds { + NETLINK_FOO_CMD_FOO, + NETLINK_FOO_CMD_BAR, +}; + +enum netlink_foo_attrs { + NETLINK_FOO_ATTR1, + NETLINK_FOO_ATTR2, + NETLINK_FOO_ATTR3 = NETLINK_FOO_ATTR2 + 3, // make them non-dense + NETLINK_FOO_ATTR4, + NETLINK_FOO_ATTR5, + NETLINK_FOO_ATTR6, + NETLINK_FOO_ATTR7, +}; + +struct netlink_foo_struct1 { + int a, b, c; +}; + +typedef struct { + double a, b, c; +} netlink_foo_struct2; diff --git a/tools/syz-declextract/testdata/io_uring.c b/tools/syz-declextract/testdata/io_uring.c new file mode 100644 index 000000000..20f85f0e5 --- /dev/null +++ b/tools/syz-declextract/testdata/io_uring.c @@ -0,0 +1,36 @@ +// Copyright 2024 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +#include "include/uapi/io_uring.h" + +struct io_issue_def { + void (*prep)(void); + void (*issue)(void); +}; + +void io_eopnotsupp_prep() {} +void io_nop_prep() {} +void io_nop() {} +void io_readv_prep() {} +void io_read() {} +void io_writev_prep() {} +void io_write() {} + +const struct io_issue_def ops[] = { + [IORING_OP_NOP] = { + .prep = io_nop_prep, + .issue = io_nop, + }, + [IORING_OP_READV] = { + .prep = io_readv_prep, + .issue = io_read, + }, + [IORING_OP_WRITEV] = { + .prep = io_writev_prep, + .issue = io_write, + }, + [IORING_OP_NOT_SUPPORTED] = { + .prep = io_eopnotsupp_prep, + .issue = io_write, + }, +}; diff --git a/tools/syz-declextract/testdata/io_uring.c.info b/tools/syz-declextract/testdata/io_uring.c.info new file mode 100644 index 000000000..6757eca74 --- /dev/null +++ b/tools/syz-declextract/testdata/io_uring.c.info @@ -0,0 +1,3 @@ +IOURING IORING_OP_NOP func:io_nop access:user manual_desc:false auto_desc:false file:io_uring.c subsystem:kernel +IOURING IORING_OP_READV func:io_read access:user manual_desc:false auto_desc:false file:io_uring.c subsystem:kernel +IOURING IORING_OP_WRITEV func:io_write access:user manual_desc:false auto_desc:false file:io_uring.c subsystem:kernel diff --git a/tools/syz-declextract/testdata/io_uring.c.json b/tools/syz-declextract/testdata/io_uring.c.json new file mode 100644 index 000000000..927adfe26 --- /dev/null +++ b/tools/syz-declextract/testdata/io_uring.c.json @@ -0,0 +1,22 @@ +{ + "includes": [ + "include/uapi/io_uring.h" + ], + "iouring_ops": [ + { + "name": "IORING_OP_NOP", + "func": "io_nop", + "source_file": "io_uring.c" + }, + { + "name": "IORING_OP_READV", + "func": "io_read", + "source_file": "io_uring.c" + }, + { + "name": "IORING_OP_WRITEV", + "func": "io_write", + "source_file": "io_uring.c" + } + ] +} \ No newline at end of file diff --git a/tools/syz-declextract/testdata/io_uring.c.txt b/tools/syz-declextract/testdata/io_uring.c.txt new file mode 100644 index 000000000..3ddbbcf40 --- /dev/null +++ b/tools/syz-declextract/testdata/io_uring.c.txt @@ -0,0 +1,10 @@ +# Code generated by syz-declextract. DO NOT EDIT. + +meta automatic + +type auto_todo intptr + +include +include +include +include diff --git a/tools/syz-declextract/testdata/manual.txt b/tools/syz-declextract/testdata/manual.txt new file mode 100644 index 000000000..31ab63c9c --- /dev/null +++ b/tools/syz-declextract/testdata/manual.txt @@ -0,0 +1,50 @@ +# Copyright 2024 syzkaller project authors. All rights reserved. +# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +# This file contains manual descriptions that are required to compile auto-generated descriptions. + +resource fd[int32] +resource sock_nl_generic[fd] +resource pid[int32] + +type ifindex int32 + +create$pid() pid (automatic_helper) +create$sock_nl_generic() sock_nl_generic (automatic_helper) +sendmsg$netlink(fd sock_nl_generic, data ptr[in, msghdr_netlink[netlink_msg_t[int32, genlmsghdr_t[1], int32]]], flags flags[send_flags]) + +use(a ptr[in, use]) +use { + f0 pid + f1 ifindex + f2 auto_todo + f3 nlattr[1, int32] + f4 nlnest[1, int32] + f5 nl_generic_attr + +} + +type msghdr_netlink[MSG] { + vec ptr[in, MSG] +} + +type netlink_msg_t[TYPE, PAYLOAD, ATTRS] { + type TYPE + payload PAYLOAD + attrs array[ATTRS] +} + +type genlmsghdr_t[CMD] { + cmd const[CMD, int8] +} + +type nlattr[ATTR, TYPE] { + attr const[ATTR, int32] + data TYPE +} + +type nlnest[ATTR, TYPE] nlattr[ATTR, TYPE] + +type nl_generic_attr int32 + +send_flags = 1, 2 diff --git a/tools/syz-declextract/testdata/netlink.c b/tools/syz-declextract/testdata/netlink.c new file mode 100644 index 000000000..355b84f1f --- /dev/null +++ b/tools/syz-declextract/testdata/netlink.c @@ -0,0 +1,87 @@ +// Copyright 2024 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +#include "include/netlink.h" +#include "include/uapi/netlink_family.h" + +// These consts are defined not in uapi .h, so the descriptions should contain +// values for them rather than includes. +enum netlink_foo_nested_attrs { + NETLINK_FOO_NESTED_ATTR1, + NETLINK_FOO_NESTED_ATTR2, +}; + +static netlink_foo_struct2 var; + +const struct nla_policy foo_genl_nested_policy[] = { + [NETLINK_FOO_NESTED_ATTR1] = { .type = NLA_U32 }, + [NETLINK_FOO_NESTED_ATTR2] = { .type = NLA_U32 }, +}; + +const struct nla_policy foo_genl_policy[] = { + [NETLINK_FOO_ATTR1] = { .type = NLA_U32 }, + [NETLINK_FOO_ATTR2] = { .type = NLA_STRING, .len = 10 }, + [NETLINK_FOO_ATTR3] = { .type = NLA_NESTED }, + [NETLINK_FOO_ATTR4] = NLA_POLICY_NESTED(foo_genl_nested_policy), + [NETLINK_FOO_ATTR5] = { .len = sizeof(struct netlink_foo_struct1) }, + [NETLINK_FOO_ATTR6] = { .len = sizeof(netlink_foo_struct2) * 10 }, + [NETLINK_FOO_ATTR7] = { .len = sizeof(var) }, +}; + +const struct nla_policy genl_policy_reject_all[] = { + { .type = NLA_REJECT }, + { .type = NLA_REJECT }, +}; + +const struct nla_policy policy_forward_decl[10]; + +static void foo_cmd() {} +static void bar_cmd() {} + +static const struct genl_ops foo_ops[] = { + { + .cmd = NETLINK_FOO_CMD_FOO, + .flags = GENL_ADMIN_PERM, + .doit = foo_cmd, + }, + { + .cmd = NETLINK_FOO_CMD_BAR, + .flags = GENL_UNS_ADMIN_PERM, + .dumpit = bar_cmd, + }, +}; + +static struct genl_family foo_family = { + .ops = foo_ops, + .n_ops = ARRAY_SIZE(foo_ops), + .name = "foo family", + .policy = foo_genl_policy, +}; + +enum { + NETLINK_BAR_CMD_FOO, +}; + +static void bar_pre_doit() {} +static void bar_doit() {} +static void bar_post_doit() {} + +static const struct genl_split_ops bar_ops[] = { + { + .cmd = NETLINK_BAR_CMD_FOO, + .pre_doit = bar_pre_doit, + .doit = bar_doit, + .post_doit = bar_post_doit, + }, +}; + +struct genl_family bar_family = { + .split_ops = bar_ops, + .n_split_ops = ARRAY_SIZE(bar_ops), + .name = "BAR", + .policy = foo_genl_policy, +}; + +struct genl_family noops_family = { + .name = "NOOPS", +}; diff --git a/tools/syz-declextract/testdata/netlink.c.info b/tools/syz-declextract/testdata/netlink.c.info new file mode 100644 index 000000000..e15a8e738 --- /dev/null +++ b/tools/syz-declextract/testdata/netlink.c.info @@ -0,0 +1,3 @@ +NETLINK NETLINK_BAR_CMD_FOO func:NETLINK_BAR_CMD_FOO access:user manual_desc:false auto_desc:true file:netlink.c subsystem:kernel +NETLINK NETLINK_FOO_CMD_BAR func:bar_cmd access:ns_admin manual_desc:false auto_desc:true file:netlink.c subsystem:kernel +NETLINK NETLINK_FOO_CMD_FOO func:foo_cmd access:admin manual_desc:false auto_desc:true file:netlink.c subsystem:kernel diff --git a/tools/syz-declextract/testdata/netlink.c.json b/tools/syz-declextract/testdata/netlink.c.json new file mode 100644 index 000000000..e4e485182 --- /dev/null +++ b/tools/syz-declextract/testdata/netlink.c.json @@ -0,0 +1,197 @@ +{ + "includes": [ + "include/uapi/netlink_family.h" + ], + "defines": [ + { + "name": "NETLINK_BAR_CMD_FOO", + "value": "0" + }, + { + "name": "NETLINK_FOO_NESTED_ATTR1", + "value": "0" + }, + { + "name": "NETLINK_FOO_NESTED_ATTR2", + "value": "1" + } + ], + "structs": [ + { + "name": "netlink_foo_struct1", + "byte_size": 12, + "fields": [ + { + "name": "a", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + }, + { + "name": "b", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + }, + { + "name": "c", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + } + ] + }, + { + "name": "netlink_foo_struct2", + "byte_size": 24, + "fields": [ + { + "name": "a", + "counted_by": -1, + "type": { + "int": { + "byte_size": 8, + "name": "double", + "base": "double" + } + } + }, + { + "name": "b", + "counted_by": -1, + "type": { + "int": { + "byte_size": 8, + "name": "double", + "base": "double" + } + } + }, + { + "name": "c", + "counted_by": -1, + "type": { + "int": { + "byte_size": 8, + "name": "double", + "base": "double" + } + } + } + ] + } + ], + "netlink_families": [ + { + "name": "BAR", + "ops": [ + { + "name": "NETLINK_BAR_CMD_FOO", + "func": "NETLINK_BAR_CMD_FOO", + "access": "user", + "policy": "foo_genl_policy$auto_netlink" + } + ], + "source_file": "netlink.c" + }, + { + "name": "NOOPS", + "source_file": "netlink.c" + }, + { + "name": "foo family", + "ops": [ + { + "name": "NETLINK_FOO_CMD_FOO", + "func": "foo_cmd", + "access": "admin", + "policy": "foo_genl_policy$auto_netlink" + }, + { + "name": "NETLINK_FOO_CMD_BAR", + "func": "bar_cmd", + "access": "ns_admin", + "policy": "foo_genl_policy$auto_netlink" + } + ], + "source_file": "netlink.c" + } + ], + "netlink_policies": [ + { + "name": "foo_genl_nested_policy$auto_netlink", + "attrs": [ + { + "name": "NETLINK_FOO_NESTED_ATTR1", + "kind": "NLA_U32" + }, + { + "name": "NETLINK_FOO_NESTED_ATTR2", + "kind": "NLA_U32" + } + ] + }, + { + "name": "foo_genl_policy$auto_netlink", + "attrs": [ + { + "name": "NETLINK_FOO_ATTR1", + "kind": "NLA_U32" + }, + { + "name": "NETLINK_FOO_ATTR2", + "kind": "NLA_STRING", + "max_size": 10 + }, + { + "name": "NETLINK_FOO_ATTR3", + "kind": "NLA_NESTED" + }, + { + "name": "NETLINK_FOO_ATTR4", + "kind": "NLA_NESTED", + "nested_policy": "foo_genl_nested_policy$auto_netlink" + }, + { + "name": "NETLINK_FOO_ATTR5", + "max_size": 12, + "elem": { + "struct": "netlink_foo_struct1" + } + }, + { + "name": "NETLINK_FOO_ATTR6", + "max_size": 240, + "elem": { + "struct": "netlink_foo_struct2" + } + }, + { + "name": "NETLINK_FOO_ATTR7", + "max_size": 24, + "elem": { + "struct": "netlink_foo_struct2" + } + } + ] + }, + { + "name": "genl_policy_reject_all$auto_netlink" + } + ] +} \ No newline at end of file diff --git a/tools/syz-declextract/testdata/netlink.c.txt b/tools/syz-declextract/testdata/netlink.c.txt new file mode 100644 index 000000000..4b67a444d --- /dev/null +++ b/tools/syz-declextract/testdata/netlink.c.txt @@ -0,0 +1,51 @@ +# Code generated by syz-declextract. DO NOT EDIT. + +meta automatic + +type auto_todo intptr + +include +include +include +include + +resource genl_BAR_family_id_auto[int16] +resource genl_foo_family_family_id_auto[int16] +type msghdr_BAR_auto[CMD, POLICY] msghdr_netlink[netlink_msg_t[genl_BAR_family_id_auto, genlmsghdr_t[CMD], POLICY]] +type msghdr_foo_family_auto[CMD, POLICY] msghdr_netlink[netlink_msg_t[genl_foo_family_family_id_auto, genlmsghdr_t[CMD], POLICY]] +syz_genetlink_get_family_id$auto_BAR(name ptr[in, string["BAR"]], fd sock_nl_generic) genl_BAR_family_id_auto +syz_genetlink_get_family_id$auto_foo_family(name ptr[in, string["foo family"]], fd sock_nl_generic) genl_foo_family_family_id_auto +sendmsg$auto_NETLINK_BAR_CMD_FOO(fd sock_nl_generic, msg ptr[in, msghdr_BAR_auto[NETLINK_BAR_CMD_FOO, foo_genl_policy$auto_netlink]], f flags[send_flags]) +sendmsg$auto_NETLINK_FOO_CMD_BAR(fd sock_nl_generic, msg ptr[in, msghdr_foo_family_auto[NETLINK_FOO_CMD_BAR, foo_genl_policy$auto_netlink]], f flags[send_flags]) +sendmsg$auto_NETLINK_FOO_CMD_FOO(fd sock_nl_generic, msg ptr[in, msghdr_foo_family_auto[NETLINK_FOO_CMD_FOO, foo_genl_policy$auto_netlink]], f flags[send_flags]) + +foo_genl_nested_policy$auto_netlink [ + NETLINK_FOO_NESTED_ATTR1 nlattr[NETLINK_FOO_NESTED_ATTR1, int32] + NETLINK_FOO_NESTED_ATTR2 nlattr[NETLINK_FOO_NESTED_ATTR2, int32] +] [varlen] + +foo_genl_policy$auto_netlink [ + NETLINK_FOO_ATTR1 nlattr[NETLINK_FOO_ATTR1, int32] + NETLINK_FOO_ATTR2 nlattr[NETLINK_FOO_ATTR2, stringnoz] + NETLINK_FOO_ATTR3 nlnest[NETLINK_FOO_ATTR3, array[nl_generic_attr]] + NETLINK_FOO_ATTR4 nlnest[NETLINK_FOO_ATTR4, array[foo_genl_nested_policy$auto_netlink]] + NETLINK_FOO_ATTR5 nlattr[NETLINK_FOO_ATTR5, netlink_foo_struct1$auto_record] + NETLINK_FOO_ATTR6 nlattr[NETLINK_FOO_ATTR6, array[netlink_foo_struct2$auto_record, 0:10]] + NETLINK_FOO_ATTR7 nlattr[NETLINK_FOO_ATTR7, netlink_foo_struct2$auto_record] +] [varlen] + +netlink_foo_struct1$auto_record { + a int32 + b int32 + c int32 +} + +netlink_foo_struct2$auto_record { + a int64 + b int64 + c int64 +} + +define NETLINK_BAR_CMD_FOO 0 +define NETLINK_FOO_NESTED_ATTR1 0 +define NETLINK_FOO_NESTED_ATTR2 1 diff --git a/tools/syz-declextract/testdata/syscall.c b/tools/syz-declextract/testdata/syscall.c new file mode 100644 index 000000000..be247151b --- /dev/null +++ b/tools/syz-declextract/testdata/syscall.c @@ -0,0 +1,12 @@ +// Copyright 2024 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +#include "include/syscall.h" + +SYSCALL_DEFINE1(open, const char* filename, int flags, int mode) { + return 0; +} + +SYSCALL_DEFINE1(chmod, const char* filename, int mode) { + return 0; +} diff --git a/tools/syz-declextract/testdata/syscall.c.info b/tools/syz-declextract/testdata/syscall.c.info new file mode 100644 index 000000000..5d204a68e --- /dev/null +++ b/tools/syz-declextract/testdata/syscall.c.info @@ -0,0 +1,2 @@ +SYSCALL chmod func:__do_sys_chmod access:unknown manual_desc:false auto_desc:true file:syscall.c subsystem:kernel +SYSCALL open func:__do_sys_open access:unknown manual_desc:false auto_desc:true file:syscall.c subsystem:kernel diff --git a/tools/syz-declextract/testdata/syscall.c.json b/tools/syz-declextract/testdata/syscall.c.json new file mode 100644 index 000000000..6e52fd57e --- /dev/null +++ b/tools/syz-declextract/testdata/syscall.c.json @@ -0,0 +1,77 @@ +{ + "syscalls": [ + { + "func": "__do_sys_chmod", + "args": [ + { + "name": "filename", + "counted_by": -1, + "type": { + "ptr": { + "elem": { + "buffer": { + "is_string": true + } + }, + "is_const": true + } + } + }, + { + "name": "mode", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + } + ], + "source_file": "syscall.c" + }, + { + "func": "__do_sys_open", + "args": [ + { + "name": "filename", + "counted_by": -1, + "type": { + "ptr": { + "elem": { + "buffer": { + "is_string": true + } + }, + "is_const": true + } + } + }, + { + "name": "flags", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + }, + { + "name": "mode", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + } + ], + "source_file": "syscall.c" + } + ] +} \ No newline at end of file diff --git a/tools/syz-declextract/testdata/syscall.c.txt b/tools/syz-declextract/testdata/syscall.c.txt new file mode 100644 index 000000000..b55b077c3 --- /dev/null +++ b/tools/syz-declextract/testdata/syscall.c.txt @@ -0,0 +1,12 @@ +# Code generated by syz-declextract. DO NOT EDIT. + +meta automatic + +type auto_todo intptr + +include +include +include + +chmod$auto(filename ptr[in, filename], mode int32) +open$auto(filename ptr[in, filename], flags int32, mode int32) diff --git a/tools/syz-declextract/testdata/types.c b/tools/syz-declextract/testdata/types.c new file mode 100644 index 000000000..8fc67aeb9 --- /dev/null +++ b/tools/syz-declextract/testdata/types.c @@ -0,0 +1,55 @@ +// Copyright 2024 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +#include "include/syscall.h" + +typedef struct { float f; } anon_t; +struct empty_struct {}; +typedef int fd_t; +typedef struct forward forward_t; + +struct anon_struct { + // Various tricky anon cases. + struct { int x; } a; + struct {} b; + struct { int y; }; + union { int q; long w; }; + anon_t foo; + forward_t* forward; + struct { int a; int b; } array[4]; + struct { int a; int b; } *ptr; + struct { int a; int b; } *ptr_array[4]; +}; + +enum bitfield_enum { a, b, c }; + +struct bitfields { + int a : 1; + int : 2; + int b : 3; + long d : 2; + long pad : 3; + enum bitfield_enum e : 10; + int l : 10; + int* p __attribute__((counted_by(l))); +} __attribute__((aligned(32))); + +struct packed_t { + char x; + int y; +} __attribute__((packed, aligned(32))); + +struct various { + struct various* recursive; + struct recursive* next; + struct packed_t packed; +}; + +struct recursive { + struct various various; +}; + +SYSCALL_DEFINE1(types_syscall, struct anon_struct* p, struct empty_struct* y, + struct bitfields* b, int pid, fd_t f, struct various* v) { + return 0; +} diff --git a/tools/syz-declextract/testdata/types.c.info b/tools/syz-declextract/testdata/types.c.info new file mode 100644 index 000000000..4e1bdf314 --- /dev/null +++ b/tools/syz-declextract/testdata/types.c.info @@ -0,0 +1 @@ +SYSCALL types_syscall func:__do_sys_types_syscall access:unknown manual_desc:false auto_desc:true file:types.c subsystem:kernel diff --git a/tools/syz-declextract/testdata/types.c.json b/tools/syz-declextract/testdata/types.c.json new file mode 100644 index 000000000..df19ab4a4 --- /dev/null +++ b/tools/syz-declextract/testdata/types.c.json @@ -0,0 +1,555 @@ +{ + "defines": [ + { + "name": "a", + "value": "0" + }, + { + "name": "b", + "value": "1" + }, + { + "name": "c", + "value": "2" + } + ], + "enums": [ + { + "name": "bitfield_enum", + "values": [ + "a", + "b", + "c" + ] + } + ], + "structs": [ + { + "name": "anon_struct", + "byte_size": 104, + "fields": [ + { + "name": "a", + "counted_by": -1, + "type": { + "struct": "anon_struct_a" + } + }, + { + "name": "b", + "counted_by": -1, + "type": { + "struct": "anon_struct_b" + } + }, + { + "name": "anon_struct_2", + "is_anonymous": true, + "counted_by": -1, + "type": { + "struct": "anon_struct_2" + } + }, + { + "name": "anon_struct_3", + "is_anonymous": true, + "counted_by": -1, + "type": { + "struct": "anon_struct_3" + } + }, + { + "name": "foo", + "counted_by": -1, + "type": { + "struct": "anon_t" + } + }, + { + "name": "forward", + "counted_by": -1, + "type": { + "ptr": { + "elem": { + "int": { + "byte_size": 8, + "name": "TODO", + "base": "long" + } + } + } + } + }, + { + "name": "array", + "counted_by": -1, + "type": { + "array": { + "elem": { + "struct": "anon_struct_array" + }, + "min_size": 4, + "max_size": 4 + } + } + }, + { + "name": "ptr", + "counted_by": -1, + "type": { + "ptr": { + "elem": { + "struct": "anon_struct_ptr" + } + } + } + }, + { + "name": "ptr_array", + "counted_by": -1, + "type": { + "array": { + "elem": { + "ptr": { + "elem": { + "struct": "anon_struct_ptr_array" + } + } + }, + "min_size": 4, + "max_size": 4 + } + } + } + ] + }, + { + "name": "anon_struct_2", + "byte_size": 4, + "fields": [ + { + "name": "y", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + } + ] + }, + { + "name": "anon_struct_3", + "byte_size": 8, + "is_union": true, + "fields": [ + { + "name": "q", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + }, + { + "name": "w", + "counted_by": -1, + "type": { + "int": { + "byte_size": 8, + "name": "long", + "base": "long" + } + } + } + ] + }, + { + "name": "anon_struct_a", + "byte_size": 4, + "fields": [ + { + "name": "x", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + } + ] + }, + { + "name": "anon_struct_array", + "byte_size": 8, + "fields": [ + { + "name": "a", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + }, + { + "name": "b", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + } + ] + }, + { + "name": "anon_struct_b" + }, + { + "name": "anon_struct_ptr", + "byte_size": 8, + "fields": [ + { + "name": "a", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + }, + { + "name": "b", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + } + ] + }, + { + "name": "anon_struct_ptr_array", + "byte_size": 8, + "fields": [ + { + "name": "a", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + }, + { + "name": "b", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + } + ] + }, + { + "name": "anon_t", + "byte_size": 4, + "fields": [ + { + "name": "f", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "float", + "base": "float" + } + } + } + ] + }, + { + "name": "bitfields", + "byte_size": 32, + "align": 32, + "fields": [ + { + "name": "a", + "bit_width": 1, + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + }, + { + "name": "bitfields_1", + "is_anonymous": true, + "bit_width": 2, + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + }, + { + "name": "b", + "bit_width": 3, + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + }, + { + "name": "d", + "bit_width": 2, + "counted_by": -1, + "type": { + "int": { + "byte_size": 8, + "name": "long", + "base": "long" + } + } + }, + { + "name": "pad", + "bit_width": 3, + "counted_by": -1, + "type": { + "int": { + "byte_size": 8, + "name": "long", + "base": "long" + } + } + }, + { + "name": "e", + "bit_width": 10, + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "enum": "bitfield_enum" + } + } + }, + { + "name": "l", + "bit_width": 10, + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + }, + { + "name": "p", + "counted_by": 6, + "type": { + "ptr": { + "elem": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + } + } + } + ] + }, + { + "name": "empty_struct" + }, + { + "name": "packed_t", + "byte_size": 32, + "is_packed": true, + "align": 32, + "fields": [ + { + "name": "x", + "counted_by": -1, + "type": { + "int": { + "byte_size": 1, + "name": "char", + "base": "char" + } + } + }, + { + "name": "y", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + } + ] + }, + { + "name": "recursive", + "byte_size": 64, + "fields": [ + { + "name": "various", + "counted_by": -1, + "type": { + "struct": "various" + } + } + ] + }, + { + "name": "various", + "byte_size": 64, + "fields": [ + { + "name": "recursive", + "counted_by": -1, + "type": { + "ptr": { + "elem": { + "struct": "various" + } + } + } + }, + { + "name": "next", + "counted_by": -1, + "type": { + "ptr": { + "elem": { + "struct": "recursive" + } + } + } + }, + { + "name": "packed", + "counted_by": -1, + "type": { + "struct": "packed_t" + } + } + ] + } + ], + "syscalls": [ + { + "func": "__do_sys_types_syscall", + "args": [ + { + "name": "p", + "counted_by": -1, + "type": { + "ptr": { + "elem": { + "struct": "anon_struct" + } + } + } + }, + { + "name": "y", + "counted_by": -1, + "type": { + "ptr": { + "elem": { + "struct": "empty_struct" + } + } + } + }, + { + "name": "b", + "counted_by": -1, + "type": { + "ptr": { + "elem": { + "struct": "bitfields" + } + } + } + }, + { + "name": "pid", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "int", + "base": "int" + } + } + }, + { + "name": "f", + "counted_by": -1, + "type": { + "int": { + "byte_size": 4, + "name": "fd_t", + "base": "int" + } + } + }, + { + "name": "v", + "counted_by": -1, + "type": { + "ptr": { + "elem": { + "struct": "various" + } + } + } + } + ], + "source_file": "types.c" + } + ] +} \ No newline at end of file diff --git a/tools/syz-declextract/testdata/types.c.txt b/tools/syz-declextract/testdata/types.c.txt new file mode 100644 index 000000000..d7586effc --- /dev/null +++ b/tools/syz-declextract/testdata/types.c.txt @@ -0,0 +1,87 @@ +# Code generated by syz-declextract. DO NOT EDIT. + +meta automatic + +type auto_todo intptr + +include +include +include + +auto_bitfield_enum = a, b, c + +types_syscall$auto(p ptr[inout, anon_struct$auto_record], y ptr[inout, void], b ptr[inout, bitfields$auto_record], pid pid, f int32, v ptr[inout, various$auto_record]) + +anon_struct$auto_record { + a anon_struct_a$auto_record + b void + anon_struct_2 anon_struct_2$auto_record + anon_struct_3 anon_struct_3$auto_record + foo anon_t$auto_record + forward ptr[inout, auto_todo] + array array[anon_struct_array$auto_record, 4] + ptr ptr[inout, anon_struct_ptr$auto_record] + ptr_array array[ptr[inout, anon_struct_ptr_array$auto_record], 4] +} + +anon_struct_2$auto_record { + y int32 +} + +anon_struct_3$auto_record [ + q int32 + w intptr +] + +anon_struct_a$auto_record { + x int32 +} + +anon_struct_array$auto_record { + a int32 + b int32 +} + +anon_struct_ptr$auto_record { + a int32 + b int32 +} + +anon_struct_ptr_array$auto_record { + a int32 + b int32 +} + +anon_t$auto_record { + f int32 +} + +bitfields$auto_record { + a int32:1 + bitfields_1 const[0, int32:2] + b int32:3 + d intptr:2 + pad const[0, intptr:3] + e flags[auto_bitfield_enum, int32:10] + l len[p, int32:10] + p ptr[inout, int32] +} [align[32]] + +packed_t$auto_record { + x int8 + y int32 +} [packed, align[32]] + +recursive$auto_record { + various various$auto_record +} + +various$auto_record { + recursive ptr[inout, various$auto_record, opt] + next ptr[inout, recursive$auto_record, opt] + packed packed_t$auto_record +} + +define a 0 +define b 1 +define c 2 -- cgit mrf-deployment