RHEL Engineering is moving the tracking of its product development work on RHEL 6 through RHEL 9 to Red Hat Jira (issues.redhat.com). If you're a Red Hat customer, please continue to file support cases via the Red Hat customer portal. If you're not, please head to the "RHEL project" in Red Hat Jira and file new tickets here. Individual Bugzilla bugs in the statuses "NEW", "ASSIGNED", and "POST" are being migrated throughout September 2023. Bugs of Red Hat partners with an assigned Engineering Partner Manager (EPM) are migrated in late September as per pre-agreed dates. Bugs against components "kernel", "kernel-rt", and "kpatch" are only migrated if still in "NEW" or "ASSIGNED". If you cannot log in to RH Jira, please consult article #7032570. That failing, please send an e-mail to the RH Jira admins at rh-issues@redhat.com to troubleshoot your issue as a user management inquiry. The email creates a ServiceNow ticket with Red Hat. Individual Bugzilla bugs that are migrated will be moved to status "CLOSED", resolution "MIGRATED", and set with "MigratedToJIRA" in "Keywords". The link to the successor Jira issue will be found under "Links", have a little "two-footprint" icon next to it, and direct you to the "RHEL project" in Red Hat Jira (issue links are of type "https://issues.redhat.com/browse/RHEL-XXXX", where "X" is a digit). This same link will be available in a blue banner at the top of the page informing you that that bug has been migrated.
Bug 1184247 - docker load can clobber existing name
Summary: docker load can clobber existing name
Keywords:
Status: CLOSED ERRATA
Alias: None
Product: Red Hat Enterprise Linux 7
Classification: Red Hat
Component: docker
Version: 7.1
Hardware: x86_64
OS: Linux
unspecified
low
Target Milestone: rc
: ---
Assignee: smahajan@redhat.com
QA Contact: Virtualization Bugs
URL:
Whiteboard:
Depends On:
Blocks: 1186442
TreeView+ depends on / blocked
 
Reported: 2015-01-20 20:42 UTC by Chris Evich
Modified: 2019-03-06 01:04 UTC (History)
5 users (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2015-08-06 00:31:51 UTC
Target Upstream Version:
Embargoed:


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
Red Hat Product Errata RHBA-2015:1536 0 normal SHIPPED_LIVE docker bug fix and enhancement update 2015-08-06 04:31:26 UTC

Description Chris Evich 2015-01-20 20:42:26 UTC
Description of problem:
Given an image "foo:latest" with ID 1234 already in docker, docker load < foo.tar with ID 5678 (same name, different ID) clobbers the existing name (of ID 1234) to "<none>".  Since images are most often referenced by name, it's not a very nice thing to do w/o being documented or issuing a "Warning: image foo already exists, renaming to <none>".

Version-Release number of selected component (if applicable):
docker-1.4.1-12.el7.x86_64

How reproducible:
Minor prep. required.

Steps to Reproduce:
1. docker run --name foo rhel7 /bin/true
2. docker commit foo foobar
   (note image ID)
3. docker save foobar > foobar.tar
4. docker rm foo
5. docker rmi foobar
6. docker run --name bar rhel7 /bin/false
7. docker commit bar foobar
   (note image ID)
8. docker rm bar
9. docker load < foobar.tar
10. docker images


Actual results:
[root@dockertest ~]# docker images
REPOSITORY                         TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
foobar                             latest              17be95040cc3        13 seconds ago      147 MB
...cut...
[root@dockertest ~]# docker load < foobar.tar
[root@dockertest ~]# echo $?
0
[root@dockertest ~]# docker images
REPOSITORY                         TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
<none>                             <none>              17be95040cc3        29 seconds ago      147 MB
foobar                             latest              90e44769e068        2 minutes ago       147 MB

Expected results:
Allow the load, but issue "Warning: existing image will be renamed <none>"
-or-
Document this in a "note" in the docker load man page
-or-
Fail the load with a 'image foobar already exists'

Additional info:
I don't think it's worth pressing for one particular rename behavior over another.  They're all equally correct or not, depending on users POV.  However, it would be nice (IMHO) to have this in docs or have a warning printed so limit surprises.
  Either way, I think this can be low severity.

Comment 3 smahajan@redhat.com 2015-03-09 18:59:43 UTC
Chris,

Another thing I see is, it clobbers the existing image to <none>:<none> and also creates a new one.

Does this happen with you too ?

Shishir

Comment 4 Chris Evich 2015-03-09 19:46:38 UTC
Hrmmm, dunno, but that's very bad docker behaviour, and it very mean to clobber poor orphans, just sayin' :D  Are you sure it's clobbering them (replacing their ID) and not hiding the other ones (i.e. docker images --all)?

Comment 5 smahajan@redhat.com 2015-03-09 19:51:03 UTC
Chris, its not replacing the ID.

It just creates a new one, and clobbers the name of the existing {foobar} to <none>:<none>

Taking a look now.

Shishir

Comment 6 Chris Evich 2015-03-09 20:12:18 UTC
Oh ya, that's what I was reporting.  I'm not sure we can fault the behaviour itself, unless it's inconsistent with other tagging/naming operations.  The issue for me is more about avoiding surprises, making expectations and/or outcome clearer for users.  That could mean a documented rule of "docker always honours the last image naming request" and/or a warning message would be fine and appropriate as well.

Comment 7 smahajan@redhat.com 2015-03-10 13:38:36 UTC
Issue opened with Docker.
https://github.com/docker/docker/issues/11285

Working on the fix now.

Shishir

Comment 8 smahajan@redhat.com 2015-03-10 14:34:56 UTC
Chris,

Dan and I discussed a solution yesterday of throwing an error, if the incoming image name already matches to an existing name {foobar in this case}.
However naming the image part, {reading the repositories JSON} is at the very end i.e. the image layers would already have been loaded into /var/lib/docker/graph by that time, so it would be too late to throw an error.

I am working on an alternative solution. Here is the design.

If the user tries to load foobar:latest {ID: 5678} When a foobar:latest {ID: 1234} already exists, we throw a warning message 

Message: The image {e.g.foobar} you are trying to load has the same name to an existing image, but the IDs do not match. 

Changing the name from {e.g. foobar} to foobar_xxxx.

Here xxxx would be a randomly generated string.

In the end the original image would be foobar:latest and the new one would be 
foobar_xxxx:latest.

Does this work for you?

PS: I can read the JSON first and throw the error, but that would change the order of execution of how the `docker load` is working right now. I feel there must be a reason they are doing things in particular order. Load as compared to Import is different in the fact that it preserves all the metadeta while loading the tar ball.

Shishir

Comment 9 Chris Evich 2015-03-10 15:02:10 UTC
Shishir,

Yep, in general that sounds workable.  The only thing that makes me slightly nervous is renaming to a random name.  What happens if that name also already exists?

We ran into this problem with some docker autotest tests, and found we needed to verify the random name also doesn't exist.  However, in a situation where there are a LOT of images, the check can present a performance problem.

Though maybe it's just a corner-case, one way around it could be to skip the rename to random.  Instead just have the warning say it's leaving image ID 1234567 un-tagged (since the image ID is much less likely to clash than a random name).

Another idea is, back to the core of "limit surprises", maybe leave the existing behaviour, just make it part of the warning: "The image {e.g.foobar} you are trying to load has the same name to an existing image, but the IDs do not match.  Existing image with ID 1234567 has been un-tagged" (or something to that effect).

Just trying to think of ways so the solution doesn't add more complexity than the underlying causes :D

Comment 10 smahajan@redhat.com 2015-03-10 15:09:07 UTC
Chris,

Random name should be random. (Not security proof random :), but a good pseudo random)
That's where SEEDS come into picture. With a good dynamic seed, I should be able to create a random string.

