Open deeplow opened 10 months ago
As I understand it, the goal here is to have a way to prompt the user that their installed Docker Desktop version is outdated, when it's the case.
My understanding is that it should only be checked on Windows and macOS machines, as Linux doesn't rely on Docker Desktop.
As Docker Desktop is closed-source, I did some reverse engineering (using mitm-proxy) to find how Docker Desktop itself is looking for updates.
I found this URL is used on my Apple Silicon machine:
https://desktop.docker.com/mac/main/arm64/appcast.xml
It's returning XML
unfortunately (I wish it would be JSON
, but 🤷🏼♂️)
Here is the generic version:
https://desktop.docker.com/{platform}/main/{architecture}/appcast.xml
Where:
{platform}
is one of linux
, mac
or win
{architecture}
is one of arm64
and amd64
In fact, this appcast.xml
file is defined by Sparkle and defined here.
The current code base already has a way to do some checks, which is documented here, and I plan on doing the following changes:
Change the name of the settings so they are more specific (changing updater_{check,latest_version,changelog}
to updater_release_*
), and providing a way to migrate the old settings to this new naming.
Introducing new settings:
updater_docker_check
which will make it possible for the user to enable / disable this check;updater_docker_latest_version
, storing the latest known remote versionupdater_docker_latest_changelog
where we could cache the changelog (provided by appcast.xml
)The settings would then look like this:
# Updater settings
"updater_last_check": None, # last check in UNIX epoch (secs since 1970)
"updater_errors": 0,
# Update release settings
"updater_release_check": None,
"updater_release_latest_version": get_version(),
"updater_release_latest_changelog": "",
# Update docker settings
"updater_docker_check": None,
"updater_docker_latest_version": None,
"updater_docker_latest_changelog": "",
Use the already-in-place mechanism to do the checks, additionally checking for this new version check if it's enabled / not disabled, depending if we want to make this opt-in or opt-out (I would advise asking the user, so it's opt-in, to not leak anything to third parties without user consent).
Here are command lines for this. (Tested on macOS and windows) :
docker version --format '{{.Server.Platform.Name}}'
"Docker Desktop 4.19.0 (106363)"
Parsing a remotely loaded XML file can be an attack vector, as there are multiple XML vulnerabilities out there. To circumvent this, relying on defusedxml might help.
That would also be good to have another non-xml way to get the latest version, but that would diverge from the official way, as far as I'm aware.
Very cool Alexis, thanks a lot for the dig! Diving into your comments right now:
It seems that the only way to check if there's a new Docker Desktop version out is to:
Parse the returned XML in a safe way (didn't know about defusedxml
, nice), and grab the latest release.
Which is the latest release btw? Are we sure that the user can install it? I'm seeing some restrictions in the xml:
<sparkle:minimumSystemVersion>
( [EditionID] != Home && [EditionID] != HomeEval && [EditionID] != Core && [EditionID] != CoreN && [EditionID] != CoreSingleLanguage && [EditionID] != CoreCountrySpecific && [BuildNumber] >= 19044 ) || ( [BuildNumber] >= 19044 )
</sparkle:minimumSystemVersion>
Also, I don't know if they have any beta/stable channels, which may confuse our parsing logic.
What I'm concerned about is that we need to handle the following cases:
appcast.xml
URL that is not there (highly unlikely, but it can be the case)appcast.xml
(e.g., because the user is in a system that cannot upgrade to it)From a UX perspective, based on your suggestions, I understand that we also need to:
The security audit that spawned this issue says the following:
The assessment team recommends implementing a feature in Dangerzone that checks the host system for the latest version of Docker/Docker Desktop upon startup. If the feature detects an outdated Docker installation, Dangerzone could then provide a warning to the user, recommending an update. This precaution aims to mitigate the risk of attackers exploiting vulnerabilities within the container to escape to the host system.
It assumed that a mechanism existed locally where you could check for the latest version of Docker. It would be great if docker info
or docker version
provided this info, but unfortunately it doesn't. With that said, I believe that reimplementing a subset of the Sparkle client in our application for another app (Docker) would open a different can of worms than the ones we have now. It can work, sure, but we have to be very careful with regards to security and user privacy.
So, ultimately I think we should think this through before going forward. Maybe there's another way with less corner cases that can work here, at least for a subset of the affected users.
Thanks for the feedback. I agree that redoing a sparkle client seems superfluous, and I share your concerns about the restrictions present in the XML
, which seem to follow a language we don't know.
You comment made me look for alternate ways to know the latest available version of Docker Desktop. Maybe Docker Desktop is storing the data somewhere we can reuse ? 🤔 That would mean the checks are done out of band for us, and that we can reuse their code by just looking at the results.
But… I'm not even sure that's possible. I'll have a closer look.
After some tinkering on my system, I'm unable to find this information. I'm putting here my findings, but I'm not sure they're relevant.
I've been looking at the following locations:
~/Library/Group\ Containers/group.com.docker/
, contains some version information, but it's fairly weird, I'm not sure we should rely on it:
cat unleash-repo-schema-v1-Docker\ Desktop.json | jq ".SidebarLayout"
{
"name": "SidebarLayout",
"description": "Enables new Sidebar Layout for Docker Desktop",
"enabled": true,
"strategies": [
{
"id": 0,
"name": "flexibleRollout",
"constraints": [
{
"contextName": "version",
"operator": "SEMVER_LT",
"values": [],
"value": "4.31.0",
"caseInsensitive": false,
"inverted": true
}
],
"parameters": {
"groupId": "SidebarLayout",
"rollout": "100",
"stickiness": "default"
},
"segments": null
}
],
"createdAt": "0001-01-01T00:00:00Z",
"strategy": "",
"parameters": null,
"variants": []
}
There is a settings.json
file there, where we can see if the automatic updates are activated, what's the channel, etc. It might prove useful.
cat settings.json | jq | grep -i Update
"updateAvailableTime": 1692453100698,
"updateInstallTime": 0,
"disableUpdate": false,
"acceptCanaryUpdates": false,
"useNightlyBuildUpdates": false,
"autoDownloadUpdates": false,
"updateHostsFile": false,
FYI, I'm not pursuing the effort on this pull request because the path forward is not clear. I've pushed the changes (related to renaming the settings) to the 2024-06-docker-desktop-version-check
branch in case it's useful for the future.
Thanks for documenting your findings Alexis. They will be really useful once we decide to work again on this issue. For the record, I was thinking that we could at least notify the user that their Docker Desktop installation is outdated if, e.g., it's been 6 months since the last release (docker version
returns the build date of the software, for instance).
This is one possible metric we can use that does not rely on external sources. It doesn't cover every use case, sure, but it will help the vast majority of our users, who have installed Docker Desktop at some point and then forgot about it.
One other thing I was considering is if Docker Desktop already has such a mechanism. My thinking was that:
So, if Docker Desktop informs users about important upgrades on startup, we're good.
One other thing I was considering is if Docker Desktop already has such a mechanism. My thinking was that:
- Our users need to start Docker Desktop manually, in order to run Dangerzone
- Sparkle project can notify users about updates, if they are critical
So, if Docker Desktop informs users about important upgrades on startup, we're good.
This is the case: Docker Desktop is displaying a warning to the users when they start the program, at least on OSX (I'm not sure on Windows, but I expect this to be the same, we should check).
Here is how this is displayed to the end users:
None of these are blocking, though.
Also worth nothing: in the "software updates" settings, there is an "Always download updates" checkbox:
I was thinking that we could at least notify the user that their Docker Desktop installation is outdated if, e.g., it's been 6 months since the last release (docker version returns the build date of the software, for instance).
That would certainly be useful. I'm also thinking we could add a minimal supported version in the dangerzone code somewhere (potentially even one for Windows and one for MacOS), and warn the user if the installed version doesn't match this.
Because we're issuing a release every two months (approximately), it would allow to warn our users to upgrade quicker than the 6 month cap you're mentioning.
We could check the version returned by docker version
:
$ docker version --format '{{.Server.Platform.Name}}'
"Docker Desktop 4.19.0 (106363)"
This is the case: Docker Desktop is displaying a warning to the users when they start the program, at least on OSX
Pretty awesome dig, and thanks a lot for the image. So, it seems that Docker does not urge the users to update, but it does inform them about it (kind of like our own update notifications).
That would certainly be useful. I'm also thinking we could add a minimal supported version in the dangerzone code somewhere (potentially even one for Windows and one for MacOS), and warn the user if the installed version doesn't match this.
That's actually a really good idea! Are you thinking of showing a warning notification to our users, or something more visible, like a pop-up? Note that for Dangerzone updates, we show just a notification bubble for the time being.
That's actually a really good idea! Are you thinking of showing a warning notification to our users, or something more visible, like a pop-up? Note that for Dangerzone updates, we show just a notification bubble for the time being.
That's a good question, and the answer depends on how we want this to be annoying for our users. If we don't want to be too annoying, reusing the notification bubble might be enough.
Even though we are shipping updates when critical vulnerabilities are found in the container image, the user may be running an outdated Docker Desktop version, which in the worst-case scenario is a container escape vulnerability, which completely undermines the security of the system.
We should add to the updater a way of notifying the user of Docker Desktop updates.