VYPR
Medium severity6.7NVD Advisory· Published May 27, 2026

CVE-2026-48065

CVE-2026-48065

Description

pam_usb provides hardware authentication for Linux using ordinary removable media. Prior to 0.9.1, src/conf.c allocates heap memory proportional to n_devices, a count derived from libxml2 XPath evaluation of the config file, without first enforcing an upper bound. On 32-bit targets (armv7l, i686 -- both listed in the project Makefile), the multiplication n_devices * sizeof(t_pusb_device) wraps around size_t, causing xmalloc() to receive a very small size. Because xmalloc() only calls abort() on NULL return, a small-but-non-NULL allocation is accepted, and subsequent array writes overflow the heap. This vulnerability is fixed in 0.9.1.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Integer overflow in pam_usb before 0.9.1 allows heap buffer overflow on 32-bit systems via unconstrained device count in config file.

Vulnerability

In pam_usb versions prior to 0.9.1, the function src/conf.c allocates heap memory proportional to n_devices, a count derived from libxml2 XPath evaluation of the configuration file without enforcing an upper bound [1][2]. On 32-bit targets (armv7l, i686), the multiplication n_devices * sizeof(t_pusb_device) (where sizeof(t_pusb_device) is 640 bytes) can overflow size_t, causing xmalloc() to receive a very small size. Because xmalloc() only calls abort() on NULL return, a small-but-non-NULL allocation is accepted, and subsequent array writes overflow the heap [1][2]. The affected code paths are at lines 222, 231, 245, and 300 of src/conf.c [1].

Exploitation

An attacker must have write access to /etc/security/pam_usb.conf (root-owned, mode 644 by default) to inject a crafted configuration containing a large number of device entries (approximately 6.7 million) [1][2]. On a 32-bit host, when pam_usb loads this configuration during authentication, the integer overflow triggers a heap buffer overflow [1][2]. This requires either root privileges or a secondary vulnerability that grants config file write access, such as a supply-chain compromise [2].

Impact

Successful exploitation results in heap corruption, which can lead to arbitrary code execution or privilege escalation within the PAM authentication context [1][2]. The CVSS v3 score is 6.7 (Medium) on 32-bit systems; 64-bit systems are not affected because the required device count would exhaust memory before overflow occurs [1][2].

Mitigation

The vulnerability is fixed in pam_usb version 0.9.1, released on 2026-05-27 [1][2]. The fix adds a PUSB_MAX_DEVICES constant to src/conf.h and enforces it before any allocation [1][2]. Users should upgrade to 0.9.1 or later. No workaround is available for unpatched versions. The CVE is not listed on CISA's Known Exploited Vulnerabilities (KEV) catalog.

AI Insight generated on May 27, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Patches

1
b2dde8c03f3e

