Relative paths in .desktop, .service files' Exec= lines

Simon McVittie simon.mcvittie at collabora.co.uk
Mon Jun 20 17:24:58 UTC 2016


At the GTK Hackfest last week, while discussing what the GLib/GTK stack
can do to help make Linux apps more relocatable, the topic of
relocatable freedesktop .desktop and D-Bus .service files came up.
Looking at my email, I realise I already brought this up on these
mailing lists about 2 years ago. I would like to bring this to a
conclusion and get some wording into both specifications.

To recap:

* The meaning of absolute paths - Exec=/opt/whatever/bin/foo, or
  Exec=C:\whatever\bin\foo on Windows - is obvious.

* The meaning of Exec=foo in .desktop files is well-defined in the
  spec: it searches $PATH for foo, in the same way execlp() would.

* The meaning of Exec=foo in D-Bus .service files is not given in the
  D-Bus Specification, and the reference implementation in dbus-daemon
  is not particularly useful: it looks for foo in dbus-daemon's current
  working directory, which in practice is usually either / or $HOME.
  I think we can probably change this to be consistent with .desktop
  files in a development branch like 1.11 without actually breaking any
  practical application.

* The meaning of Exec=./foo or Exec=../bar/foo is unspecified.
  In dbus-daemon it is relative to the dbus-daemon's current working
  directory, which again does not seem particularly useful. In .desktop
  files, it probably depends on the launcher (usually a menu, a file
  manager or an implementation of XDG autostart). GNOME's GLib currently
  does the same unhelpful thing as dbus-daemon.

* I would very much like the specified behaviour in the D-Bus
  Specification to be the same as the specified behaviour of .desktop
  files, whatever that happens to be.

My preferred proposal: relative to .desktop file
================================================

I think relative paths containing at least one path separator (slash on
Unix, slash or backslash on Windows) should be treated as being relative
to the directory in which the .desktop or .service file was found, while
paths containing no path separators should have their current meaning
from the Desktop Entry Specification, and so should absolute paths. This
was suggested by KDE's Thiago Macieira during the previous discussion,
and was also unanimous among GTK hackfest attendees. I'm going to
propose Desktop Entry Specification and D-Bus Specification patches for
this unless there is consensus on something better.

One subtlety of the phrasing is that a single .desktop or .service file
might be visible in more than one directory thanks to symlinks, hard
links or bind mounts. Thiago's phrasing makes it specific that it is the
directory that actually appeared in the .desktop or .service search path
that matters, and not any of the same file's other apparent locations.

For the somewhat obscure feature in which
".../applications/foo/whatever.desktop" is equivalent to
".../applications/foo-whatever.desktop", I don't really care whether the
relative path is relative to .../applications or .../applications/foo. I
would go for .../applications if I have to make an arbitrary decision,
but I believe this feature was added to support something in KDE, so
I'll defer to whichever one KDE developers would prefer.

Alternatives and why I am not proposing them
============================================

Relative to executable
----------------------

Ralf Habacker's original proposal for D-Bus was to interpret relative
paths as relative to the the dbus-daemon executable, on platforms where
that can be determined (which includes at least Windows and Linux but
not all BSD platforms), stripping any trailing "/bin" first. Extending
this reasoning to .desktop files would result in GNOME Shell using paths
based on its executable /usr/bin/gnome-shell for programs chosen from
its menus, gnome-session using paths based on its executable
/usr/lib/gnome-session/gnome-session-binary, and so on.

The major objection to this interpretation should be obvious from the
two GNOME examples that I gave: the programs that interpret .desktop
files might be in ${libexecdir} instead of ${bindir}, and even if they
are, it is not necessarily *the same* ${bindir} (for example consider
the situation where you have GNOME in /usr/bin and KDE in
/opt/kde5/bin). This results in the same .desktop file being interpreted
differently by two launchers, which seems highly undesirable.

Relative to getcwd()
--------------------

This is what dbus-daemon and GLib currently do, and I don't think it's
at all useful. The current working directory of a process that launches
.desktop files, or of a dbus-daemon, is not well-defined; in practice it
will usually either be / or $HOME, neither of which seems a good base
for finding executables.

Fail to execute
---------------

Jon Watte advocated defining the meaning of a relative Exec= to be
"unconditionally fail to execute", so Exec=../bin/foo would simply never
work, asserting that relative paths are "a security can of worms". Some
rebuttals for the security concern:

* The Exec line in a .desktop file can execute arbitrary code - that's
  sort of the point. Exec=/bin/sh -c "echo pwned > ~/.bashrc" is
  mandated to work by the specification. As such, I don't see how
  defining a way to achieve relocatable .desktop files opens up
  a vulnerability on any system that is not already vulnerable: if you
  don't want to execute arbitrary code, you must already avoid launching
  arbitrary .desktop files.

* Relocation in almost the proposed way is already possible on Unix,
  because .desktop files can feed arbitrary commands to a
  Turing-complete shell. Proof of concept: if this is in
  /opt/Foo/share/applications/foo.desktop, as one long line:

  Exec=/bin/sh -c "cd \"${0%/*}\";shift;exec \"$@\"" %k ../../bin/foo %F

  it should (if I've got my shell and .desktop syntax right) cd to
  /opt/Foo/share/applications and then execute /opt/Foo/bin/foo with
  any supplied filenames as arguments. It isn't particularly robust,
  and wrongly overrides WorkingDirectory, but it works (modulo any
  errors I have made in that untested implementation). That being the
  case, making the same result easier and more robust can't possibly be
  a new security vulnerability?

Without further work, this would also leave us with no way to represent
relative paths to executables, and hence no way to have relocatable
(movable) app installations. This seems bad; there is clearly demand for
relocatable app installations on Linux (Canonical's Snap format, games
from gog.com or Humble Bundle, and so on), on Windows (which was the
context of the original request), and on OS X (where the expectation is
that "app folders" are usually movable).

Relative to some global configuration option
--------------------------------------------

There was a suggestion that either relative paths or paths starting with
some special token, perhaps "#", could denote "the root of the
installation" for relocation, with the root of the installation
configured via /etc on Unix or a Registry key on Windows. This is a
non-starter for at least D-Bus on Windows, where the ability to have
multiple complete "stacks" in distinct prefixes is valued. Similarly, if
installing applications in non-standard prefixes on Unix, there is
nothing that could be written in /etc as "the" root of "the"
installation that could be correct for all of them.

RFC
===

Are there any specific objections to this approach going into the
Desktop Entry and D-Bus specifications?

Does anyone have a better plan?

I'm assuming that GNOME programs do what GLib does, which is to look up
executables relative to getcwd(). What do other major desktop
environments like KDE do?

Thanks,
    S
-- 
Simon McVittie
Collabora Ltd. <http://www.collabora.com/>


More information about the xdg mailing list