aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2024-01-04 16:59:50 +0100
committerAleksandr Nogikh <nogikh@google.com>2024-02-19 11:54:01 +0000
commit3af7dd651dc78ce0784bef793d14dd2f72d07138 (patch)
tree112d4bd0ae54628d3934b2f6b9f7a11cb699983e /docs
parent8cb16e665dbb5f87aa58856049c1ad6067dc6293 (diff)
docs: describe conditional fields
Diffstat (limited to 'docs')
-rw-r--r--docs/syscall_descriptions_syntax.md191
1 files changed, 188 insertions, 3 deletions
diff --git a/docs/syscall_descriptions_syntax.md b/docs/syscall_descriptions_syntax.md
index 5334ec911..fe3b72a3e 100644
--- a/docs/syscall_descriptions_syntax.md
+++ b/docs/syscall_descriptions_syntax.md
@@ -137,7 +137,7 @@ Structs are described as:
```
structname "{" "\n"
- (fieldname type ("(" fieldattribute* ")")? "\n")+
+ (fieldname type ("(" fieldattribute* ")")? (if[expression])? "\n")+
"}" ("[" attribute* "]")?
```
@@ -152,6 +152,18 @@ foo {
}
```
+You may specify conditions that determine whether a field will be included:
+
+```
+foo {
+ field0 int32
+ field1 int32 (if[value[field0] == 0x1])
+}
+```
+
+See [the corresponding section](syscall_descriptions_syntax.md#conditional-fields)
+for more details.
+
`out_overlay` attribute allows to have separate input and output layouts for the struct.
Fields before the `out_overlay` field are input, fields starting from `out_overlay` are output.
Input and output fields overlap in memory (both start from the beginning of the struct in memory).
@@ -167,7 +179,6 @@ foo {
}
```
-
Structs can have attributes specified in square brackets after the struct.
Attributes are:
@@ -181,10 +192,17 @@ Unions are described as:
```
unionname "[" "\n"
- (fieldname type "\n")+
+ (fieldname type (if[expression])? "\n")+
"]" ("[" attribute* "]")?
```
+During fuzzing, syzkaller randomly picks one of the union options.
+
+You may also specify conditions that determine whether the corresponding
+option may or may not be selected, depending on values of other fields. See
+[the corresponding section](syscall_descriptions_syntax.md#conditional-fields)
+for more details.
+
Unions can have attributes specified in square brackets after the union.
Attributes are:
@@ -405,6 +423,173 @@ foo(a ptr[in, array[int8, MY_PATH_MAX]])
define MY_PATH_MAX PATH_MAX + 2
```
+## Conditional fields
+
+### In structures
+
+In syzlang, it's possible to specify a condition for every struct field that
+determines whether the field should be included or omitted:
+
+```
+header_fields {
+ magic const[0xabcd, int16]
+ haveInteger int8
+} [packed]
+
+packet {
+ header header_fields
+ integer int64 (if[value[header:haveInteger] == 0x1])
+ body array[int8]
+} [packed]
+
+some_call(a ptr[in, packet])
+```
+
+In this example, the `packet` structure will include the field `integer` only
+if `header.haveInteger == 1`. In memory, `packet` will have the following
+layout:
+
+| header_files.magic = 0xabcd | header_files.haveInteger = 0x1 | integer | body |
+| - | - | - | - |
+
+
+That corresponds to e.g. the following program:
+```
+some_call(&AUTO={{AUTO, 0x1}, @value=0xabcd, []})
+```
+
+If `header.haveInteger` is not `1`, syzkaller will just pretend that the field
+`integer` does not exist.
+```
+some_call(&AUTO={{AUTO, 0x0}, @void, []})
+```
+
+| header_files.magic = 0xabcd | header_files.haveInteger = 0x0 | body |
+| - | - | - |
+
+Every conditional field is assumed to be of variable length and so is the struct
+to which this field belongs.
+
+When a variable length field appears in the middle of a structure, the structure
+must be marked with `[packed].`
+
+Conditions on bitfields are prohibited:
+```
+struct {
+ f0 int
+ f1 int:3 (if[value[f0] == 0x1]) # It will not compile.
+}
+```
+
+But you may reference bitfields in your conditions:
+```
+struct {
+ f0 int:1
+ f1 int:7
+ f2 int (if[value[f0] == value[f1]])
+} [packed]
+```
+
+### In unions
+
+Let's consider the following example.
+
+```
+struct {
+ type int
+ body alternatives
+}
+
+alternatives [
+ int int64 (if[value[struct:type] == 0x1])
+ arr array[int64, 5] (if[value[struct:type] == 0x2])
+ default int32
+] [varlen]
+
+some_call(a ptr[in, struct])
+```
+
+In this case, the union option will be selected depending on the value of the
+`type` field. For example, if `type` is `0x1`, then it can be either `int` or
+`default`:
+```
+some_call(&AUTO={0x1, @int=0x123})
+some_call(&AUTO={0x1, @default=0x123})
+```
+
+If `type` is `0x2`, it can be either `arr` or `default`.
+
+If `type` is neither `0x1` nor `0x2`, syzkaller may only select `default`:
+```
+some_call(&AUTO={0x0, @default=0xabcd})
+```
+
+To ensure that a union can always be constructed, the last union field **must always
+have no condition**.
+
+Thus, the following definition would fail to compile:
+
+```
+alternatives [
+ int int64 (if[value[struct:type] == 0x1])
+ arr array[int64, 5] (if[value[struct:type] == 0x1])
+] [varlen]
+```
+
+During prog mutation and generation syzkaller will select a random union field
+whose condition is satisfied.
+
+
+### Expression syntax
+
+Currently, only `==`, `!=` and `&` operators are supported. However, the
+functionality was designed in such a way that adding more operators is easy.
+Feel free to file a GitHub issue or write us an email in case it's needed.
+
+Expressions are evaluated as `int64` values. If the final result of an
+expression is not 0, it's assumed to be satisfied.
+
+If you want to reference a field's value, you can do it via
+`value[path:to:field]`, which is similar to the `len[]` argument.
+
+```
+sub_struct {
+ f0 int
+ # Reference a field in a parent struct.
+ f1 int (if[value[struct:f2]]) # Same as if[value[struct:f2] != 0]].
+}
+
+struct {
+ f2 int
+ f3 sub_struct
+ f4 int (if[value[f2] == 0x2]) # Reference a sibling field.
+ f5 int (if[value[f3:f0] == 0x1]) # Reference a nested field.
+} [packed]
+
+call(a ptr[in, struct])
+```
+
+The referenced field must be of integer type and there must be no
+conditional fields in the path to it. For example, the following
+descriptions will not compile.
+
+```
+struct {
+ f0 int
+ f1 int (if[value[f0] == 0x1])
+ f2 int (if[value[f1] == 0x1])
+}
+```
+
+You may also reference constants in expressions:
+```
+struct {
+ f0 int
+ f1 int
+ f2 int (if[value[f0] & SOME_CONST == OTHER_CONST])
+}
+```
+
## Meta
Description files can also contain `meta` directives that specify meta-information for the whole file.