As reported in #11294, the Docker daemon will execute contains it
shouldn't run in the event that a requested tag is present in an image's
ID. This leads to the wrong image being started up silently.
This change reduces the risk of such a collision by using the short ID
iff the actual revOrTag looks like a short ID (not that it necessarily
is).
Signed-off-by: Richard Burnison <rburnison@ebay.com>
| ... | ... |
@@ -335,9 +335,12 @@ func (store *TagStore) GetImage(repoName, refOrID string) (*image.Image, error) |
| 335 | 335 |
} |
| 336 | 336 |
|
| 337 | 337 |
// If no matching tag is found, search through images for a matching image id |
| 338 |
- for _, revision := range repo {
|
|
| 339 |
- if strings.HasPrefix(revision, refOrID) {
|
|
| 340 |
- return store.graph.Get(revision) |
|
| 338 |
+ // iff it looks like a short ID or would look like a short ID |
|
| 339 |
+ if stringid.IsShortID(stringid.TruncateID(refOrID)) {
|
|
| 340 |
+ for _, revision := range repo {
|
|
| 341 |
+ if strings.HasPrefix(revision, refOrID) {
|
|
| 342 |
+ return store.graph.Get(revision) |
|
| 343 |
+ } |
|
| 341 | 344 |
} |
| 342 | 345 |
} |
| 343 | 346 |
|
| ... | ... |
@@ -4,19 +4,27 @@ import ( |
| 4 | 4 |
"crypto/rand" |
| 5 | 5 |
"encoding/hex" |
| 6 | 6 |
"io" |
| 7 |
+ "regexp" |
|
| 7 | 8 |
"strconv" |
| 8 | 9 |
) |
| 9 | 10 |
|
| 11 |
+const shortLen = 12 |
|
| 12 |
+ |
|
| 13 |
+// Determine if an arbitrary string *looks like* a short ID. |
|
| 14 |
+func IsShortID(id string) bool {
|
|
| 15 |
+ return regexp.MustCompile("^[a-z0-9]{12}$").MatchString(id)
|
|
| 16 |
+} |
|
| 17 |
+ |
|
| 10 | 18 |
// TruncateID returns a shorthand version of a string identifier for convenience. |
| 11 | 19 |
// A collision with other shorthands is very unlikely, but possible. |
| 12 | 20 |
// In case of a collision a lookup with TruncIndex.Get() will fail, and the caller |
| 13 | 21 |
// will need to use a langer prefix, or the full-length Id. |
| 14 | 22 |
func TruncateID(id string) string {
|
| 15 |
- shortLen := 12 |
|
| 23 |
+ trimTo := shortLen |
|
| 16 | 24 |
if len(id) < shortLen {
|
| 17 |
- shortLen = len(id) |
|
| 25 |
+ trimTo = len(id) |
|
| 18 | 26 |
} |
| 19 |
- return id[:shortLen] |
|
| 27 |
+ return id[:trimTo] |
|
| 20 | 28 |
} |
| 21 | 29 |
|
| 22 | 30 |
// GenerateRandomID returns an unique id |
| ... | ... |
@@ -1,6 +1,9 @@ |
| 1 | 1 |
package stringid |
| 2 | 2 |
|
| 3 |
-import "testing" |
|
| 3 |
+import ( |
|
| 4 |
+ "strings" |
|
| 5 |
+ "testing" |
|
| 6 |
+) |
|
| 4 | 7 |
|
| 5 | 8 |
func TestGenerateRandomID(t *testing.T) {
|
| 6 | 9 |
id := GenerateRandomID() |
| ... | ... |
@@ -33,3 +36,21 @@ func TestShortenIdInvalid(t *testing.T) {
|
| 33 | 33 |
t.Fatalf("Id returned is incorrect: truncate on %s returned %s", id, truncID)
|
| 34 | 34 |
} |
| 35 | 35 |
} |
| 36 |
+ |
|
| 37 |
+func TestIsShortIDNonHex(t *testing.T) {
|
|
| 38 |
+ id := "some non-hex value" |
|
| 39 |
+ if IsShortID(id) {
|
|
| 40 |
+ t.Fatalf("%s is not a short ID", id)
|
|
| 41 |
+ } |
|
| 42 |
+} |
|
| 43 |
+ |
|
| 44 |
+func TestIsShortIDNotCorrectSize(t *testing.T) {
|
|
| 45 |
+ id := strings.Repeat("a", shortLen+1)
|
|
| 46 |
+ if IsShortID(id) {
|
|
| 47 |
+ t.Fatalf("%s is not a short ID", id)
|
|
| 48 |
+ } |
|
| 49 |
+ id = strings.Repeat("a", shortLen-1)
|
|
| 50 |
+ if IsShortID(id) {
|
|
| 51 |
+ t.Fatalf("%s is not a short ID", id)
|
|
| 52 |
+ } |
|
| 53 |
+} |