Repository: hashicorp/vault (Go)

Issue:
Runtime error when supplying "none" for a denied_parameter
When we create a policy in Vault 1.1 that denys certain parameter values, a runtime error occurs within Vault if the client submits a null value for this very parameter. I'm not sure if this has any other implications.
Steps to reproduce:
1. Create a policy with a denied_parameter statement:

```
vault policy write examplepolicy -<<EOF
  path "pki/issue/example" {
    capabilities = ["update"]
    denied_parameters = {
      "common_name" = ["a"]
    }
  }
EOF
```

2. Attach a token to this policy and submit a request with the value "null" for the denied parameter:
curl -X POST -H "X-Vault-Token: s...." -d '{ "common_name": null }' https://<vaultserver>:8200/v1/pki/issue/example

Expected result: Vault should deny the request.
Actual result: Vault immediately closes the connection without any response.

Vault log is showing the following:
```
vault[7762]: 2019-04-12T16:12:50.882+0200 [INFO]  http: panic serving 172.0.0.1:46470: runtime error: invalid memory address or nil pointer dereference
vault[7762]: goroutine 136103 [running]:
vault[7762]: net/http.(*conn).serve.func1(0xc0009f6280)
vault[7762]: /goroot/src/net/http/server.go:1746 +0xd0
vault[7762]: panic(0x2663920, 0x4cf1060)
vault[7762]: /goroot/src/runtime/panic.go:513 +0x1b9
vault[7762]: github.com/hashicorp/vault/vault.valueInSlice(0x0, 0x0, 0xc000e81710, 0x1, 0x1, 0xc000b350b0)
vault[7762]: /gopath/src/github.com/hashicorp/vault/vault/acl.go:611 +0xf9
vault[7762]: github.com/hashicorp/vault/vault.valueInParameterList(0x0, 0x0, 0xc000e81710, 0x1, 0x1, 0xc0004b8c01)
vault[7762]: /gopath/src/github.com/hashicorp/vault/vault/acl.go:606 +0x67
vault[7762]: github.com/hashicorp/vault/vault.(*ACL).AllowOperation(0xc0006834c0, 0x2f0dae0, 0xc000b34d20, 0xc0000de780, 0x2abf800, 0x1)
vault[7762]: /gopath/src/github.com/hashicorp/vault/vault/acl.go:534 +0x745
vault[7762]: github.com/hashicorp/vault/vault.(*Core).performPolicyChecks(0xc000554a00, 0x2f0dae0, 0xc000b34d20, 0xc0006834c0, 0xc000a9d7a0, 0xc0000de780, 0x0, 0xc000ab6f16, 0x0)
vault[7762]: /gopath/src/github.com/hashicorp/vault/vault/acl.go:579 +0x9a
vault[7762]: github.com/hashicorp/vault/vault.(*Core).checkToken(0xc000554a00, 0x2f0dae0, 0xc000b34d20, 0xc0000de780, 0x0, 0x0, 0x0, 0x0, 0x0)
vault[7762]: /gopath/src/github.com/hashicorp/vault/vault/request_handling.go:348 +0x7a1
vault[7762]: github.com/hashicorp/vault/vault.(*Core).handleRequest(0xc000554a00, 0x2f0dae0, 0xc000b34d20, 0xc0000de780, 0x0, 0x0, 0x0, 0x0)
vault[7762]: /gopath/src/github.com/hashicorp/vault/vault/request_handling.go:565 +0x3bf
vault[7762]: github.com/hashicorp/vault/vault.(*Core).handleCancelableRequest(0xc000554a00, 0x2f0dae0, 0xc000b34d20, 0x4cf5a00, 0xc0000de780, 0x2f0dae0, 0xc000b34960, 0x0)
vault[7762]: /gopath/src/github.com/hashicorp/vault/vault/request_handling.go:427 +0xda5
vault[7762]: github.com/hashicorp/vault/vault.(*Core).HandleRequest(0xc000554a00, 0x2f0dae0, 0xc000b34960, 0xc0000de780, 0xc0000de780, 0xc0004b8cf9, 0x2b45686)
vault[7762]: /gopath/src/github.com/hashicorp/vault/vault/request_handling.go:393 +0x18e
vault[7762]: github.com/hashicorp/vault/http.request(0xc000554a00, 0x2f0a060, 0xc0004e4a80, 0xc000bbd100, 0xc0000de780, 0x0, 0x0)
vault[7762]: /gopath/src/github.com/hashicorp/vault/http/handler.go:565 +0x76
vault[7762]: github.com/hashicorp/vault/http.handleLogicalInternal.func1(0x2f0a060, 0xc0004e4a80, 0xc000bbd100)
vault[7762]: /gopath/src/github.com/hashicorp/vault/http/logical.go:272 +0x290
vault[7762]: net/http.HandlerFunc.ServeHTTP(0xc0001cb840, 0x2f0a060, 0xc0004e4a80, 0xc000bbd100)
vault[7762]: /goroot/src/net/http/server.go:1964 +0x44
vault[7762]: github.com/hashicorp/vault/http.handleRequestForwarding.func1(0x2f0a060, 0xc0004e4a80, 0xc000bbd100)
vault[7762]: /gopath/src/github.com/hashicorp/vault/http/handler.go:501 +0x2b5
vault[7762]: net/http.HandlerFunc.ServeHTTP(0xc0001cb880, 0x2f0a060, 0xc0004e4a80, 0xc000bbd100)
vault[7762]: /goroot/src/net/http/server.go:1964 +0x44
vault[7762]: net/http.(*ServeMux).ServeHTTP(0xc0004f3770, 0x2f0a060, 0xc0004e4a80, 0xc000bbd100)
vault[7762]: /goroot/src/net/http/server.go:2361 +0x127
vault[7762]: github.com/hashicorp/vault/http.wrapHelpHandler.func1(0x2f0a060, 0xc0004e4a80, 0xc000bbd100)
vault[7762]: /gopath/src/github.com/hashicorp/vault/http/help.go:24 +0x150
vault[7762]: net/http.HandlerFunc.ServeHTTP(0xc0001cb920, 0x2f0a060, 0xc0004e4a80, 0xc000bbd100)
vault[7762]: /goroot/src/net/http/server.go:1964 +0x44
vault[7762]: github.com/hashicorp/vault/http.wrapCORSHandler.func1(0x2f0a060, 0xc0004e4a80, 0xc000bbd100)
vault[7762]: /gopath/src/github.com/hashicorp/vault/http/cors.go:29 +0x531
vault[7762]: net/http.HandlerFunc.ServeHTTP(0xc0001cb940, 0x2f0a060, 0xc0004e4a80, 0xc000bbd100)
vault[7762]: /goroot/src/net/http/server.go:1964 +0x44
vault[7762]: github.com/hashicorp/vault/http.wrapGenericHandler.func1(0x2f0a060, 0xc0004e4a80, 0xc000bbcf00)
vault[7762]: /gopath/src/github.com/hashicorp/vault/http/handler.go:193 +0x295
vault[7762]: net/http.HandlerFunc.ServeHTTP(0xc0004f3bf0, 0x2f0a060, 0xc0004e4a80, 0xc000bbcf00)
vault[7762]: /goroot/src/net/http/server.go:1964 +0x44
vault[7762]: github.com/hashicorp/vault/vendor/github.com/hashicorp/go-cleanhttp.PrintablePathCheckHandler.func1(0x2f0a060, 0xc0004e4a80, 0xc000bbcf00)
vault[7762]: /gopath/src/github.com/hashicorp/vault/vendor/github.com/hashicorp/go-cleanhttp/handlers.go:40 +0xcc
vault[7762]: net/http.HandlerFunc.ServeHTTP(0xc0001cb980, 0x2f0a060, 0xc0004e4a80, 0xc000bbcf00)
vault[7762]: /goroot/src/net/http/server.go:1964 +0x44
vault[7762]: github.com/hashicorp/vault/http.WrapForwardedForHandler.func1(0x2f0a060, 0xc0004e4a80, 0xc000bbcf00)
vault[7762]: /gopath/src/github.com/hashicorp/vault/http/handler.go:204 +0x186
vault[7762]: net/http.HandlerFunc.ServeHTTP(0xc00009f1d0, 0x2f0a060, 0xc0004e4a80, 0xc000bbcf00)
vault[7762]: /goroot/src/net/http/server.go:1964 +0x44
vault[7762]: net/http.serverHandler.ServeHTTP(0xc0003ed1e0, 0x2f0a060, 0xc0004e4a80, 0xc000bbcf00)
vault[7762]: /goroot/src/net/http/server.go:2741 +0xab
vault[7762]: net/http.(*conn).serve(0xc0009f6280, 0x2f0da20, 0xc0001bdf80)
vault[7762]: /goroot/src/net/http/server.go:1847 +0x646
vault[7762]: created by net/http.(*Server).Serve
vault[7762]: /goroot/src/net/http/server.go:2851 +0x2f5
```


