-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(s/i/cpuproxy): custom cpuproxy for android
This diff pulls code from https://go-review.googlesource.com/c/sys/+/197540/ to add better support for detecting arm64 CPU features. I extracted this diff from 62177de with the intent of coming up with a more manageable patch set. The idea here is to use this better cpuproxy functionality to feed crypto libraries with better understanding of cpu capabilities. The original issue describing this problem in its full extent was ooni/probe#1444. We're now working to forward-port this patch to go1.17. AFAICT, as of go1.17, the src/runtime/os_linux.go still falls back to reduce functionality in case /proc/self/auxv isn't readable: https://github.com/golang/go/blob/go1.17.3/src/runtime/os_linux.go#L216 The current issue describing this problem as of go1.17 is ooni/probe#1863. Is there a better way?
- Loading branch information
1 parent
f58c78a
commit 7807667
Showing
3 changed files
with
116 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// +build android | ||
// +build arm64 | ||
|
||
// Copyright 2019 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
// | ||
// This file is based on the diff available at | ||
// https://go-review.googlesource.com/c/sys/+/197540/ | ||
|
||
package cpuproxy | ||
|
||
/* | ||
#include <sys/auxv.h> | ||
// getauxval is not available on Android until API level 20. Link it as a weak | ||
// symbol and check whether it is not NULL before using it. | ||
unsigned long getauxval(unsigned long type) __attribute__((weak)); | ||
*/ | ||
import "C" | ||
|
||
import "sync" | ||
|
||
// These constants are Linux specific. | ||
const ( | ||
_AT_HWCAP = 16 // hardware capability bit vector | ||
) | ||
|
||
// get returns the value of the getauxval auxiliary vector, or | ||
// zero where the functionality is unavailable. | ||
func get(t uint) uint { | ||
if C.getauxval == C.NULL { | ||
return 0 | ||
} | ||
return uint(C.getauxval(C.ulong(t))) | ||
} | ||
|
||
// dogethwcap returns the value of _AT_HWCAP by calling | ||
// the getauxval(3) function in libc (if available). | ||
func dogethwcap() uint { | ||
return get(_AT_HWCAP) | ||
} | ||
|
||
// These variables allow to cache getauxval(3) results. | ||
var ( | ||
once sync.Once | ||
hwcap uint | ||
) | ||
|
||
// gethwcap is like dogethwcap except that this function | ||
// ensures we call getauxval(3) just once. After the first | ||
// invocation we memoize the result. | ||
func gethwcap() uint { | ||
once.Do(func() { | ||
hwcap = dogethwcap() | ||
}) | ||
return hwcap | ||
} | ||
|
||
// HWCAP bits. These are exposed by Linux. | ||
const ( | ||
hwcap_AES = 1 << 3 | ||
hwcap_PMULL = 1 << 4 | ||
hwcap_SHA1 = 1 << 5 | ||
hwcap_SHA2 = 1 << 6 | ||
hwcap_CRC32 = 1 << 7 | ||
hwcap_ATOMICS = 1 << 8 | ||
hwcap_CPUID = 1 << 11 | ||
) | ||
|
||
// HasAES returns whether the CPU supports AES. | ||
func HasAES() bool { | ||
return (gethwcap() & hwcap_AES) != 0 | ||
} | ||
|
||
// HasGFMUL returns whether the CPU supports GFMUL. | ||
func HasGFMUL() bool { | ||
return (gethwcap() & hwcap_PMULL) != 0 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// +build !android !arm64 | ||
|
||
package cpuproxy | ||
|
||
import "internal/cpu" | ||
|
||
// HasAES returns whether the CPU supports AES. | ||
func HasAES() bool { | ||
return cpu.X86.HasAES || cpu.ARM64.HasAES | ||
} | ||
|
||
// HasGFMUL returns whether the CPU supports GFMUL. | ||
func HasGFMUL() bool { | ||
return cpu.X86.HasPCLMULQDQ || cpu.ARM64.HasPMULL | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// Package cpuproxy is a getauxval aware proxy for internal/cpu. | ||
// | ||
// The problem that we want to solve is that on Android there are | ||
// cases where reading /proc/self/auxv is not possible. | ||
// | ||
// This causes crypto/tls to not choose AES where it would otherwise | ||
// be possible, in turn causing censorship. See also the | ||
// https://github.com/ooni/probe/issues/1444 issue for more details. | ||
// | ||
// Ideally we would like to call getauxval(3) when initializing | ||
// the runtime package. However, runtime cannot use CGO. Doing that | ||
// leads to an import loop, so we cannot build. | ||
// | ||
// We could also try to parse /proc/cpuinfo (I didn't explore this route). | ||
// | ||
// The solution chosen here is to export predicates on the CPU | ||
// functionality. We limit ourselves to what we need in order to | ||
// choose AES in crypto/tls when the CPU supports it. | ||
// | ||
// The predicates use internal/cpu values for every GOOS/GOARCH except | ||
// android/arm64, where we call getauxval(3). | ||
package cpuproxy |