From a97c527ac491cc13f6778010a2a81c84642ea1ca Mon Sep 17 00:00:00 2001 From: Rhys Hiltner Date: Wed, 29 Sep 2021 17:35:27 -0700 Subject: [PATCH] runtime: add padding to Linux kernel structures Go exchanges siginfo and sigevent structures with the kernel. They contain unions, but Go's use is limited to the first few fields. Pad out the rest so the size Go sees is the same as what the Linux kernel sees. This is a follow-up to CL 342052 which added the sigevent struct without padding, and to CL 353136 which added the padding but with an assertion that confused several type-checkers. It updates the siginfo struct as well so there are no bad examples in the defs_linux_*.go files. Reviewed-on: https://go-review.googlesource.com/c/go/+/353136 Change-Id: I9610632ff0ec43eba91f560536f5441fa907b36f Reviewed-on: https://go-review.googlesource.com/c/go/+/360094 Run-TryBot: Ian Lance Taylor Reviewed-by: Ian Lance Taylor Reviewed-by: Michael Pratt --- src/runtime/defs_linux_386.go | 20 ++++++++++++++++++-- src/runtime/defs_linux_amd64.go | 20 ++++++++++++++++++-- src/runtime/defs_linux_arm.go | 20 ++++++++++++++++++-- src/runtime/defs_linux_arm64.go | 20 ++++++++++++++++++-- src/runtime/defs_linux_mips64x.go | 20 ++++++++++++++++++-- src/runtime/defs_linux_mipsx.go | 20 ++++++++++++++++++-- src/runtime/defs_linux_ppc64.go | 20 ++++++++++++++++++-- src/runtime/defs_linux_ppc64le.go | 20 ++++++++++++++++++-- src/runtime/defs_linux_riscv64.go | 20 ++++++++++++++++++-- src/runtime/defs_linux_s390x.go | 20 ++++++++++++++++++-- src/runtime/export_linux_test.go | 5 +++++ src/runtime/os_linux.go | 16 ++++++++++------ src/runtime/runtime_linux_test.go | 11 +++++++++++ 13 files changed, 206 insertions(+), 26 deletions(-) diff --git a/src/runtime/defs_linux_386.go b/src/runtime/defs_linux_386.go index d8b546cb4c..24fb58bbf8 100644 --- a/src/runtime/defs_linux_386.go +++ b/src/runtime/defs_linux_386.go @@ -3,6 +3,8 @@ package runtime +import "unsafe" + const ( _EINTR = 0x4 _EAGAIN = 0xb @@ -166,7 +168,7 @@ type sigactiont struct { sa_mask uint64 } -type siginfo struct { +type siginfoFields struct { si_signo int32 si_errno int32 si_code int32 @@ -174,6 +176,13 @@ type siginfo struct { si_addr uint32 } +type siginfo struct { + siginfoFields + + // Pad struct to the max size in the kernel. + _ [_si_max_size - unsafe.Sizeof(siginfoFields{})]byte +} + type stackt struct { ss_sp *byte ss_flags int32 @@ -229,7 +238,7 @@ type itimerval struct { it_value timeval } -type sigevent struct { +type sigeventFields struct { value uintptr signo int32 notify int32 @@ -237,6 +246,13 @@ type sigevent struct { sigev_notify_thread_id int32 } +type sigevent struct { + sigeventFields + + // Pad struct to the max size in the kernel. + _ [_sigev_max_size - unsafe.Sizeof(sigeventFields{})]byte +} + type epollevent struct { events uint32 data [8]byte // to match amd64 diff --git a/src/runtime/defs_linux_amd64.go b/src/runtime/defs_linux_amd64.go index 6afb67f77f..36da22f8ce 100644 --- a/src/runtime/defs_linux_amd64.go +++ b/src/runtime/defs_linux_amd64.go @@ -3,6 +3,8 @@ package runtime +import "unsafe" + const ( _EINTR = 0x4 _EAGAIN = 0xb @@ -128,7 +130,7 @@ type sigactiont struct { sa_mask uint64 } -type siginfo struct { +type siginfoFields struct { si_signo int32 si_errno int32 si_code int32 @@ -136,6 +138,13 @@ type siginfo struct { si_addr uint64 } +type siginfo struct { + siginfoFields + + // Pad struct to the max size in the kernel. + _ [_si_max_size - unsafe.Sizeof(siginfoFields{})]byte +} + type itimerspec struct { it_interval timespec it_value timespec @@ -146,7 +155,7 @@ type itimerval struct { it_value timeval } -type sigevent struct { +type sigeventFields struct { value uintptr signo int32 notify int32 @@ -154,6 +163,13 @@ type sigevent struct { sigev_notify_thread_id int32 } +type sigevent struct { + sigeventFields + + // Pad struct to the max size in the kernel. + _ [_sigev_max_size - unsafe.Sizeof(sigeventFields{})]byte +} + type epollevent struct { events uint32 data [8]byte // unaligned uintptr diff --git a/src/runtime/defs_linux_arm.go b/src/runtime/defs_linux_arm.go index ec24d76326..13d06969e3 100644 --- a/src/runtime/defs_linux_arm.go +++ b/src/runtime/defs_linux_arm.go @@ -4,6 +4,8 @@ package runtime +import "unsafe" + // Constants const ( _EINTR = 0x4 @@ -169,7 +171,7 @@ type itimerval struct { it_value timeval } -type sigevent struct { +type sigeventFields struct { value uintptr signo int32 notify int32 @@ -177,7 +179,14 @@ type sigevent struct { sigev_notify_thread_id int32 } -type siginfo struct { +type sigevent struct { + sigeventFields + + // Pad struct to the max size in the kernel. + _ [_sigev_max_size - unsafe.Sizeof(sigeventFields{})]byte +} + +type siginfoFields struct { si_signo int32 si_errno int32 si_code int32 @@ -185,6 +194,13 @@ type siginfo struct { si_addr uint32 } +type siginfo struct { + siginfoFields + + // Pad struct to the max size in the kernel. + _ [_si_max_size - unsafe.Sizeof(siginfoFields{})]byte +} + type sigactiont struct { sa_handler uintptr sa_flags uint32 diff --git a/src/runtime/defs_linux_arm64.go b/src/runtime/defs_linux_arm64.go index f9f175004b..f9ee9cbc35 100644 --- a/src/runtime/defs_linux_arm64.go +++ b/src/runtime/defs_linux_arm64.go @@ -3,6 +3,8 @@ package runtime +import "unsafe" + const ( _EINTR = 0x4 _EAGAIN = 0xb @@ -128,7 +130,7 @@ type sigactiont struct { sa_mask uint64 } -type siginfo struct { +type siginfoFields struct { si_signo int32 si_errno int32 si_code int32 @@ -136,6 +138,13 @@ type siginfo struct { si_addr uint64 } +type siginfo struct { + siginfoFields + + // Pad struct to the max size in the kernel. + _ [_si_max_size - unsafe.Sizeof(siginfoFields{})]byte +} + type itimerspec struct { it_interval timespec it_value timespec @@ -146,7 +155,7 @@ type itimerval struct { it_value timeval } -type sigevent struct { +type sigeventFields struct { value uintptr signo int32 notify int32 @@ -154,6 +163,13 @@ type sigevent struct { sigev_notify_thread_id int32 } +type sigevent struct { + sigeventFields + + // Pad struct to the max size in the kernel. + _ [_sigev_max_size - unsafe.Sizeof(sigeventFields{})]byte +} + type epollevent struct { events uint32 _pad uint32 diff --git a/src/runtime/defs_linux_mips64x.go b/src/runtime/defs_linux_mips64x.go index 63433cb9be..2601082ee1 100644 --- a/src/runtime/defs_linux_mips64x.go +++ b/src/runtime/defs_linux_mips64x.go @@ -6,6 +6,8 @@ package runtime +import "unsafe" + const ( _EINTR = 0x4 _EAGAIN = 0xb @@ -134,7 +136,7 @@ type sigactiont struct { sa_restorer uintptr } -type siginfo struct { +type siginfoFields struct { si_signo int32 si_code int32 si_errno int32 @@ -143,6 +145,13 @@ type siginfo struct { si_addr uint64 } +type siginfo struct { + siginfoFields + + // Pad struct to the max size in the kernel. + _ [_si_max_size - unsafe.Sizeof(siginfoFields{})]byte +} + type itimerspec struct { it_interval timespec it_value timespec @@ -153,7 +162,7 @@ type itimerval struct { it_value timeval } -type sigevent struct { +type sigeventFields struct { value uintptr signo int32 notify int32 @@ -161,6 +170,13 @@ type sigevent struct { sigev_notify_thread_id int32 } +type sigevent struct { + sigeventFields + + // Pad struct to the max size in the kernel. + _ [_sigev_max_size - unsafe.Sizeof(sigeventFields{})]byte +} + type epollevent struct { events uint32 pad_cgo_0 [4]byte diff --git a/src/runtime/defs_linux_mipsx.go b/src/runtime/defs_linux_mipsx.go index ffbf5051eb..37651ef7e4 100644 --- a/src/runtime/defs_linux_mipsx.go +++ b/src/runtime/defs_linux_mipsx.go @@ -6,6 +6,8 @@ package runtime +import "unsafe" + const ( _EINTR = 0x4 _EAGAIN = 0xb @@ -129,7 +131,7 @@ type sigactiont struct { sa_restorer uintptr } -type siginfo struct { +type siginfoFields struct { si_signo int32 si_code int32 si_errno int32 @@ -137,6 +139,13 @@ type siginfo struct { si_addr uint32 } +type siginfo struct { + siginfoFields + + // Pad struct to the max size in the kernel. + _ [_si_max_size - unsafe.Sizeof(siginfoFields{})]byte +} + type itimerspec struct { it_interval timespec it_value timespec @@ -147,7 +156,7 @@ type itimerval struct { it_value timeval } -type sigevent struct { +type sigeventFields struct { value uintptr signo int32 notify int32 @@ -155,6 +164,13 @@ type sigevent struct { sigev_notify_thread_id int32 } +type sigevent struct { + sigeventFields + + // Pad struct to the max size in the kernel. + _ [_sigev_max_size - unsafe.Sizeof(sigeventFields{})]byte +} + type epollevent struct { events uint32 pad_cgo_0 [4]byte diff --git a/src/runtime/defs_linux_ppc64.go b/src/runtime/defs_linux_ppc64.go index e0775e2974..c7aa7234c1 100644 --- a/src/runtime/defs_linux_ppc64.go +++ b/src/runtime/defs_linux_ppc64.go @@ -3,6 +3,8 @@ package runtime +import "unsafe" + const ( _EINTR = 0x4 _EAGAIN = 0xb @@ -129,7 +131,7 @@ type sigactiont struct { sa_mask uint64 } -type siginfo struct { +type siginfoFields struct { si_signo int32 si_errno int32 si_code int32 @@ -137,6 +139,13 @@ type siginfo struct { si_addr uint64 } +type siginfo struct { + siginfoFields + + // Pad struct to the max size in the kernel. + _ [_si_max_size - unsafe.Sizeof(siginfoFields{})]byte +} + type itimerspec struct { it_interval timespec it_value timespec @@ -147,7 +156,7 @@ type itimerval struct { it_value timeval } -type sigevent struct { +type sigeventFields struct { value uintptr signo int32 notify int32 @@ -155,6 +164,13 @@ type sigevent struct { sigev_notify_thread_id int32 } +type sigevent struct { + sigeventFields + + // Pad struct to the max size in the kernel. + _ [_sigev_max_size - unsafe.Sizeof(sigeventFields{})]byte +} + type epollevent struct { events uint32 pad_cgo_0 [4]byte diff --git a/src/runtime/defs_linux_ppc64le.go b/src/runtime/defs_linux_ppc64le.go index e0775e2974..c7aa7234c1 100644 --- a/src/runtime/defs_linux_ppc64le.go +++ b/src/runtime/defs_linux_ppc64le.go @@ -3,6 +3,8 @@ package runtime +import "unsafe" + const ( _EINTR = 0x4 _EAGAIN = 0xb @@ -129,7 +131,7 @@ type sigactiont struct { sa_mask uint64 } -type siginfo struct { +type siginfoFields struct { si_signo int32 si_errno int32 si_code int32 @@ -137,6 +139,13 @@ type siginfo struct { si_addr uint64 } +type siginfo struct { + siginfoFields + + // Pad struct to the max size in the kernel. + _ [_si_max_size - unsafe.Sizeof(siginfoFields{})]byte +} + type itimerspec struct { it_interval timespec it_value timespec @@ -147,7 +156,7 @@ type itimerval struct { it_value timeval } -type sigevent struct { +type sigeventFields struct { value uintptr signo int32 notify int32 @@ -155,6 +164,13 @@ type sigevent struct { sigev_notify_thread_id int32 } +type sigevent struct { + sigeventFields + + // Pad struct to the max size in the kernel. + _ [_sigev_max_size - unsafe.Sizeof(sigeventFields{})]byte +} + type epollevent struct { events uint32 pad_cgo_0 [4]byte diff --git a/src/runtime/defs_linux_riscv64.go b/src/runtime/defs_linux_riscv64.go index 1052213a4c..332720a8c8 100644 --- a/src/runtime/defs_linux_riscv64.go +++ b/src/runtime/defs_linux_riscv64.go @@ -4,6 +4,8 @@ package runtime +import "unsafe" + const ( _EINTR = 0x4 _EAGAIN = 0xb @@ -126,7 +128,7 @@ type sigactiont struct { sa_mask uint64 } -type siginfo struct { +type siginfoFields struct { si_signo int32 si_errno int32 si_code int32 @@ -134,6 +136,13 @@ type siginfo struct { si_addr uint64 } +type siginfo struct { + siginfoFields + + // Pad struct to the max size in the kernel. + _ [_si_max_size - unsafe.Sizeof(siginfoFields{})]byte +} + type itimerspec struct { it_interval timespec it_value timespec @@ -144,7 +153,7 @@ type itimerval struct { it_value timeval } -type sigevent struct { +type sigeventFields struct { value uintptr signo int32 notify int32 @@ -152,6 +161,13 @@ type sigevent struct { sigev_notify_thread_id int32 } +type sigevent struct { + sigeventFields + + // Pad struct to the max size in the kernel. + _ [_sigev_max_size - unsafe.Sizeof(sigeventFields{})]byte +} + type epollevent struct { events uint32 pad_cgo_0 [4]byte diff --git a/src/runtime/defs_linux_s390x.go b/src/runtime/defs_linux_s390x.go index b072955d4a..740d8100c5 100644 --- a/src/runtime/defs_linux_s390x.go +++ b/src/runtime/defs_linux_s390x.go @@ -4,6 +4,8 @@ package runtime +import "unsafe" + const ( _EINTR = 0x4 _EAGAIN = 0xb @@ -125,7 +127,7 @@ type sigactiont struct { sa_mask uint64 } -type siginfo struct { +type siginfoFields struct { si_signo int32 si_errno int32 si_code int32 @@ -133,6 +135,13 @@ type siginfo struct { si_addr uint64 } +type siginfo struct { + siginfoFields + + // Pad struct to the max size in the kernel. + _ [_si_max_size - unsafe.Sizeof(siginfoFields{})]byte +} + type itimerspec struct { it_interval timespec it_value timespec @@ -143,7 +152,7 @@ type itimerval struct { it_value timeval } -type sigevent struct { +type sigeventFields struct { value uintptr signo int32 notify int32 @@ -151,6 +160,13 @@ type sigevent struct { sigev_notify_thread_id int32 } +type sigevent struct { + sigeventFields + + // Pad struct to the max size in the kernel. + _ [_sigev_max_size - unsafe.Sizeof(sigeventFields{})]byte +} + type epollevent struct { events uint32 pad_cgo_0 [4]byte diff --git a/src/runtime/export_linux_test.go b/src/runtime/export_linux_test.go index b7c901f238..dea94a934c 100644 --- a/src/runtime/export_linux_test.go +++ b/src/runtime/export_linux_test.go @@ -8,11 +8,16 @@ package runtime import "unsafe" +const SiginfoMaxSize = _si_max_size +const SigeventMaxSize = _sigev_max_size + var NewOSProc0 = newosproc0 var Mincore = mincore var Add = add type EpollEvent epollevent +type Siginfo siginfo +type Sigevent sigevent func Epollctl(epfd, op, fd int32, ev unsafe.Pointer) int32 { return epollctl(epfd, op, fd, (*epollevent)(ev)) diff --git a/src/runtime/os_linux.go b/src/runtime/os_linux.go index 06773c2193..32a1e1b4f7 100644 --- a/src/runtime/os_linux.go +++ b/src/runtime/os_linux.go @@ -440,6 +440,11 @@ func pipe() (r, w int32, errno int32) func pipe2(flags int32) (r, w int32, errno int32) func setNonblock(fd int32) +const ( + _si_max_size = 128 + _sigev_max_size = 64 +) + //go:nosplit //go:nowritebarrierrec func setsig(i uint32, fn uintptr) { @@ -636,12 +641,11 @@ func setThreadCPUProfiler(hz int32) { spec.it_interval.setNsec(1e9 / int64(hz)) var timerid int32 - sevp := &sigevent{ - notify: _SIGEV_THREAD_ID, - signo: _SIGPROF, - sigev_notify_thread_id: int32(mp.procid), - } - ret := timer_create(_CLOCK_THREAD_CPUTIME_ID, sevp, &timerid) + var sevp sigevent + sevp.notify = _SIGEV_THREAD_ID + sevp.signo = _SIGPROF + sevp.sigev_notify_thread_id = int32(mp.procid) + ret := timer_create(_CLOCK_THREAD_CPUTIME_ID, &sevp, &timerid) if ret != 0 { // If we cannot create a timer for this M, leave profileTimerValid false // to fall back to the process-wide setitimer profiler. diff --git a/src/runtime/runtime_linux_test.go b/src/runtime/runtime_linux_test.go index cd59368cb2..a753aeea58 100644 --- a/src/runtime/runtime_linux_test.go +++ b/src/runtime/runtime_linux_test.go @@ -61,3 +61,14 @@ func TestEpollctlErrorSign(t *testing.T) { t.Errorf("epollctl = %v, want %v", v, -EBADF) } } + +func TestKernelStructSize(t *testing.T) { + // Check that the Go definitions of structures exchanged with the kernel are + // the same size as what the kernel defines. + if have, want := unsafe.Sizeof(Siginfo{}), uintptr(SiginfoMaxSize); have != want { + t.Errorf("Go's siginfo struct is %d bytes long; kernel expects %d", have, want) + } + if have, want := unsafe.Sizeof(Sigevent{}), uintptr(SigeventMaxSize); have != want { + t.Errorf("Go's sigevent struct is %d bytes long; kernel expects %d", have, want) + } +} -- 2.50.0