Commit 805eaeef authored by Ilya Tocar's avatar Ilya Tocar

crypto/sha1: fix AVX2 variant on AMD64

AVX2 variant reads next blocks while calculating current block.
Avoid reading past the end of data, by switching back to original,
for last blocks.

Fixes #15617.

Change-Id: I04fa2d83f1b47995117c77b4a3d403a7dff594d4
Reviewed-on: https://go-review.googlesource.com/23138Reviewed-by: 's avatarKeith Randall <khr@golang.org>
Run-TryBot: Ilya Tocar <ilya.tocar@intel.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 8a1dc324
// +build amd64
// +build linux darwin
// Copyright 2016 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.
package sha1_test
import (
"crypto/sha1"
"syscall"
"testing"
)
func TestOutOfBoundsRead(t *testing.T) {
const pageSize = 4 << 10
data, err := syscall.Mmap(0, 0, 2*pageSize, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
if err != nil {
panic(err)
}
if err := syscall.Mprotect(data[pageSize:], syscall.PROT_NONE); err != nil {
panic(err)
}
for i := 0; i < pageSize; i++ {
sha1.Sum(data[pageSize-i : pageSize])
}
}
......@@ -94,13 +94,15 @@ func TestBlockSize(t *testing.T) {
// Tests that blockGeneric (pure Go) and block (in assembly for some architectures) match.
func TestBlockGeneric(t *testing.T) {
gen, asm := New().(*digest), New().(*digest)
buf := make([]byte, BlockSize*20) // arbitrary factor
rand.Read(buf)
blockGeneric(gen, buf)
block(asm, buf)
if *gen != *asm {
t.Error("block and blockGeneric resulted in different states")
for i := 1; i < 30; i++ { // arbitrary factor
gen, asm := New().(*digest), New().(*digest)
buf := make([]byte, BlockSize*i)
rand.Read(buf)
blockGeneric(gen, buf)
block(asm, buf)
if *gen != *asm {
t.Errorf("For %#v block and blockGeneric resulted in different states", buf)
}
}
}
......
......@@ -12,13 +12,22 @@ func blockAVX2(dig *digest, p []byte)
func blockAMD64(dig *digest, p []byte)
func checkAVX2() bool
// TODO(TocarIP): fix AVX2 crash (golang.org/issue/15617) and
// then re-enable this:
var hasAVX2 = false // checkAVX2()
var hasAVX2 = checkAVX2()
func block(dig *digest, p []byte) {
if hasAVX2 && len(p) >= 256 {
blockAVX2(dig, p)
// blockAVX2 calculates sha1 for 2 block per iteration
// it also interleaves precalculation for next block.
// So it may read up-to 192 bytes past end of p
// We may add checks inside blockAVX2, but this will
// just turn it into a copy of blockAMD64,
// so call it directly, instead.
safeLen := len(p) - 128
if safeLen%128 != 0 {
safeLen -= 64
}
blockAVX2(dig, p[:safeLen])
blockAMD64(dig, p[safeLen:])
} else {
blockAMD64(dig, p)
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment