diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2023-04-03 07:45:09 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2023-04-03 10:29:09 +0200 |
| commit | d04ac3a54895a36998e3f1da27c2ce33f7a80c5a (patch) | |
| tree | e79bc6b62402f2b9e1b4cf91bc38b2a6c404e7b1 | |
| parent | 7c00f48c0c766f7abd4601bd9848527dd1e4be77 (diff) | |
sys/linux: add syz_pkey_set syscalls
The syscall sets PKRU register which is part of protection keys (pkey).
| -rw-r--r-- | executor/common_linux.h | 24 | ||||
| -rw-r--r-- | pkg/csource/generated.go | 19 | ||||
| -rw-r--r-- | pkg/host/syscalls_linux.go | 20 | ||||
| -rw-r--r-- | sys/linux/sys.txt | 2 | ||||
| -rw-r--r-- | sys/linux/test/pkey | 10 |
5 files changed, 75 insertions, 0 deletions
diff --git a/executor/common_linux.h b/executor/common_linux.h index e53a908ab..a2736624a 100644 --- a/executor/common_linux.h +++ b/executor/common_linux.h @@ -5547,3 +5547,27 @@ static long syz_clone3(volatile long a0, volatile long a1) } #endif + +#if SYZ_EXECUTOR || __NR_syz_pkey_set +// syz_pkey_set(key pkey, val flags[pkey_flags]) +static long syz_pkey_set(volatile long pkey, volatile long val) +{ +#if GOARCH_amd64 || GOARCH_386 + uint32 eax = 0; + uint32 ecx = 0; + asm volatile("rdpkru" + : "=a"(eax) + : "c"(ecx) + : "edx"); + // PKRU register contains 2 bits per key. + // Max number of keys is 16. + // Clear old bits for the key: + eax &= ~(3 << ((pkey % 16) * 2)); + // Set new bits for the key: + eax |= (val & 3) << ((pkey % 16) * 2); + uint32 edx = 0; + asm volatile("wrpkru" ::"a"(eax), "c"(ecx), "d"(edx)); +#endif + return 0; +} +#endif diff --git a/pkg/csource/generated.go b/pkg/csource/generated.go index 552cc9191..204d6d2ee 100644 --- a/pkg/csource/generated.go +++ b/pkg/csource/generated.go @@ -11378,6 +11378,25 @@ static long syz_clone3(volatile long a0, volatile long a1) #endif +#if SYZ_EXECUTOR || __NR_syz_pkey_set +static long syz_pkey_set(volatile long pkey, volatile long val) +{ +#if GOARCH_amd64 || GOARCH_386 + uint32 eax = 0; + uint32 ecx = 0; + asm volatile("rdpkru" + : "=a"(eax) + : "c"(ecx) + : "edx"); + eax &= ~(3 << ((pkey % 16) * 2)); + eax |= (val & 3) << ((pkey % 16) * 2); + uint32 edx = 0; + asm volatile("wrpkru" ::"a"(eax), "c"(ecx), "d"(edx)); +#endif + return 0; +} +#endif + #elif GOOS_test #include <stdlib.h> diff --git a/pkg/host/syscalls_linux.go b/pkg/host/syscalls_linux.go index 67efd9295..7037dc001 100644 --- a/pkg/host/syscalls_linux.go +++ b/pkg/host/syscalls_linux.go @@ -18,6 +18,7 @@ import ( "github.com/google/syzkaller/pkg/osutil" "github.com/google/syzkaller/prog" "github.com/google/syzkaller/sys/targets" + "golang.org/x/sys/unix" ) func isSupported(c *prog.Syscall, target *prog.Target, sandbox string) (bool, string) { @@ -37,6 +38,9 @@ func isSupported(c *prog.Syscall, target *prog.Target, sandbox string) (bool, st if strings.HasPrefix(c.Name, "mount$") { return isSupportedMount(c, sandbox) } + if c.CallName == "pkey_alloc" { + return isSyzPkeySetSupported(c, target, sandbox) + } if c.Name == "ioctl$EXT4_IOC_SHUTDOWN" && sandbox == "none" { // Don't shutdown root filesystem. return false, "unsafe with sandbox=none" @@ -317,6 +321,7 @@ var syzkallSupport = map[string]func(*prog.Syscall, *prog.Target, string) (bool, "syz_usbip_server_init": isSyzUsbIPSupported, "syz_clone": alwaysSupported, "syz_clone3": alwaysSupported, + "syz_pkey_set": isSyzPkeySetSupported, } func isSupportedSyzkall(c *prog.Syscall, target *prog.Target, sandbox string) (bool, string) { @@ -544,3 +549,18 @@ func extractStringConst(typ prog.Type) (string, bool) { } return v, true } + +func isSyzPkeySetSupported(c *prog.Syscall, target *prog.Target, sandbox string) (bool, string) { + if target.Arch != targets.AMD64 && target.Arch != targets.I386 { + return false, "unsupported arch" + } + key, _, err := syscall.Syscall6(unix.SYS_PKEY_ALLOC, 0, 0, 0, 0, 0, 0) + if err != 0 { + return false, fmt.Sprintf("pkey_alloc failed: %v", err) + } + _, _, err = syscall.Syscall6(unix.SYS_PKEY_FREE, key, 0, 0, 0, 0, 0) + if err != 0 { + return false, fmt.Sprintf("pkey_free failed: %v", err) + } + return true, "" +} diff --git a/sys/linux/sys.txt b/sys/linux/sys.txt index 80ece3188..4b403ddd9 100644 --- a/sys/linux/sys.txt +++ b/sys/linux/sys.txt @@ -212,6 +212,8 @@ resource pkey[int32]: -1 pkey_alloc(flags const[0], val flags[pkey_flags]) pkey pkey_free(key pkey) pkey_mprotect(addr vma, len len[addr], prot flags[mmap_prot], key pkey) +syz_pkey_set(key pkey, val flags[pkey_flags]) + pkey_flags = PKEY_DISABLE_ACCESS, PKEY_DISABLE_WRITE restart_syscall() diff --git a/sys/linux/test/pkey b/sys/linux/test/pkey new file mode 100644 index 000000000..063e878cc --- /dev/null +++ b/sys/linux/test/pkey @@ -0,0 +1,10 @@ +# requires: arch=amd64 + +r0 = pkey_alloc(0x0, 0x0) +mmap(&(0x7f0000000000/0x1000)=nil, 0x1000, 0x3, 0x32, 0xffffffffffffffff, 0x0) +pkey_mprotect(&(0x7f0000000000/0x1000)=nil, 0x1000, 0x3, r0) +syz_pkey_set(r0, 0x3) +pipe(&(0x7f0000000000)={0x0, 0x0}) # EFAULT +syz_pkey_set(r0, 0x0) +pipe(&(0x7f0000000000)={0x0, 0x0}) +pkey_free(r0) |
