Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

runtime/cgo: CGO and goroutines with OpenSSL random number generator #21208

Closed
kazkansouh opened this issue Jul 28, 2017 · 5 comments
Closed

Comments

@kazkansouh
Copy link

What version of Go are you using (go version)?

go version go1.8.3 linux/amd64

What operating system and processor architecture are you using (go env)?

GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/kazza/go-test"
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build602983390=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"
PKG_CONFIG="pkg-config"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"

What did you do?

package main

// Demonstration of an issue that involves running the openssl BN_rand
// function in multiple goroutines. Sometimes the program will
// segfault.

/*
#cgo CFLAGS: -std=c99 -Wall -Wpedantic
#cgo LDFLAGS: -lcrypto
#include <openssl/bn.h>

void GO_OPENSSL_free_char(char *addr) {
  OPENSSL_free(addr);
}
*/
import "C"
import (
	"errors"
	"fmt"
	"sync"
)

// Generates a random integer using the openssl BN_rand function as a
// string.
func Generate() (err error, str string) {
	bn := C.BN_new()
	if ret := C.BN_rand(bn, 127, 0, 1) ; ret == 1 {
		str = "ok"
		if ret := C.BN_bn2dec(bn) ; ret != nil {
			str = C.GoString(ret)
			C.GO_OPENSSL_free_char(ret)
		} else {
			err = errors.New("Failed to convert bn into string")
		}
		C.BN_free(bn)
	} else {
		err = errors.New("Failed to generate random number")
	}
	return
}

// Define the number of threads and times each thread will execute an
// action
const (
	threads = 100
	actions = 1000
)

func main() {
	var wg sync.WaitGroup

	for i := 0; i < threads; i++ {
		wg.Add(1)
		go func() {
			for j := 0; j < actions; j++ {
				fmt.Print(".")
				if err, _ := Generate(); err != nil {
					fmt.Println(err)
				}
			}
			wg.Done()
		}()
	}

	wg.Wait()
	fmt.Println("\nDone!")
}

What did you expect to see?

The program execute without error.

What did you see instead?

When run with a single thread, the program works as expected. However, when run with multiple threads the program sometimes segfaults. I suspect this is a problem with the method that OpenSSL uses to generate random numbers by accessing uninitialised regions of memory, however, this is not repeatable within C by the equivalent program (using pthreads) so I have opened it here just to be sure.

I have tried compiling OpenSSL with the -DPURIFY that allows BN_rand to pass valgrind without warnings, but it still causes segfaults in go.

This is an issue for me as currently the only reliable way to generate xmldsig's in go is to bind against the xmlsec1 C library. This means, that when signing XML documents under heavy load can cause the application to crash.

@bradfitz
Copy link
Contributor

Does OpenSSL use thread-local storage?

If so, you'll need to use https://golang.org/pkg/runtime/#LockOSThread in your Generate func.

@kazkansouh
Copy link
Author

I believe it does not, I tried adding LockOSThread as the first command in the Generate func and still observed the same behaviour.

@bradfitz
Copy link
Contributor

What do you want us to do with this bug?

User questions typically go to the mailing list (https://golang.org/wiki/Questions), and I don't see evidence that there's a Go bug here. I assume this is some OpenSSL usage problem. If this is a cgo and/or runtime error, what is it?

@kazkansouh
Copy link
Author

Thankyou for the advise.

If I can pin point the issue precisely, Ill consider re-opening it if appropriate.

@bradfitz
Copy link
Contributor

Thanks. Yes, do re-open if you find something we can help with on the Go side.

@mikioh mikioh changed the title CGO and goroutines with OpenSSL random number generator runtime/cgo: CGO and goroutines with OpenSSL random number generator Aug 2, 2017
@golang golang locked and limited conversation to collaborators Aug 2, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants