Automatic Update System for Scripts

Jakob Kummerow jakob.kummerow at googlemail.com
Mon Sep 7 12:37:37 UTC 2009


Hi everyone,

I posted this to the forum last night, but then Mamarok told me it
would be better to post it here instead, so here goes:


A. Introduction

Inspired by the recent turmoil with the lyricswiki-script, and based
on the fact that scripts can easily be updated without recompiling or
reinstalling Amarok, I had the idea that an automated updating system
for scripts would be a great thing. Especially, this would mean that
new versions of scripts can be published in a matter of minutes,
without the need to release a new version of Amarok (or to wait for
such a release).
Discussing the idea in IRC it quickly turned out that (a) I wasn't the
first to think of it and (b) to prevent any security risks, digital
signing would be necessary. Of course, updates would only be hosted on
a trusted server (amarok.kde.org I guess), but you have to assume that
each and every webserver is hackable, and an automated update system
that distributes malicious code is quite a nightmare.
I went ahead and created first a small proof-of-concept app and then a
slightly larger standalone app that provides the functionality we
need, based on KDE and Qt technology. The cryptographic stuff that's
needed for the signatures is provided by the "Crypto++" library, which
therefore becomes a new dependency for Amarok. I have not yet actually
integrated the new code into Amarok, but hopefully that will mainly be
a matter of copy-'n'-pasting now.


B. What works:

   * generating key pairs (small command-line app)
   * creating signatures for files (same small command-line app, the
two can easily be split if deemed appropriate)
   * copying all scripts from /usr/share/apps/amarok/scripts/ to
~/.kde(4)/share/apps/amarok/scripts/, which is of course necessary to
make the scripts replacable without requiring root access
   * determining the version number of the existing scripts
   * checking a predefined location for updates
   * deciding on the applicability of those updates
   * downloading the updates
   * verifying the signatures of the updates
   * installing the updates (if verification was successful)

That's pretty much all we need :-)


C. What remains to be done is integrating all of that into Amarok, and
here I need some help:

   * At which point exactly is it most reasonable to perform the
updating procedure? My guess is
dialogs/ScriptManager::ScriptManager(QWidget* parent), or the
beginning of dialogs/ScriptManager::findScripts(), but I'm not sure
whether there's a better solution.
   * With the changes incorporated, Amarok will need Crypto++ both
for compiling and at run time. Crypto++ is available via the package
managers of Gentoo and Ubuntu; I didn't check other distros but they
should have it, too. How does one have to change the build system to
integrate the new dependency? (In the simple Makefile I've used for
testing, the required parameter is "-lcryptopp")
   * The (probably) biggest remaining change is that so far, I
execute the downloads of version, update and signature synchronously;
I guess that will have to be changed to asynchronous operation.
Unfortunately, I have no idea how the Qt event system that's required
for this works. All I can say is "SLOT? wtf?".
     Please, could someone either explain to me how I can use
asynchronous downloads, or (even better :P ) offer to take over
implementation of that part?
     There's one small catch: The contents of the method
ScriptManager::findScripts() should only be executed after the
updating process, asynchronous or not, has finished. Otherwise an
additional restart of Amarok would be necessary in order for the
updated scripts to be used.
   * Which base URL should be used for the update checks?
amarok.kde.org/updates/scripts/ ?
   * The public key that must be integrated into Amarok is around 400
bytes of base64 encoded data. Should I put it as a string directly
into the source code, or is it better to have it as a separate file?
If the latter, where? I don't think there's a reason not to put it
into the source, because we don't intend to change it; and if we do
want to change it, that can happen in the next Amarok version.



D. And here is the (planned) workflow for releasing an update:

1. Joe User in a spate of industriousness creates an updated version
of greatscript/main.js and greatscript/logo.png
2. He sends them to Dev E. Loper for review.
3. Dev verifies that the new version works and doesn't contain malicious code.
4. Dev especially makes sure that in the first line of main.js, the
NUMBER in "AmarokScriptVersion=NUMBER" got incremented. (It doesn't
really matter by how much, but there must be an increment to prevent
endless updating loops. Only integers are allowed, no point releases.)
Dev memorizes the new version number.
5. Dev puts the updated files into an archive called main.tar.gz
(important: without any enclosing folder!)
6. Using his private key, Dev signs the archive, generating
main.tar.gz.signature.
7. Assuming the base URL for updates is
http://amarok.kde.org/updates/scripts/, Dev now puts the files online:

   mv main.tar.gz http://amarok.kde.org/updates/scripts/greatscript/main.tar.gz
   mv main.tar.gz.signature
