Skip to content

[BUG] Swap size wrong on 32-bit platforms for >4TiB swap (/proc/meminfo fallback path, same root cause as #2563) #2564

Description

@baracudaz

Describe the bug

Same root cause as #2563: on 32-bit platforms where unsigned long is 32 bits (e.g. armv5tel/ILP32), Swap's /proc/meminfo fallback path parses swap size with strtoul, which silently saturates instead of reporting the real value for large swap sizes.

This is currently dormant rather than live-observed — it only triggers past ~4 TiB of swap, and only when the fallback path is actually used (see below) — but it's the identical defect class, found while auditing the codebase after #2563.

Where

src/detection/swap/swap_linux.c, detectByProcMeminfo():

uint64_t swapTotal = 0, swapFree = 0;

char* token = nullptr;
if ((token = strstr(buf, "SwapTotal:")) != nullptr) {
    swapTotal = strtoul(token + strlen("SwapTotal:"), nullptr, 10);
}

if ((token = strstr(buf, "SwapFree:")) != nullptr) {
    swapFree = strtoul(token + strlen("SwapFree:"), nullptr, 10);
}

FFSwapResult* swap = FF_LIST_ADD(FFSwapResult, *result);
ffStrbufInitStatic(&swap->name, "Total");
swap->bytesTotal = swapTotal * 1024lu;
swap->bytesUsed = (swapTotal - swapFree) * 1024lu;

SwapTotal/SwapFree in /proc/meminfo are reported in kB. strtoul returns unsigned long, 32 bits wide on ILP32 platforms — max 4294967295. A swap size in kB that exceeds that (i.e. swap larger than ~4 TiB) overflows and strtoul saturates at ULONG_MAX per C99 7.24.1.4, silently producing a wrong bytesTotal/bytesUsed instead of the real size — exactly the same failure mode as the PhysicalDisk bug in #2563, just parsing /proc/meminfo instead of /sys/block/*/size.

Per the comment above this function (// For Android, // Ref: #620), this path is a fallback used only when /proc/swaps can't be read (e.g. some Android/Termux environments) — ffDetectSwap() tries detectByProcSwaps() (which correctly uses sscanf(..., "%" SCNu64 "%" SCNu64, ...) straight into uint64_t, no overflow risk) first. So on a typical Linux desktop/server this code path never runs. It's still worth fixing for correctness/consistency and because the exact set of environments that hit this fallback (and their swap configurations) isn't something this report can rule out.

Suggested fix

Same fix as #2563 — use a 64-bit-safe parse:

swapTotal = strtoull(token + strlen("SwapTotal:"), nullptr, 10);
...
swapFree = strtoull(token + strlen("SwapFree:"), nullptr, 10);

(src/detection/memory/memory_linux.c's equivalent /proc/meminfo parsing already does this correctly with strtoull — this file is the outlier.)

Related

Found while auditing the codebase for the same overflow class after filing #2563 (PhysicalDisk size wrong on 32-bit hosts for disks >2 TiB). Everything else checked (memory_linux.c, disk_linux.c's statvfs64-based mount sizing, and all other strtoul call sites, which are for PCI IDs/PIDs/CPU part numbers/colors — inherently small values) was confirmed 64-bit-safe.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions