mirror of
https://github.com/mvt-project/mvt.git
synced 2026-09-23 18:00:53 +02:00
Merge pull request #937 from va-resident/fix/mountinfo-rw-both-layers
Fix mountinfo read-write detection across both option layers
This commit is contained in:
@@ -136,6 +136,10 @@ class Mounts(AndroidArtifact):
|
||||
mount_options = fields[5].split(",")
|
||||
super_options = fields[separator + 3].split(",")
|
||||
options = list(dict.fromkeys(mount_options + super_options))
|
||||
# fields[5] are the per-mount (VFS) flags, the field after the
|
||||
# separator the superblock's; a mount is writable only if both
|
||||
# allow it. The merged list made every read-only overlay a HIGH.
|
||||
is_read_write = "rw" in mount_options and "rw" in super_options
|
||||
mount_point = fields[4].replace("\\040", " ")
|
||||
device = fields[separator + 2].replace("\\040", " ")
|
||||
filesystem_type = fields[separator + 1]
|
||||
@@ -156,7 +160,7 @@ class Mounts(AndroidArtifact):
|
||||
"options_list": options,
|
||||
"optional_fields": fields[6:separator],
|
||||
"is_system_partition": is_system,
|
||||
"is_read_write": "rw" in options,
|
||||
"is_read_write": is_read_write,
|
||||
"process_ids": [process_id],
|
||||
}
|
||||
)
|
||||
@@ -191,7 +195,14 @@ class Mounts(AndroidArtifact):
|
||||
)
|
||||
|
||||
# Check for other suspicious mount options
|
||||
suspicious_opts = [opt for opt in options if opt in SUSPICIOUS_OPTIONS]
|
||||
# `rw` sitting in the merged option list is not evidence of
|
||||
# writability (see is_read_write in parse_mountinfo); every other
|
||||
# suspicious option is meaningful in either list.
|
||||
suspicious_opts = [
|
||||
opt
|
||||
for opt in options
|
||||
if opt in SUSPICIOUS_OPTIONS and (opt != "rw" or mount["is_read_write"])
|
||||
]
|
||||
if suspicious_opts and mount["is_system_partition"]:
|
||||
if (
|
||||
"noatime" in mount["mount_options"]
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# Mobile Verification Toolkit (MVT)
|
||||
# Copyright (c) 2021-2026 The MVT Authors.
|
||||
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||
# https://license.mvt.re/1.1/
|
||||
"""A mount is writable only if both mountinfo option layers allow it."""
|
||||
|
||||
from mvt.android.artifacts.mounts import Mounts
|
||||
from mvt.common.alerts import AlertLevel
|
||||
|
||||
# fields[5] is the per-mount (VFS) layer, the field after "-" the superblock.
|
||||
RO_OVERLAY = (
|
||||
"304 166 0:130 / /product/usr rw,relatime shared:63 - overlay overlay "
|
||||
"ro,seclabel,lowerdir=/mnt/vendor/ext/product/usr:/product/usr"
|
||||
)
|
||||
RW_SYSTEM = (
|
||||
"305 166 0:131 / /system rw,relatime shared:64 - ext4 /dev/block/dm-1 "
|
||||
"rw,seclabel,errors=panic"
|
||||
)
|
||||
|
||||
|
||||
def _run(line):
|
||||
mounts = Mounts()
|
||||
mounts.results = Mounts.parse_mountinfo(line, 1)
|
||||
mounts.check_indicators()
|
||||
return mounts
|
||||
|
||||
|
||||
class TestMountsReadWriteLayers:
|
||||
def test_rw_vfs_over_ro_superblock_is_not_writable(self):
|
||||
mounts = _run(RO_OVERLAY)
|
||||
assert mounts.results[0]["is_read_write"] is False
|
||||
assert mounts.alertstore.count(AlertLevel.HIGH) == 0
|
||||
assert mounts.alertstore.count(AlertLevel.MEDIUM) == 0
|
||||
|
||||
def test_rw_in_both_layers_still_alerts(self):
|
||||
mounts = _run(RW_SYSTEM)
|
||||
assert mounts.results[0]["is_read_write"] is True
|
||||
assert mounts.alertstore.count(AlertLevel.HIGH) == 1
|
||||
|
||||
def test_both_option_layers_are_still_reported(self):
|
||||
mounts = _run(RO_OVERLAY)
|
||||
options = mounts.results[0]["options_list"]
|
||||
assert "rw" in options and "ro" in options
|
||||
Reference in New Issue
Block a user