From c19df6d2c70dff44e11599122c32ddd3430c6779 Mon Sep 17 00:00:00 2001 From: Nico <32375741+nulmete@users.noreply.github.com> Date: Fri, 15 May 2026 08:48:17 +0200 Subject: [PATCH] Fix double-counted Linux disk space from bind-mounted filesystems (#44969) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Related issue:** Resolves #43091 # Checklist for submitter - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements), JS inline code is prevented especially for url redirects, and untrusted data interpolated into shell scripts/commands is validated against shell metacharacters. ## Testing - [ ] Added/updated automated tests - [x] QA'd all new/changed functionality manually Was able to reproduce by enrolling a Ubuntu 25.10 host and mounting / onto a different path like this: ```bash sudo mkdir -p /tmp/snap.rootfs_TESTING sudo mount --bind / /tmp/snap.rootfs_TESTING ``` Then, refetched vitals and saw the total disk space doubled: Screenshot 2026-05-07 at 9 40 12 PM With the fix applied on this branch, refetched again and saw the correct total disk space: Screenshot 2026-05-07 at 9 31 15 PM ## Summary by CodeRabbit ## Bug Fixes - Resolved inaccurate total disk space reporting on Linux systems where the same filesystem is bind-mounted at multiple paths. --- changes/43091-inaccurate-total-disk-space | 1 + .../understanding-host-vitals.md | 4 +-- docs/queries.yml | 30 +++++++++++-------- server/service/osquery_utils/queries.go | 3 +- 4 files changed, 22 insertions(+), 16 deletions(-) create mode 100644 changes/43091-inaccurate-total-disk-space diff --git a/changes/43091-inaccurate-total-disk-space b/changes/43091-inaccurate-total-disk-space new file mode 100644 index 0000000000..837d75a26a --- /dev/null +++ b/changes/43091-inaccurate-total-disk-space @@ -0,0 +1 @@ +* Fixed Linux total disk space being double-counted when a filesystem was bind-mounted at multiple paths (e.g. snap-confine's `/tmp/snap.rootfs_*`). diff --git a/docs/Contributing/product-groups/orchestration/understanding-host-vitals.md b/docs/Contributing/product-groups/orchestration/understanding-host-vitals.md index f332682fb5..821883fdf7 100644 --- a/docs/Contributing/product-groups/orchestration/understanding-host-vitals.md +++ b/docs/Contributing/product-groups/orchestration/understanding-host-vitals.md @@ -175,7 +175,7 @@ SELECT (blocks_available * 100 / blocks) AS percent_disk_space_available, SELECT (blocks_available * 100 / blocks) AS percent_disk_space_available, round((blocks_available * blocks_size * 10e-10),2) AS gigs_disk_space_available, round((blocks * blocks_size * 10e-10),2) AS gigs_total_disk_space, - (SELECT round(SUM(blocks * blocks_size) * 10e-10, 2) FROM mounts WHERE + (SELECT round(SUM(per_device_size) * 10e-10, 2) FROM (SELECT MAX(blocks * blocks_size) AS per_device_size FROM mounts WHERE -- exclude mounts with no space blocks > 0 AND blocks_size > 0 @@ -223,7 +223,7 @@ OR device LIKE '/dev/nvme%' OR device LIKE '/dev/mapper%' OR device LIKE '/dev/md%' OR device LIKE '/dev/dm-%' -)) AS gigs_all_disk_space +) GROUP BY device)) AS gigs_all_disk_space FROM mounts WHERE path = '/' LIMIT 1; ``` diff --git a/docs/queries.yml b/docs/queries.yml index 37ad4ff55f..ab4a66b19a 100644 --- a/docs/queries.yml +++ b/docs/queries.yml @@ -113,7 +113,8 @@ spec: SELECT (blocks_available * 100 / blocks) AS percent_disk_space_available, round((blocks_available * blocks_size * 10e-10),2) AS gigs_disk_space_available, round((blocks * blocks_size * 10e-10),2) AS gigs_total_disk_space, - (SELECT round(SUM(blocks * blocks_size) * 10e-10, 2) FROM mounts WHERE + (SELECT round(SUM(per_device_size) * 10e-10, 2) FROM ( + SELECT MAX(blocks * blocks_size) AS per_device_size FROM mounts WHERE -- exclude mounts with no space blocks > 0 AND blocks_size > 0 @@ -121,7 +122,7 @@ spec: -- exclude external storage AND path NOT LIKE '/media%' AND path NOT LIKE '/mnt%' -- exclude device drivers - AND path NOT LIKE '/dev%' + AND path NOT LIKE '/dev%' -- exclude kernel-related mounts AND path NOT LIKE '/proc%' @@ -132,7 +133,7 @@ spec: AND path NOT LIKE '/var/run%' -- exclude boot files - AND path NOT LIKE '/boot%' + AND path NOT LIKE '/boot%' -- exclude snap packages AND path NOT LIKE '/snap%' AND path NOT LIKE '/var/snap%' @@ -142,24 +143,27 @@ spec: AND path NOT LIKE '/var/lib/containers%' AND type IN ( - 'ext4', - 'ext3', - 'ext2', - 'xfs', - 'btrfs', - 'ntfs', + 'ext4', + 'ext3', + 'ext2', + 'xfs', + 'btrfs', + 'ntfs', 'vfat', 'fuseblk', --seen on NTFS and exFAT volumes mounted via FUSE 'zfs' --also valid storage ) AND ( - device LIKE '/dev/sd%' - OR device LIKE '/dev/hd%' - OR device LIKE '/dev/vd%' - OR device LIKE '/dev/nvme%' + device LIKE '/dev/sd%' + OR device LIKE '/dev/hd%' + OR device LIKE '/dev/vd%' + OR device LIKE '/dev/nvme%' OR device LIKE '/dev/mapper%' OR device LIKE '/dev/md%' OR device LIKE '/dev/dm-%' + ) + -- group by device so a filesystem bind-mounted at multiple paths is only counted once + GROUP BY device )) AS gigs_all_disk_space FROM mounts WHERE path = '/' LIMIT 1; bash: df -P / | awk 'NR==2 { blocks=$2; blocks_available=$4; blocks_size=$2/$3 } END { printf "percent_disk_space_available=%.2f\n", (blocks_available * 100 / blocks); printf "gigs_disk_space_available=%.2f\n", (blocks_available * blocks_size * 10e-10); printf "gigs_total_disk_space=%.2f\n", (blocks * blocks_size * 10e-10) }' diff --git a/server/service/osquery_utils/queries.go b/server/service/osquery_utils/queries.go index e165cb6be6..3595df4438 100644 --- a/server/service/osquery_utils/queries.go +++ b/server/service/osquery_utils/queries.go @@ -442,11 +442,12 @@ var hostDetailQueries = map[string]DetailQuery{ Platforms: append(fleet.HostLinuxOSs, "darwin", "windows"), // not chrome }, "disk_space_unix": { + // GROUP BY device collapses bind mounts so a filesystem mounted at multiple paths is counted once. Query: fmt.Sprintf(` SELECT (blocks_available * 100 / blocks) AS percent_disk_space_available, round((blocks_available * blocks_size * 10e-10),2) AS gigs_disk_space_available, round((blocks * blocks_size * 10e-10),2) AS gigs_total_disk_space, - (SELECT round(SUM(blocks * blocks_size) * 10e-10, 2) FROM mounts %s) AS gigs_all_disk_space + (SELECT round(SUM(per_device_size) * 10e-10, 2) FROM (SELECT MAX(blocks * blocks_size) AS per_device_size FROM mounts %s GROUP BY device)) AS gigs_all_disk_space FROM mounts WHERE path = '/' LIMIT 1;`, linuxGigsAllDiskSpaceSubQueryConditions), Platforms: fleet.HostLinuxOSs, DirectIngestFunc: directIngestDiskSpace,