03 Nov, 2020

5 commits

  • When using FUSE passthrough, read/write operations are directly forwarded
    to the lower file system file through VFS, but there is no guarantee that
    the process that is triggering the request has the right permissions to
    access the lower file system. This would cause the read/write access to
    fail.

    In passthrough file systems, where the FUSE daemon is responsible for the
    enforcement of the lower file system access policies, often happens that
    the process dealing with the FUSE file system doesn't have access to the
    lower file system.
    Being the FUSE daemon in charge of implementing the FUSE file operations,
    that in the case of read/write operations usually simply results in the
    copy of memory buffers from/to the lower file system respectively, these
    operations are executed with the FUSE daemon privileges.

    This patch adds a reference to the FUSE daemon credentials, referenced at
    FUSE_DEV_IOC_PASSTHROUGH_OPEN ioctl() time so that they can be used to
    temporarily raise the user credentials when accessing lower file system
    files in passthrough.
    The process accessing the FUSE file with passthrough enabled temporarily
    receives the privileges of the FUSE daemon while performing read/write
    operations. Similar behavior is implemented in overlayfs.
    These privileges will be reverted as soon as the IO operation completes.
    This feature does not provide any higher security privileges to those
    processes accessing the FUSE file system with passthrough enabled. This is
    because it is still the FUSE daemon responsible for enabling or not the
    passthrough feature at file open time, and should enable the feature only
    after appropriate access policy checks.

    Bug: 168023149
    Link: https://lore.kernel.org/lkml/20201026125016.1905945-6-balsini@android.com/
    Signed-off-by: Alessio Balsini
    Signed-off-by: Alessio Balsini
    Change-Id: I1123f8113578eb8713f2b777a1b5ec76882bd762

    Alessio Balsini
     
  • Extend the passthrough feature by handling asynchronous IO both for read
    and write operations.

    When an AIO request is received, if the request targets a FUSE file with
    the passthrough functionality enabled, a new identical AIO request is
    created. The new request targets the lower file system file and gets
    assigned a special FUSE passthrough AIO completion callback.
    When the lower file system AIO request is completed, the FUSE passthrough
    AIO completion callback is executed and propagates the completion signal to
    the FUSE AIO request by triggering its completion callback as well.

    Bug: 168023149
    Link: https://lore.kernel.org/lkml/20201026125016.1905945-5-balsini@android.com/
    Signed-off-by: Alessio Balsini
    Signed-off-by: Alessio Balsini
    Change-Id: I1e6b4602e0813c425a41f370c856d2e99e771277

    Alessio Balsini
     
  • All the read and write operations performed on fuse_files which have the
    passthrough feature enabled are forwarded to the associated lower file
    system file via VFS.

    Sending the request directly to the lower file system avoids the userspace
    round-trip that, because of possible context switches and additional
    operations might reduce the overall performance, especially in those cases
    where caching doesn't help, for example in reads at random offsets.

    Verifying if a fuse_file has a lower file system file associated with can
    be done by checking the validity of its passthrough_filp pointer. This
    pointer is not NULL only if passthrough has been successfully enabled via
    the appropriate ioctl().
    When a read/write operation is requested for a FUSE file with passthrough
    enabled, a new equivalent VFS request is generated, which instead targets
    the lower file system file.
    The VFS layer performs additional checks that allow for safer operations
    but may cause the operation to fail if the process accessing the FUSE file
    system does not have access to the lower file system.

    This change only implements synchronous requests in passthrough, returning
    an error in the case of asynchronous operations, yet covering the majority
    of the use cases.

    Bug: 168023149
    Link: https://lore.kernel.org/lkml/20201026125016.1905945-4-balsini@android.com/
    Signed-off-by: Alessio Balsini
    Signed-off-by: Alessio Balsini
    Change-Id: If76bb8725e1ac567f9dbe3edb79ebb4d43d77dfb

    Alessio Balsini
     
  • Implement the FUSE passthrough ioctl() that associates the lower
    (passthrough) file system file with the fuse_file.

    The file descriptor passed to the ioctl() by the FUSE daemon is used to
    access the relative file pointer, that will be copied to the fuse_file data
    structure to consolidate the link between the FUSE and lower file system.

    To enable the passthrough mode, userspace triggers the
    FUSE_DEV_IOC_PASSTHROUGH_OPEN ioctl() and, if the call succeeds,
    receives back an identifier that will be used at open/create response
    time in the fuse_open_out field to associate the FUSE file to the lower
    file system file.
    The value returned by the ioctl() to userspace can be:
    - > 0: success, the identifier can be used as part of an open/create
    reply.
    - < 0: an error occurred.
    The value 0 has been left unused for backward compatibility: the
    fuse_open_out field that is used to pass the passthrough_fh back to the
    kernel uses the same bits that were previously as struct padding,
    zero-initialized in the common libfuse implementation. Removing the 0
    value fixes the ambiguity between the case in which 0 corresponds to a
    real passthrough_fh or a missing implementation, simplifying the
    userspace implementation.

    For the passthrough mode to be successfully activated, the lower file
    system file must implement both read_ and write_iter file operations.
    This extra check avoids special pseudo files to be targeted for this
    feature.
    Passthrough comes with another limitation: no further file system stacking
    is allowed for those FUSE file systems using passthrough.

    Bug: 168023149
    Link: https://lore.kernel.org/lkml/20201026125016.1905945-3-balsini@android.com/
    Signed-off-by: Alessio Balsini
    Signed-off-by: Alessio Balsini
    Change-Id: Id6067dcb882d58daef5ffe44355c383cabeed547

    Alessio Balsini
     
  • Expose the FUSE_PASSTHROUGH interface to userspace and declare all the
    basic data structures and functions as the skeleton on top of which the
    FUSE passthrough functionality will be built.

    As part of this, introduce the new FUSE passthrough ioctl(), which
    allows
    the FUSE daemon to specify a direct connection between a FUSE file and a
    lower file system file. Such ioctl() requires userspace to pass the file
    descriptor of one of its opened files through the fuse_passthrough_out
    data
    structure introduced in this patch. This structure includes extra fields
    for possible future extensions.
    Also, add the passthrough functions for the set-up and tear-down of the
    data structures and locks that will be used both when fuse_conns and
    fuse_files are created/deleted.

    Bug: 168023149
    Link: https://lore.kernel.org/lkml/20201026125016.1905945-2-balsini@android.com/
    Signed-off-by: Alessio Balsini
    Signed-off-by: Alessio Balsini
    Change-Id: I6dd150b93607e10ed53f7e7975b35b6090080fa2

    Alessio Balsini