Discussion:

Patch:
diff --git a/vault/acl.go b/vault/acl.go
index 4105b3583f7..1313fa33b5d 100644
--- a/vault/acl.go
+++ b/vault/acl.go
@@ -709,7 +709,14 @@ func valueInParameterList(v interface{}, list []interface{}) bool {
 
 func valueInSlice(v interface{}, list []interface{}) bool {
 	for _, el := range list {
-		if reflect.TypeOf(el).String() == "string" && reflect.TypeOf(v).String() == "string" {
+		if el == nil || v == nil {
+			// It doesn't seem possible to set up a nil entry in the list, but it is possible
+			// to pass in a null entry in the API request being checked. Just in case,
+			// nil will match nil.
+			if el == v {
+				return true
+			}
+		} else if reflect.TypeOf(el).String() == "string" && reflect.TypeOf(v).String() == "string" {
 			item := el.(string)
 			val := v.(string)
 


Test patch:
diff --git a/vault/acl_test.go b/vault/acl_test.go
index 5a2de1b7fc3..a8cb634dd85 100644
--- a/vault/acl_test.go
+++ b/vault/acl_test.go
@@ -549,6 +549,8 @@ func testACLValuePermissions(t *testing.T, ns *namespace.Namespace) {
 		{"foo/bar", []string{"deny"}, []interface{}{"bad glob"}, false},
 		{"foo/bar", []string{"deny"}, []interface{}{"good"}, true},
 		{"foo/bar", []string{"allow"}, []interface{}{"good"}, true},
+		{"foo/bar", []string{"deny"}, []interface{}{nil}, true},
+		{"foo/bar", []string{"allow"}, []interface{}{nil}, true},
 		{"foo/baz", []string{"aLLow"}, []interface{}{"good"}, true},
 		{"foo/baz", []string{"deny"}, []interface{}{"bad"}, false},
 		{"foo/baz", []string{"deny"}, []interface{}{"good"}, false},
@@ -557,6 +559,7 @@ func testACLValuePermissions(t *testing.T, ns *namespace.Namespace) {
 		{"foo/baz", []string{"deNy", "allow"}, []interface{}{"bad", "good"}, false},
 		{"foo/baz", []string{"aLLow"}, []interface{}{"bad"}, false},
 		{"foo/baz", []string{"Neither"}, []interface{}{"bad"}, false},
+		{"foo/baz", []string{"allow"}, []interface{}{nil}, false},
 		{"fizz/buzz", []string{"allow_multi"}, []interface{}{"good"}, true},
 		{"fizz/buzz", []string{"allow_multi"}, []interface{}{"good1"}, true},
 		{"fizz/buzz", []string{"allow_multi"}, []interface{}{"good2"}, true},