[Security] Guard n_devices against size_t overflow before heap allocation in conf.c (#359)

https://github.com/mcdope/pam_usbMcDopeMay 19, 2026Fixed in 0.9.1via llm-release-walk
2 files changed · +47 0
  • src/conf.c+8 0 modified
    @@ -18,6 +18,7 @@
     #include <sys/utsname.h>
     #include <string.h>
     #include <errno.h>
    +#include <stdint.h>
     #include "mem.h"
     #include "conf.h"
     #include "xpath.h"
    @@ -227,6 +228,13 @@ int pusb_conf_parse(
     		xmlCleanupParser();
     		return 0;
     	}
    +	if (n_devices < 0 || (size_t)n_devices > SIZE_MAX / sizeof(t_pusb_device))
    +	{
    +		log_error("Device count for user \"%s\" would overflow allocation.\n", user);
    +		xmlFreeDoc(doc);
    +		xmlCleanupParser();
    +		return 0;
    +	}
     
     	char **device_list = xmalloc(n_devices * sizeof(char *));
     	if (!device_list)
    
  • tests/unit/c/conf_test.c+39 0 modified
    @@ -280,6 +280,44 @@ static void test_conf_parses_more_than_ten_devices(void **state)
     	pusb_conf_free(&opts);
     }
     
    +/* ── overflow guard ── */
    +
    +static void test_parse_many_devices_no_false_positive(void **state)
    +{
    +	(void)state;
    +	/*
    +	 * Positive regression for the SIZE_MAX / sizeof(t_pusb_device) guard added
    +	 * in conf.c. 200 devices is well within the safe range on any target, so
    +	 * pusb_conf_parse must succeed. The actual overflow boundary cannot be
    +	 * exercised portably in a unit test (it requires SIZE_MAX / 640 entries,
    +	 * which is impractical on any real target); correctness is verified by
    +	 * code inspection.
    +	 */
    +	const int N = 200;
    +	char tmpfile[] = "/tmp/pamusb_test_many_XXXXXX";
    +	int fd = mkstemp(tmpfile);
    +	assert_true(fd >= 0);
    +	FILE *f = fdopen(fd, "w");
    +	assert_non_null(f);
    +
    +	fprintf(f, "<?xml version=\"1.0\"?><configuration><devices>\n"); /* DevSkim: ignore DS154189 */
    +	for (int i = 0; i < N; i++)
    +		fprintf(f, "<device id=\"dev%d\"><vendor>V</vendor><model>M</model>" /* DevSkim: ignore DS154189 */
    +		           "<serial>S%03d</serial><volume_uuid>U%d</volume_uuid></device>\n", i, i, i);
    +	fprintf(f, "</devices><users><user id=\"testuser\">\n"); /* DevSkim: ignore DS154189 */
    +	for (int i = 0; i < N; i++)
    +		fprintf(f, "<device>dev%d</device>\n", i); /* DevSkim: ignore DS154189 */
    +	fprintf(f, "</user></users><services/></configuration>\n"); /* DevSkim: ignore DS154189 */
    +	fclose(f);
    +
    +	t_pusb_options opts;
    +	pusb_conf_init(&opts);
    +	assert_int_equal(1, pusb_conf_parse(tmpfile, &opts, "testuser", "login"));
    +	assert_int_equal(N, opts.device_count);
    +	pusb_conf_free(&opts);
    +	unlink(tmpfile);
    +}
    +
     /* ── main ── */
     
     int main(void)
    @@ -305,6 +343,7 @@ int main(void)
     		cmocka_unit_test(test_parse_user_not_in_conf),
     		cmocka_unit_test(test_superuser_attribute_case_sensitive),
     		cmocka_unit_test(test_conf_parses_more_than_ten_devices),
    +		cmocka_unit_test(test_parse_many_devices_no_false_positive),
     	};
     	return cmocka_run_group_tests(tests, NULL, NULL);
     }
    

Vulnerability mechanics

Root cause

"Missing upper-bound check on n_devices before integer multiplication in heap allocation leads to integer overflow on 32-bit targets."

Attack vector

An attacker must have write access to /etc/security/pam_usb.conf (root-owned, mode 644 by default) [ref_id=2]. By crafting a config file with approximately 6.7 million device entries (n_devices ≈ 6,710,887), the multiplication n_devices * sizeof(t_pusb_device) wraps around size_t on 32-bit targets (armv7l, i686) [ref_id=1]. xmalloc() receives a small size (e.g., 384 bytes) but returns a non-NULL pointer, and subsequent array writes for 6.7M device structs overflow the heap [ref_id=1][ref_id=2]. On 64-bit targets the multiplication would require more than 2^23 entries, exhausting memory before overflow, so this is a 32-bit-only exploitable path [ref_id=1][ref_id=2].

Affected code

src/conf.c lines 222, 231, 245, and 300 [ref_id=1][ref_id=2]. Line 222 calls pusb_xpath_count_nodes() without an upper-bound check. Lines 231, 245, and 300 perform unchecked multiplications n_devices * sizeof(char *) or n_devices * sizeof(t_pusb_device) in xmalloc() calls [ref_id=1].

What the fix does

The fix adds a PUSB_MAX_DEVICES constant (set to 64) in src/conf.h and enforces it in src/conf.c before any allocation [ref_id=1][ref_id=2]. After counting nodes via pusb_xpath_count_nodes(), the code checks if n_devices is out of range (≤ 0 or > PUSB_MAX_DEVICES) and returns early with an error log [ref_id=1]. This bounds check prevents the integer multiplication from ever receiving a value large enough to wrap size_t on 32-bit targets. The same guard is applied before the su_names allocation at line 300 [ref_id=1]. No changes are needed at lines 231 and 245 because the n_devices ≤ PUSB_MAX_DEVICES check makes those multiplications safe [ref_id=1].

Preconditions

  • configAttacker must have write access to /etc/security/pam_usb.conf (root-owned, mode 644 by default)
  • configTarget must be a 32-bit architecture (armv7l or i686)
  • inputpam_usb must load the attacker-controlled config file during authentication

Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

3

News mentions

0

No linked articles in our index yet.