Initial ideas on portals for file access



The xdg-app stuff for non-sandboxed apps is functioning pretty well
now, and even if its not 100% there yet its time to start looking at
making sandboxed application integrate with the system, the so called
"portals".

I've been thinking a bit about file access in sandboxed apps. There
are all sorts of files of course, some are the executables and data
files require for the app to work, and others are internal things like
save games and databases. These are really not all that hard, we
already have the readonly files in the app, and per-app writable
storage for internal files. The more interesting part is instead what
I'd call documents. These are files that the user is aware of and that
can be used by multiple applications. Typical examples of such files
are images, videos, text files, audio files, office documents, pdf
files.

There are a few ways such documents could be used by sandboxed
applications:

* Application silos

  All documents are owned by a particular app, sharing between
  applications is a copy operation. This is the model that iOS uses
  mostly. Its simple (already works in xdg-app essentially) and
  very safe.

* Allow app access to parts of $HOME

  For instance, you could have libreoffice have access to ~/Documents
  only. This is pretty limiting and not particularly safe, but it is
  easy to implement. This is similar to the android model, where apps
  that read shared files request the permissions to read your storage,
  and then get full access.

* Allow application access to files after interactive operation

  If the app initiates an interactive operation, such as an open file
  dialog, that runs outside the control of the application, and the
  user selects a particular file, then we can safely send the content
  of the file to the app. The reason this works is that the user
  implicitly grants access to the selected file, and is aware that the
  app wants it, all in a natural fashion.

  This is a very interesting model, as it allows a more traditional
  way to store your files, yet it is still quite safe.  However, this
  model only works in a limited number of cases, since a lot of
  operations (for example "save") does not have a natural user
  interaction.

* Implicit permission grants from interactive operations

  This is an extension of the previous model where certain operations
  implicitly grants further permissions for the application. A typical
  example would be once you've opened a file you are then allowed to
  read it again.

  This model is very pragmatic. Its not quite as safe as the previous
  one (details depend on the exact rules used), but it makes it possible
  to model a lot of typical file use.

So, what do we want to do here? I don't think the application silo
model is a good fit, because its very unlike how desktop Linux works
(users file are stored in $HOME), and we would be fighting both users
and existing apps making this work. We could allow partial HOME access
to some very trusted apps, but that doesn't really strikes me as a
proper sandbox solution.

In my opinion the last model is the one we need to focus on. The
question is what kind of implicit permissions are we talking
about. For example, in the case of an open file dialog, here are some
permissions that could be granted to the app:

 * Ability to read file contents (clearly ok)
 * Access to an actual file descriptor for the file
 * Access to the same file at a later time (how much later?)
 * Access to a new version of the file at the same place
 * Ability to replace the file with a new version
 * Access other files in the same location (say video subtitles)
 * Knowledge about the file (filename, mimetype, mtime, etc)
 * Knowledge about the file environment (pathname, type of share, etc)
 * Ability to persist the file reference for later in e.g. "recent
files"
   (across app restart, and/or system restarts)
 * Ability to pass the cookie to another app

I don't think all of these are should be granted, but some
should. Clearly the open call has to returns some kind of (probably
persistent) opaque cookie that refers to the file and has app
permission stored on it.

Unrelated to sandboxing, such cookies are also something we've kind of
wanted for a while in GVfs/Gio. The GFile APIs in glib is very an
abstraction for file access on a bit lower level than "documents". The
goal with it is to be able to implement e.g. a file manager and a file
selector, as well as fitting in with our current APIs for those. This
leads to a set of semantics that are closer to POSIX than what is
needed for a pure document open/save API. In particular, it encodes
the requirement that the app is able to select, ahead of time the
storage identifier (filename) for files, which kind of breaks for
cloud-style database backed file stores like google drive, where the
file identifier is a db unique key and the filename is just a piece of
metadata. If we add an API for the kind of document cookies described
above we should make sure it also can be used even in non-sandboxed
apps for these kinds of stores.

Here are some assumptions I'm making on how document files will be
used.  I believe these are realistic, and these limitations will help
us design the APIs.

* A document instance would be read only (i.e. no in place replacement
  like databases or log files)
* A document can be replaced with a new version
* Document could be read/written as a stream, but they are also often
  done using seeks (for instance seek in videos, or back-patching
  file headers when saving).
* Documents can be large (videos)
* Applications will work on the files as if they were local, rather
  than as if they were doing a network operation. This implies a
  possible download/upload operation outside the app.
  If you need to do streaming from the network you should use an
  actual network protocol library instead.
* Documents can be local files, or from a network filesystem (smb,
  nfs) or from some kind of cloud service (google drive)

Given the above, here is a strawman proposal for how this could work:

There is a dbus service on a well known name on the session bus. All
requests about documents goes through it, and all sandboxed apps can
talk to it.

All references to documents are done via opaque cookies, which are
stored on the host side, and contain per-app permissions for
operations/information. These cookies are persisted by the dbus
service, so an app can store them in they data.

Cookies are created by interactive requests, like open file dialogs,
or save as dialogs, although we may allow an app to create a cookie
for an already existing file belonging to itself without interaction.

Actually reading and writing files is done by passing a file
descriptor to the application. In the read case, a read-only one for
the actual file (or a cached copy), and in the write case a read-write
one for a temporary file.

All operations are fully async, and have some kind of reference to a
parent window so that they can do slow i/o and show interactive
dialogs.

Here are some available operations:

Open() - open document dialog, then optional download dialog
  Input: document type filter
  Output: A cookie
  Permissions granted:
    Allow reading the current version forever
    Allow reading future versions forever (maybe?)
    Allow getting file metadata
    These permissions affect only this app, other (sandboxed) apps have
      no access, so you can't pass on the cookie

SaveAs() - save-as dialog, then optional upload dialog
  Input: Initial title (can be used as filename)
  Output: A cookie
          A fd to write the file data to
          A way to set preview and metadata on the new file
  Permissions granted:
    Allow Save() without UI until a new version of the document
    Allow reading the file until a new version of the document

Save() - save new version to existing cookie, optional upload dialog
  Input: Cookie
  Output: Shows dialog if not allowed:
             No auth at all: "app foo wants to save..."
             Auth on previous version: "The file has changed since last
              time, do you still want to save"
          Way to write the data as in SaveAs()
  Permissions granted:
    Allow save and read of the new versions (until new version)

We would also have to make up some new kind of url scheme so that we
can persist these cookies to files, and so that we can pass then to
apps when we open files (i.e. when you click on a file in the file
manager).

There are some weaknesses i see here:

* The database for cookies risk growing forever, as its generally
  hard to know how to revoke some permission.
* In the save operation, I can't think of a good way to revoke access
  to the file once the app has finished writing and we're about to
  rename it over the old file. This means an app can modify a file
  that some other app is reading.
* In wayland we don't have a great way to "parent" dialogs between
  client, so we can't make the file selector seem to be owned by
  the window that requested the file operation without some form
  of compositor help.

Anyway, this can be fleshed out more, but I'd love to hear some feedback
on this first.

-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 Alexander Larsson                                            Red Hat, Inc 
       alexl redhat com            alexander larsson gmail com 
He's a time-tossed misogynist jungle king fleeing from a secret 
government programme. She's a sharp-shooting tomboy traffic cop with 
someone else's memories. They fight crime! 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]