If you see docker already uses this concept in their load functionality when they create a directory for untarring the tarball into /var/lib/docker/tmp.

They generate a directory at /var/lib/docker/tmp/docker-import-xxx where xxx is a random suffix generated by 
http://golang.org/pkg/io/ioutil/#TempDir

Shishir

Comment 11 Chris Evich 2015-03-10 15:52:29 UTC
(In reply to smahajan from comment #10)
> That's where SEEDS come into picture. With a good dynamic seed, I should be
> able to create a random string.

Seeds aren't the issue, it's the string-length that's the problem.  In other words, docker-import-xxx is only as safe as it's frequency of use versus the total number of random 'xxx' character combinations.  It's an ancient attack vector, to exploit this.  Even the standard libraries goes to extra lengths to guarantee random-name temp directories can't clash (see man 3 mkstemp it's quite incredible).  But...this is another problem, and for this issue it's probably a corner case.

One idea could be to "borrow" the assumed-uniqueness of the 12-character short ID as the "random" part.  e.g. Existing container foobar with id 123456789012 gets renamed to 'foobar_123456789012:latest'.  Then you're not responsible for any clashes because that ID already clashed :D

Comment 12 Chris Evich 2015-03-10 15:58:34 UTC
(looking at docs, Go's TempDir looks safe, similar to 'mkdtemp', but I'm not a Go authority).

Comment 13 smahajan@redhat.com 2015-03-10 16:25:01 UTC
Yes I agree its a corner case. 
But I think probability of having a collision would be quite quite rare.

Say for ex ... if my random generated ID is 10 letters.
N each letter is being picked up from a 52 character set {small letters (a-z), caps letters (A-Z)}.

I am looking at {52 C 10} = 52! / (10! * 42!) combinations  ... Which is a pretty large number to find a collision. What I m trying to say is, the whole point of randomness is, there is a very low probability of having a collision, to cover a corner case like this. 

I think we should not change the existing ID, my implementation was never touching the existing image name and tag. For the new one we can prefix the ID to the image name so image name becomes foobar_5678 in your example.

Again only if you are not convinced by my randomness hypothesis :)
otherwise we do my solution, and I get to play around with some cool stuff in goalng !

Shishir

Comment 14 smahajan@redhat.com 2015-03-10 16:25:52 UTC
Chris,

I promise it won't be something like this :))
https://www.xkcd.com/221/

Shishir

Comment 15 Daniel Walsh 2015-03-10 16:39:27 UTC
Can you scan the entire image before writing to the graph driver to look for conflicts and error out?  Or is this costly an operation?

Comment 16 Chris Evich 2015-03-10 16:56:30 UTC
(In reply to smahajan from comment #13)
> I am looking at {52 C 10} = 52! / (10! * 42!) combinations

You forgot order is important also, it's actually 10^52 but...disk space is cheap, especially for empty directories.  Even so, no reason hold up for a corner-case, we both agree it is such, and I'm sure there are more pressing issues needing attention.  I'm fine with whatever solution is lowest risk and easiest to maintain (including docs) :D

Comment 17 Chris Evich 2015-03-10 17:03:08 UTC
(In reply to Daniel Walsh from comment #15)
> Can you scan the entire image before writing to the graph driver to look for
> conflicts and error out?  Or is this costly an operation?

FWIW, this was expensive in docker autotest at the time (we were running a TON of iterations).  Here, the check is as expensive as the number of things to check (likely high) times the frequency of the checking (likely low), so not likely, but possibly bad.

In any case, back to the main point of this issue: It's not fundamentally technical in nature, though it could be made so.  Docker can keep doing what it does, I'm just saying let's not surprise users in cases of possible ambiguity.  Toss an error, warning, document it, change the behaviour, or all at once,  My motivation is trying to help avoid the support call: "Docker ate my image".

Comment 18 smahajan@redhat.com 2015-03-17 17:38:41 UTC
Closing the bugzilla in favor of PR
https://github.com/docker/docker/pull/11293

Shishir

Comment 19 Chris Evich 2015-03-17 17:59:20 UTC
Great, thanks for all your help on this.

Comment 20 Daniel Walsh 2015-03-17 19:15:48 UTC
Shishir it is not modified until it is in a package Chris can test.  A pull request is only good once it is merged.

Comment 21 smahajan@redhat.com 2015-03-17 19:17:15 UTC
oops ! my bad ... I need to check, might have a few more wrong MODIFIED then.

Shishir

Comment 22 smahajan@redhat.com 2015-04-06 17:40:59 UTC
Merged upstream. Will be available in the next docker release.

Shishir

Comment 23 Luwen Su 2015-04-27 09:15:03 UTC
(In reply to smahajan from comment #22)
> Merged upstream. Will be available in the next docker release.
> 
> Shishir

Hi Shishir,

I don't find the patch in graph/tags.go in docker-1.6.0-9.el7.x86_64, will it be included in 1.7 or rhel 1.6 version?

And an upstream test in  
#./docker -v
Docker version 1.7.0-dev, build 6cba310-dirty,

seems like,
#docker load < foobar.tar
doesn't trigger this (upstream graph/tags.go line 267)
if !force {
     return fmt.Errorf("Conflict: Tag %s is already set to image %s, if you want to replace it, please use -f option", tag, old)
			}

which "force" gets a True value through my debug.

Comment 24 smahajan@redhat.com 2015-04-27 14:22:42 UTC
Hi Luwen,

You are looking at the wrong code. This is an existing code in upstream.

This https://github.com/docker/docker/blob/master/graph/tags.go#L271-274 fixes our issue.

You should see a warning message: The image %s:%s already exists, renaming the old one with ID %s to empty string.

Let me know if you still don't see it.

Shishir

Comment 25 Luwen Su 2015-04-28 09:58:55 UTC
(In reply to smahajan from comment #24)
> Hi Luwen,
> 
> You are looking at the wrong code. This is an existing code in upstream.
> 
> This https://github.com/docker/docker/blob/master/graph/tags.go#L271-274
> fixes our issue.
> 
> You should see a warning message: The image %s:%s already exists, renaming
> the old one with ID %s to empty string.
> 
> Let me know if you still don't see it.
> 
> Shishir

Hi Shishir,

I saw the warning yesterday, just wondering if the `force` part will be useful :).
Okay, i am going to verified this once this patch goes into build. 
CC lsm to let him know.

Comment 27 Luwen Su 2015-06-15 02:33:12 UTC
Hi Lokesh,

I remember this patch is in the 1.7 branch, not the 1.6.
Also not found it in https://github.com/rhatdan/docker/blob/rhel7-1.6/graph/tags.go#L270, should we remove it from errata ?

Comment 28 Daniel Walsh 2015-06-15 13:14:15 UTC
Yes it should not be in errata.

FIxed in docker-1.7

Comment 30 Lokesh Mandvekar 2015-06-22 13:20:40 UTC
dropped from advisory

Comment 31 Luwen Su 2015-07-28 06:36:59 UTC
In docker-1.7.1-107.el7.x86_64

# docker load < foobar.tar
The image foobar:latest already exists, renaming the old one with ID ace883dfcafa to empty string
# docker images
REPOSITORY                         TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
<none>                             <none>              ace883dfcafa        20 seconds ago      158.2 MB

Move to verified

Comment 33 errata-xmlrpc 2015-08-06 00:31:51 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://rhn.redhat.com/errata/RHBA-2015-1536.html


Note You need to log in before you can comment on or make changes to this bug.