runtime: don't mlock on Ubuntu 5.4 systems

For #35777
For #37436
Fixes #40184

Change-Id: I68561497d9258e994d1c6c48d4fb41ac6130ee3a
Reviewed-on: https://go-review.googlesource.com/c/go/+/244059
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
diff --git a/src/runtime/os_linux_x86.go b/src/runtime/os_linux_x86.go
index d001e6e..97f8707 100644
--- a/src/runtime/os_linux_x86.go
+++ b/src/runtime/os_linux_x86.go
@@ -7,7 +7,10 @@
 
 package runtime
 
-import "runtime/internal/atomic"
+import (
+	"runtime/internal/atomic"
+	"unsafe"
+)
 
 //go:noescape
 func uname(utsname *new_utsname) int
@@ -55,6 +58,36 @@
 		return
 	}
 
+	if major == 5 && minor == 4 && patch < 2 {
+		// All 5.4 versions of Ubuntu are patched.
+		procVersion := []byte("/proc/version\000")
+		f := open(&procVersion[0], _O_RDONLY, 0)
+		if f >= 0 {
+			var buf [512]byte
+			p := noescape(unsafe.Pointer(&buf[0]))
+			n := read(f, p, int32(len(buf)))
+			closefd(f)
+
+			needle := []byte("Ubuntu")
+		contains:
+			for i, c := range buf[:n] {
+				if c != needle[0] {
+					continue
+				}
+				if int(n)-i < len(needle) {
+					break
+				}
+				for j, c2 := range needle {
+					if c2 != buf[i+j] {
+						continue contains
+					}
+				}
+				// This is an Ubuntu system.
+				return
+			}
+		}
+	}
+
 	if major == 5 && (minor == 2 || minor == 3 && patch < 15 || minor == 4 && patch < 2) {
 		gsignalInitQuirk = mlockGsignal
 		if m0.gsignal != nil {