http://amarok.kde.org/updates/scripts/greatscript/signature (note the
renaming!)

And yes, I know that you can't use mv exactly like that. But you
understand what I mean, right?
8. Finally, Dev tells Amarok clients all over the world that an update
is available, using the version number he remembers:

   echo "<version number>" >
http://amarok.kde.org/updates/scripts/greatscript/version

9. After that, when somewhere on the internet an Amarok is started, it
will notice the update, download, verify and install it.
10. Dev and Joe pat each other on the back for having cooperated so
well, dancing around the room because Amarok is ro'king so much :-)


E. A few remarks:

   * The filenames "main.tar.gz", "signature" and "version" are
hard-coded into the updater, so it's important that the files are
named exactly like that.
   * Each script must have a "main.js" anyway, and a new requirement
is that in the first line of that file, "AmarokScriptVersion=NUMBER"
must be present. Whitespace and other comments are allowed as well.
The line might for instance look like this:

         // info for the update system: AmarokScriptVersion = 3   Do
not change this unless you know what you're doing!

     Updating clients compare the number in the first line of the
existing file $KDEHOME/share/apps/amarok/scripts/greatscript/main.js
with the contents of
http://amarok.kde.org/updates/scripts/greatscript/version when they
decide whether to perform an update or not.
   * To let the clients find the update, the directory with the
script's name ("greatscript" in the example) must be identical on the
server and in Amarok's script directory.
   * If an evil hacker takes over the server amarok.kde.org and puts
harddrive-wiping code into all of the scripts stored there (and
increments all version numbers), the installed Amaroks in the world
will download the updates, try to verify their signatures with the
public key that's integrated into Amarok, that verification will fail,
and no update will be performed. As long as the developers who have
access to the private key keep this key secret, it is guaranteed that
each update was in fact signed by a developer.
   * If an evil hacker manages, in addition to taking over the
server, to change the public keys that are part of Amarok
installations worldwide to match a private key that he generated
himself, he would then be able to abuse the updating system for his
purposes. On the other hand, if he's already managed to change data on
your hard drive, you're f*cked anyway...


F. What about security?

Well, I'm not Bruce Schneier, but as a computer science student I've
got enough background information to know what I'm talking about. And
what I say is: As described/implemented so far, the updating system is
secure. At least, it's what's considered secure by everyone at the
moment. That means:
Digital signing is intended to protect against:

   * compromised update servers
   * compromised connections to the server ("man-in-the-middle"
attacks, compromised proxies/routers, or simply transmission errors)

and it achieves this protection successfully. It won't and can't
protect against:

   * trusted devs having their computers hacked or their houses
broken into, where the private key might be stolen
   * trusted devs signing unstable/malicious/crappy code because they
didn't see the code was bad
   * trusted devs turning over to the Dark Side(TM)
   * changed public keys on users' computers
   * brute force attacks; but unless you've got a supercomputer at
your disposal and several years of time on your hands you don't really
have a chance to find the private key
   * a scientific breakthrough that renders current encryption
schemes weak (extremely unlikely, but can't be ruled out)
   * earthquakes, so-called terrorist attacks, and the grass getting
all wet in the rain.

So, relax, these remaining risks are (a) very very small and (b)
anyway completely unavoidable. If you don't trust the Amarok devs'
good intentions and competence, don't use Amarok. In fact, it's best
not to use a computer at all.


G. Addendum

Apparently I haven't made it entirely clear that the updating system
is intended for the scripts that come with Amarok only; I don't want
to replace kde-apps.org or GHNS, and I certainly don't want to put any
additional stress on the hard-working devs. On the other hand, the
updater doesn't care where a script originally came from, if it finds
a version number in the first line, it looks for updates; so if you
ever decide to cooperate with 3rd-party script authors on the updating
mechanism, no change to the code would be required, it would just
work. Generally, I consider the system lightweight (maybe with the
exception of the extra library requirement) and easy-to-use. The part
that goes into Amarok is about 100 lines of code.

Any thoughts? Any help? Of course, I can immediately publish my source
code, if anyone wants to look at it.

Regards,
Jakob



More information about the Amarok mailing list