storage: Don't auto-mount loopback devices except in develop mode

In the event containers are being used on the server with images, attempting to
auto-mounting loop devices could interfere with their operation. We currently
don't have a use case where a user would want to auto-mount loop devices.
Initially suggested in
https://salsa.debian.org/freedombox-team/freedombox/-/issues/1854

Tests performed:

- Add a loopback device as follows and observe that is automatically mounted.

  dd if=/dev/zero of=/tmp/test_disk bs=1M count=100
  mkfs.ext4 /tmp/test_disk
  losetup loop0 /tmp/test_disk
  umount /dev/loop0
  losetup -d /dev/loop0

- Add a loopback device as follows and observe that both partitions are mounted.

  dd if=/dev/zero of=/tmp/test_disk bs=1M count=100
  parted /tmp/test_disk
  mklabel gpt
  mkpart Part1 ext4 0% 50%
  mkpart Part2 ext4 50% 100%
  kpartx -avs /tmp/test_disk
  mkfs.ext4 /dev/mapper/loop0p1
  mkfs.ext4 /dev/mapper/loop0p2
  umount /dev/mapper/loop0p1
  umount /dev/mapper/loop0p2
  kpartx -dvs /tmp/test_disk

- When --develop is removed or when code is modified to negate the not
  condition, the partitions are not auto-mounted in the above cases.

Reported-by: James Valleroy <jvalleroy@mailbox.org>
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
Sunil Mohan Adapa 2020-06-02 11:15:40 -07:00 committed by James Valleroy
parent 8c05fb0722
commit 426cef4c2c
No known key found for this signature in database
GPG Key ID: 77C0C75E7B650808

View File

@ -6,7 +6,7 @@ Handle disk operations using UDisk2 DBus API.
import logging import logging
import threading import threading
from plinth import actions from plinth import actions, cfg
from plinth.errors import ActionError from plinth.errors import ActionError
from plinth.utils import import_from_gi from plinth.utils import import_from_gi
@ -21,6 +21,7 @@ _INTERFACES = {
'Drive': 'org.freedesktop.UDisks2.Drive', 'Drive': 'org.freedesktop.UDisks2.Drive',
'Filesystem': 'org.freedesktop.UDisks2.Filesystem', 'Filesystem': 'org.freedesktop.UDisks2.Filesystem',
'Job': 'org.freedesktop.UDisks2.Job', 'Job': 'org.freedesktop.UDisks2.Job',
'Loop': 'org.freedesktop.UDisks2.Loop',
'Manager': 'org.freedesktop.UDisks2.Manager', 'Manager': 'org.freedesktop.UDisks2.Manager',
'ObjectManager': 'org.freedesktop.DBus.ObjectManager', 'ObjectManager': 'org.freedesktop.DBus.ObjectManager',
'Partition': 'org.freedesktop.UDisks2.Partition', 'Partition': 'org.freedesktop.UDisks2.Partition',
@ -114,6 +115,7 @@ class Partition(Proxy):
interface = _INTERFACES['Partition'] interface = _INTERFACES['Partition']
properties = { properties = {
'number': ('u', 'Number'), 'number': ('u', 'Number'),
'table': ('o', 'Table'),
} }
@ -123,6 +125,12 @@ class Filesystem(Proxy):
properties = {'mount_points': ('aay', 'MountPoints')} properties = {'mount_points': ('aay', 'MountPoints')}
class Loop(Proxy):
"""Abstraction for UDisks2 Loop."""
interface = _INTERFACES['Loop']
properties = {'backing_file': ('ay', 'BackingFile')}
def get_disks(): def get_disks():
"""List devices that can be ejected.""" """List devices that can be ejected."""
devices = [] devices = []
@ -226,6 +234,19 @@ def _on_filesystem_added(object_path, _interfaces):
threading.Thread(target=_consider_for_mounting, args=[object_path]).start() threading.Thread(target=_consider_for_mounting, args=[object_path]).start()
def _is_loop_device(object_path):
"""Return if the block device is a loop device backed by a file."""
loop = Loop(object_path)
if loop.backing_file:
return True
partition_table = Partition(object_path).table
if partition_table:
return _is_loop_device(partition_table)
return False
def _consider_for_mounting(object_path): def _consider_for_mounting(object_path):
"""Check if the block device needs mounting and mount it.""" """Check if the block device needs mounting and mount it."""
block_device = BlockDevice(object_path) block_device = BlockDevice(object_path)
@ -254,6 +275,12 @@ def _consider_for_mounting(object_path):
block_device.id, block_device.preferred_device) block_device.id, block_device.preferred_device)
return return
# Ignore loopback devices except in development mode.
if _is_loop_device(object_path) and not cfg.develop:
logger.info('Ignoring loop device in production mode: %s %s',
block_device.id, block_device.preferred_device)
return
_mount(object_path) _mount(object_path)