In this Section

Security Advisory – BSD lpd Access Control Bypass


Sense of Security – Security Advisory – SOS-17-002

Release Date. 23-Oct-2017
Last Update.
Vendor Notification Date. 20-Sep-2017
Product. lpr
Platform. BSD
Affected versions. OpenBSD until version 6.1 inclusive

FreeBSD version 11.1 and earlier

All downstream packages based on CVS 1.58 or earlier

Severity Rating. Medium
Impact. Exposure of sensitive information

Security bypass

Attack Vector. From local system
Solution Status. Upstream patch
CVE reference. Not yet assigned


On BSD systems the printing daemon (lpd) runs with root privileges and can read any file or object in the system in order to serve its contents to the printer. To prevent users from taking advantage of the daemon’s privileges to print any arbitrary file, the print request submission command (lpr) implements an ad-hoc access control check. When a user invokes lpr to print any given file, lpr checks whether that user can read the requested file by opening it for reading. If that succeeds, lpr then puts the print job in lpd’s queue.

This approach was previously subject to a known race condition vulnerability, in which the attacker proceeded as follows:

1. Temporarily disable the printer (by unplugging it, sending a lengthy print job, etc.);

2. Request the printing of a file through a symbolic link (lpr -s);

3. Replace the file to print with a symbolic link to another file, which the attacker is not allowed to read (e.g. /etc/shadow); and

4. Once the printer becomes available, the unauthorised target file is thus printed.

Current versions seek to prevent this attack by letting lpr store the printed file’s inode number in the print job (CF) file alongside the requested file name, and having lpd ensure that it has not changed before the actual printing starts (i.e. that the name still refers to the same actual file).

However this remains vulnerable. The bug occurs in usr.sbin/lpr/lpd/printjob.c, line 428:

fino = i;

where “fino” is the inode number extracted from the print job’s CF file, with which the actual file’s inode number is compared. As of revision 1.58 available in the OpenBSD CVS, the variable “i” is declared “int” (line 337), so it remains a 32-bit integer even on amd64 systems (among other 64-bit architectures). Consequently the inode number comparison for symlink print jobs is effectively truncated to 32 bits.

On a 64-bit filesystem with dynamic inode allocation, it is thus possible for an attacker to find or create a file whose inode number’s lower 32 bits will match the inode number of another file, in particular a file the attacker is not allowed to access. If the latter file’s inode number is lower than 2^32, the check will pass and the attacker will be able to print the file.

Please refer to the PDF version of this advisory for proof of concept code examples.


Apply patch from OpenBSD CVS revision 1.59 ( or update to OpenBSD release 6.2.

Discovered By

Jacob Zimmermann from Sense of Security Labs.