NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/60602: tmpfs size calculation overflows on 32-bit ports when memory plus swap exceeds 4GB



>Number:         60602
>Category:       kern
>Synopsis:       tmpfs size calculation overflows on 32-bit ports when memory plus swap exceeds 4GB
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Aug 16 06:45:01 +0000 2026
>Originator:     Hashimoto Kenichi
>Release:        NetBSD 10.1
>Organization:
genetec corporation
>Environment:
System: NetBSD 10.1 (GENERIC) i386, 2.9GB RAM, 32GB swap (QEMU/NVMM guest)
>Description:
In tmpfs_bytes_max() (sys/fs/tmpfs/tmpfs_mem.c rev 1.8):

	psize_t freepages = tmpfs_mem_info(false);
	uint64_t avail_mem;
	...
	avail_mem = round_page(mp->tm_bytes_used) + (freepages << PAGE_SHIFT);

The shift is evaluated in the width of psize_t before the addition.
On i386 without PAE, psize_t is unsigned long, i.e. 32 bits.
tmpfs_mem_info() returns a page count covering main memory and swap,
so once it exceeds 2^20 pages the result wraps modulo 2^32.

Two measurements, df(1) and vmstat(1) run from a single command line:

                        07:23:16        14:29:34        delta
  pages free              24,233         193,815     +169,582
  cached file pages      281,540         157,941     -123,599
  swap pages in use      512,841         515,106       +2,265
  (swap pages          8,421,126, wired 2,827, freetarg 5,461: unchanged)
  ------------------------------------------------------------
  sum                  8,205,770       8,249,488      +43,718
  df -k /tmp Size      4,186,968         148,488   -4,038,480

The input grew by 43,718 pages while the reported size fell by 4GB.
tmpfs_bytes_max() is monotonic in freepages, so this requires
truncation.  The delta matches one crossing of a 2^32 boundary to
within the error of reading swpgavail/swpgonly from vmstat.

This mount has no -s option (size_max=18446744073709551615), so MIN()
always selects the overflowed term.  A -sram%25 mount on the same
system was clamped to the same wrong value.

tmpfs_mem_incr() uses the same function, so this is not only a
reporting problem: build.sh failed with

  fatal error: error writing to /tmp//cc5cFXCC.s: No space left on device

while df reported 100M free on an idle /tmp.

An amd64 system running 11.0 reports expected values, consistent with
psize_t being 64 bits there.  PAE kernels should be unaffected
(untested).  rev 1.7 used size_t, also 32 bits on i386, so this is not
specific to the psize_t change.
>How-To-Repeat:
On a 32-bit port with main memory plus swap exceeding 4GB, mount a
tmpfs without -s and observe over time:

  { date +%T; df -k /tmp; \
    vmstat -s | grep -E 'pages free|cached file pages|swap pages'; }

The reported size does not track the page counts monotonically.
512MB RAM with 5GB swap should suffice but is unverified; the data
above is from a system in production use.

>Fix:
Unknown.




Home | Main Index | Thread Index | Old Index