Commit c5b7702b authored by Nadim Kobeissi's avatar Nadim Kobeissi 💾
Browse files

Today I received a bug report from Tom Roeder, in which he demonstrated that...

Today I received a bug report from Tom Roeder, in which he demonstrated that the following models, Model A and Model B, caused a crash in Verifpal. Let’s look at Model A:

```
// Model A
attacker[active]

principal Client[
  knows private a, b, c, d, e, f
  gg = CONCAT(a, b, c)
  h = CONCAT(gg, d, e)
]

Client -> Server : h

principal Server[
  gc, dc, ec, fc = SPLIT(h)
  ac, bc, cc = SPLIT(gc)
]

queries[
  authentication? Client -> Server: h
]
```

Here, the cause is obvious: `h` is being split into four values despite being comprised of a concatenation of three values. This should not crash Verifpal, but should reasonably either be defined behavior or throw an error. However, if we look at Model B:

```
// Model B
attacker[active]

principal Client[
  knows private a, b, c, d, e, f
  gg = CONCAT(a, b, c)
  h = CONCAT(gg, d, e, f)
]

Client -> Server : h

principal Server[
  gc, dc, ec, fc = SPLIT(h)
  ac, bc, cc = SPLIT(gc)
]

queries[
  authentication? Client -> Server: h
]
```

Here Verifpal crashes despite the model being sane. This is because the active attacker renders it non-sane by replacing `h` with CONCAT(any, three, values), again triggering the crash when `h` is split into four values despite being a concatenation of three values.

Thus Tom showed that the bug caused a crash in Verifpal in both non-sane (Model A) and sane (Model B) models.

At this point, it became clear that it was important to clearly define Verifpal’s behavior when faced with such instances. I have decided to define it such that any extraneous values are rewritten to `nil`. So, for example, in Model A, on this line:

```
gc, dc, ec, fc = SPLIT(h)
```

`fc` will be rewritten to the `nil` value. This seems to be the most sensible defined behavior for this sort of scenario.
parent 5e72b0c3
Pipeline #703 passed with stages
in 3 minutes and 10 seconds
......@@ -35,8 +35,8 @@ func constructKnowledgeMap(m Model, principals []string) (KnowledgeMap, error) {
map[string]string{principal: principal},
)
}
valKnowledgeMap.Constants = append(valKnowledgeMap.Constants, valueN.Constant)
valKnowledgeMap.Assigned = append(valKnowledgeMap.Assigned, valueN)
valKnowledgeMap.Constants = append(valKnowledgeMap.Constants, valueNil.Constant)
valKnowledgeMap.Assigned = append(valKnowledgeMap.Assigned, valueNil)
valKnowledgeMap.Creator = append(valKnowledgeMap.Creator, principals[0])
valKnowledgeMap.KnownBy = append(valKnowledgeMap.KnownBy, []map[string]string{})
valKnowledgeMap.DeclaredAt = append(valKnowledgeMap.DeclaredAt, declaredAt)
......
......@@ -107,7 +107,7 @@ func injectPrimitiveSkeleton(p Primitive, depth int) (Primitive, int) {
for i, a := range p.Arguments {
switch a.Kind {
case "constant":
skeleton.Arguments[i] = valueN
skeleton.Arguments[i] = valueNil
case "primitive":
pp, dd := injectPrimitiveSkeleton(a.Primitive, depth)
if dd > depth {
......@@ -123,7 +123,7 @@ func injectPrimitiveSkeleton(p Primitive, depth int) (Primitive, int) {
case 1:
skeleton.Arguments[i] = valueG
default:
skeleton.Arguments[i] = valueGN
skeleton.Arguments[i] = valueGNil
}
}
}
......
......@@ -108,7 +108,7 @@ func mutationMapReplaceConstant(
if valueIsGOrNil(a.Constant) {
return mutations
}
mutations = append(mutations, valueN)
mutations = append(mutations, valueNil)
if stage <= 3 {
return mutations
}
......@@ -186,9 +186,9 @@ func mutationMapReplaceEquation(
case 1:
mutations = append(mutations, valueG)
case 2:
mutations = append(mutations, valueGN)
mutations = append(mutations, valueGNil)
case 3:
mutations = append(mutations, valueGNN)
mutations = append(mutations, valueGNilNil)
}
if stage <= 3 {
return mutations
......
......@@ -324,7 +324,7 @@ var primitiveSpecs = []PrimitiveSpec{
Name: "SIGN",
From: 2,
To: func(p Primitive) Value {
return valueN
return valueNil
},
Matching: map[int][]int{
0: {0},
......@@ -553,7 +553,7 @@ var primitiveSpecs = []PrimitiveSpec{
Name: "RINGSIGN",
From: 4,
To: func(p Primitive) Value {
return valueN
return valueNil
},
Matching: map[int][]int{
0: {0, 1, 2},
......
......@@ -106,7 +106,7 @@ type Constant struct {
// Primitive represents a primitive expression:
// - Name indicates the name of the primitives.
// - Arguments indicates the arguments of the primitive.
// - Output indicates the number of outputs from the primitive.
// - Output indicates which output value of the primitive this copy should rewrite to (starts at 0).
// - Check indicates whether this has been a checked primitive.
type Primitive struct {
Name string
......
......@@ -21,7 +21,7 @@ var valueG = Value{
},
}
var valueN = Value{
var valueNil = Value{
Kind: "constant",
Constant: Constant{
Name: "nil",
......@@ -33,17 +33,17 @@ var valueN = Value{
},
}
var valueGN = Value{
var valueGNil = Value{
Kind: "equation",
Equation: Equation{
Values: []Value{valueG, valueN},
Values: []Value{valueG, valueNil},
},
}
var valueGNN = Value{
var valueGNilNil = Value{
Kind: "equation",
Equation: Equation{
Values: []Value{valueG, valueN, valueN},
Values: []Value{valueG, valueNil, valueNil},
},
}
......@@ -200,59 +200,56 @@ func valueEquivalentValueInValues(v Value, a []Value) int {
return -1
}
func valuePerformPrimitiveRebuild(
rewrites []Value, rIndex int, pi int,
rebuild Value, valPrincipalState PrincipalState,
) []Value {
rewrites[rIndex] = rebuild
if pi >= 0 {
valPrincipalState.Assigned[pi] = rebuild
if !valPrincipalState.Mutated[pi] {
valPrincipalState.BeforeMutate[pi] = rebuild
}
}
return rewrites
}
func valuePerformPrimitiveRewrite(
p Primitive, pi int, valPrincipalState PrincipalState,
) ([]Primitive, bool, Value) {
rIndex := 0
rewrites, failedRewrites, rewritten := valuePerformPrimitiveArgumentsRewrite(
p, rIndex, valPrincipalState,
rewrite, failedRewrites, rewritten := valuePerformPrimitiveArgumentsRewrite(
p, valPrincipalState,
)
rebuilt, rebuild := possibleToRebuild(rewrites[rIndex].Primitive)
rebuilt, rebuild := possibleToRebuild(rewrite.Primitive)
if rebuilt {
rewrites = valuePerformPrimitiveRebuild(
rewrites, rIndex, pi, rebuild, valPrincipalState,
)
rewrite = rebuild
if pi >= 0 {
valPrincipalState.Assigned[pi] = rebuild
if !valPrincipalState.Mutated[pi] {
valPrincipalState.BeforeMutate[pi] = rebuild
}
}
switch rebuild.Kind {
case "constant", "equation":
return failedRewrites, rewritten, rewrites[rIndex]
return failedRewrites, rewritten, rewrite
}
}
rewrittenRoot, rewrites := possibleToRewrite(
rewrites[rIndex].Primitive, valPrincipalState,
rewrittenRoot, rewrittenValues := possibleToRewrite(
rewrite.Primitive, valPrincipalState,
)
rIndex := 0
if !rewrittenRoot {
failedRewrites = append(failedRewrites, rewrites[rIndex].Primitive)
failedRewrites = append(failedRewrites, rewrittenValues[rIndex].Primitive)
} else if primitiveIsCorePrim(p.Name) {
rIndex = p.Output
}
if (rewritten || rewrittenRoot) && pi >= 0 {
valPrincipalState.Rewritten[pi] = true
valPrincipalState.Assigned[pi] = rewrites[rIndex]
if rIndex >= len(rewrittenValues) {
valPrincipalState.Assigned[pi] = valueNil
if !valPrincipalState.Mutated[pi] {
valPrincipalState.BeforeMutate[pi] = valueNil
}
return failedRewrites, (rewritten || rewrittenRoot), valueNil
}
valPrincipalState.Assigned[pi] = rewrittenValues[rIndex]
if !valPrincipalState.Mutated[pi] {
valPrincipalState.BeforeMutate[pi] = rewrites[rIndex]
valPrincipalState.BeforeMutate[pi] = rewrittenValues[rIndex]
}
}
return failedRewrites, (rewritten || rewrittenRoot), rewrites[rIndex]
return failedRewrites, (rewritten || rewrittenRoot), rewrittenValues[rIndex]
}
func valuePerformPrimitiveArgumentsRewrite(
p Primitive, rIndex int, valPrincipalState PrincipalState,
) ([]Value, []Primitive, bool) {
rewrites := []Value{{
p Primitive, valPrincipalState PrincipalState,
) (Value, []Primitive, bool) {
rewrite := Value{
Kind: "primitive",
Primitive: Primitive{
Name: p.Name,
......@@ -260,23 +257,23 @@ func valuePerformPrimitiveArgumentsRewrite(
Output: p.Output,
Check: p.Check,
},
}}
}
failedRewrites := []Primitive{}
rewritten := false
for i, a := range p.Arguments {
switch a.Kind {
case "constant":
rewrites[rIndex].Primitive.Arguments[i] = p.Arguments[i]
rewrite.Primitive.Arguments[i] = p.Arguments[i]
case "primitive":
pFailedRewrite, pRewritten, pRewrite := valuePerformPrimitiveRewrite(
a.Primitive, -1, valPrincipalState,
)
if pRewritten {
rewritten = true
rewrites[rIndex].Primitive.Arguments[i] = pRewrite
rewrite.Primitive.Arguments[i] = pRewrite
continue
}
rewrites[rIndex].Primitive.Arguments[i] = p.Arguments[i]
rewrite.Primitive.Arguments[i] = p.Arguments[i]
failedRewrites = append(failedRewrites, pFailedRewrite...)
case "equation":
eFailedRewrite, eRewritten, eRewrite := valuePerformEquationRewrite(
......@@ -284,14 +281,14 @@ func valuePerformPrimitiveArgumentsRewrite(
)
if eRewritten {
rewritten = true
rewrites[rIndex].Primitive.Arguments[i] = eRewrite
rewrite.Primitive.Arguments[i] = eRewrite
continue
}
rewrites[rIndex].Primitive.Arguments[i] = p.Arguments[i]
rewrite.Primitive.Arguments[i] = p.Arguments[i]
failedRewrites = append(failedRewrites, eFailedRewrite...)
}
}
return rewrites, failedRewrites, rewritten
return rewrite, failedRewrites, rewritten
}
func valuePerformEquationRewrite(
......
......@@ -2,6 +2,7 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/akavel/rsrc v0.9.0 h1:HwUDC0+tMFWqN4D5G+o5siGD4oVsC3jn6zM8ocjc3nY=
github.com/akavel/rsrc v0.9.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
......@@ -40,8 +41,10 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmg
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/josephspurrier/goversioninfo v1.2.0 h1:tpLHXAxLHKHg/dCU2AAYx08A4m+v9/CWg6+WUvTF4uQ=
github.com/josephspurrier/goversioninfo v1.2.0/go.mod h1:AGP2a+Y/OVJZ+s6XM4IwFUpkETwvn0orYurY8qpw1+0=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
......@@ -51,11 +54,13 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mna/pigeon v1.0.0 h1:n46IoStjdzjaXuyBH53j9HZ8CVqGWpC7P5/v8dP4qEY=
github.com/mna/pigeon v1.0.0/go.mod h1:Iym28+kJVnC1hfQvv5MUtI6AiFFzvQjHcvI4RFTG/04=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
......@@ -79,9 +84,11 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
......
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