aboutsummaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2022-01-19 15:18:52 +0000
committerAleksandr Nogikh <wp32pw@gmail.com>2022-01-20 16:29:05 +0100
commitab3d9f17d3b73b74f89b4ea3bd951e09ab4149a8 (patch)
tree68ff87a34750915492e2d1f20060a6d2b961f8ef /sys
parentb838eb76eef06deea9b4ec66dd328e77ca00eb0f (diff)
sys/linux: neutralize sched_setattr
Setting itself or another process as a real-time one leads to the starvation of kernel threads and, as a result, to false positive stall bug reports. We have been getting complaints about them for already quite a long time now. Neutralize the policy argument of the syscall as much as possible given the set of possible syzkaller mutations.
Diffstat (limited to 'sys')
-rw-r--r--sys/linux/init.go49
-rw-r--r--sys/linux/init_test.go20
2 files changed, 69 insertions, 0 deletions
diff --git a/sys/linux/init.go b/sys/linux/init.go
index 88bfe919e..6fa9665a8 100644
--- a/sys/linux/init.go
+++ b/sys/linux/init.go
@@ -230,6 +230,9 @@ func (arch *arch) neutralize(c *prog.Call) {
enforceIntArg(c.Args[0])
enforceIntArg(c.Args[1])
enforceIntArg(c.Args[2])
+ case "sched_setattr":
+ // Enabling a SCHED_FIFO or a SCHED_RR policy may lead to false positive stall-related crashes.
+ neutralizeSchedAttr(c.Args[1])
}
switch c.Meta.Name {
@@ -238,6 +241,52 @@ func (arch *arch) neutralize(c *prog.Call) {
}
}
+func neutralizeSchedAttr(a prog.Arg) {
+ switch attr := a.(type) {
+ case *prog.PointerArg:
+ if attr.Res == nil {
+ // If it's just a pointer to somewhere, still set it to NULL as there's a risk that
+ // it points to the valid memory and it can be interpreted as a sched_attr struct.
+ attr.Address = 0
+ return
+ }
+ groupArg, ok := attr.Res.(*prog.GroupArg)
+ if !ok || len(groupArg.Inner) == 0 {
+ return
+ }
+ if unionArg, ok := groupArg.Inner[0].(*prog.UnionArg); ok {
+ dataArg, ok := unionArg.Option.(*prog.DataArg)
+ if !ok {
+ return
+ }
+ if dataArg.Dir() == prog.DirOut {
+ return
+ }
+ // Clear the first 16 bytes to prevent overcoming the limitation by squashing the struct.
+ data := append([]byte{}, dataArg.Data()...)
+ for i := 0; i < 16 && i < len(data); i++ {
+ data[i] = 0
+ }
+ dataArg.SetData(data)
+ }
+
+ // Most likely it's the intended sched_attr structure.
+ if len(groupArg.Inner) > 1 {
+ policyField, ok := groupArg.Inner[1].(*prog.ConstArg)
+ if !ok {
+ return
+ }
+ const SCHED_FIFO = 0x1
+ const SCHED_RR = 0x2
+ if policyField.Val == SCHED_FIFO || policyField.Val == SCHED_RR {
+ policyField.Val = 0
+ }
+ }
+ case *prog.ConstArg:
+ attr.Val = 0
+ }
+}
+
func enforceIntArg(a prog.Arg) {
arg, ok := a.(*prog.ConstArg)
if !ok {
diff --git a/sys/linux/init_test.go b/sys/linux/init_test.go
index ed4cf03a1..8c236af5d 100644
--- a/sys/linux/init_test.go
+++ b/sys/linux/init_test.go
@@ -145,5 +145,25 @@ ioctl$X86_IOC_RDMSR_REGS(0xa, 0xc02063a0, 0x0)
ioctl$X86_IOC_RDMSR_REGS(0xa, 0xc02063a0, 0x0)
`,
},
+ {
+ In: `sched_setattr(0x0, &(0x7f00000002c0)={0x0, 0x1, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0}, 0x0)`,
+ Out: `sched_setattr(0x0, &(0x7f00000002c0)={0x0, 0x0, 0x0, 0x0, 0x3}, 0x0)`,
+ },
+ {
+ In: `sched_setattr(0x0, &(0x7f00000002c0)={0x0, 0x2, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0}, 0x0)`,
+ Out: `sched_setattr(0x0, &(0x7f00000002c0)={0x0, 0x0, 0x0, 0x0, 0x3}, 0x0)`,
+ },
+ {
+ In: `sched_setattr(0x0, &(0x7f00000002c0)={0x0, 0x3, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0}, 0x0)`,
+ Out: `sched_setattr(0x0, &(0x7f00000002c0)={0x0, 0x3, 0x0, 0x0, 0x3}, 0x0)`,
+ },
+ {
+ In: `sched_setattr(0x0, 0x123456, 0x0)`,
+ Out: `sched_setattr(0x0, 0x0, 0x0)`,
+ },
+ {
+ In: `sched_setattr(0x0, &(0x7f00000001c0)=ANY=[@ANYBLOB="1234567812345678"], 0x0)`,
+ Out: `sched_setattr(0x0, &(0x7f00000001c0)=ANY=[@ANYBLOB='\x00\x00\x00\x00\x00\x00\x00\x00'], 0x0)`,
+ },
})
}