Skip to content

Commit

Permalink
stat,seccomp: fix 32-bit overflow on stat quantities
Browse files Browse the repository at this point in the history
On most i686 distributions, glibc implements stat() for programs compiled
without -D_FILE_OFFSET_BITS=64 by calling the corresponding stat64 system
call, and if any of the 64-bit quantities in the statbuf are larger than
2^32-1, the glibc wrapper pretends the file does not exist by returning
ENOENT.

This flag mitigates the issue by pulling the rug under glibc and rewriting
the quantities to stay within bounds. For timestamps, a fixed date within
range is used. For inode numbers, the value is rewritten in a way that
keeps the (device, inode) pair unique.
  • Loading branch information
Snaipe committed Nov 12, 2024
1 parent 01f207f commit 93bc506
Show file tree
Hide file tree
Showing 7 changed files with 326 additions and 1 deletion.
6 changes: 6 additions & 0 deletions arch/x86/gen-syscall.bash
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ declare -A x86_64_syscalls=(
declare -A i386_syscalls=(
["mknod"]="14"
["mknodat"]="297"

["stat64"]="195"
["lstat64"]="196"
["fstat64"]="197"
["fstatat64"]="300"
["statx"]="383"
)

prelude=(
Expand Down
10 changes: 10 additions & 0 deletions arch/x86/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,18 @@ const struct sock_filter syscall_filter[] = {
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_USER_NOTIF),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 196, 0, 1),
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_USER_NOTIF),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 195, 0, 1),
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_USER_NOTIF),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 197, 0, 1),
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_USER_NOTIF),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 14, 0, 1),
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_USER_NOTIF),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 383, 0, 1),
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_USER_NOTIF),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 300, 0, 1),
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_USER_NOTIF),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 297, 0, 1),
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_USER_NOTIF),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
Expand Down
7 changes: 6 additions & 1 deletion arch/x86/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@ extern const size_t syscall_filter_length;

#define BST_NR_mknod 133
#define BST_NR_mknodat 259
#define BST_NR_lstat64_32 196
#define BST_NR_stat64_32 195
#define BST_NR_fstat64_32 197
#define BST_NR_mknod_32 14
#define BST_NR_statx_32 383
#define BST_NR_fstatat64_32 300
#define BST_NR_mknodat_32 297

#define BST_SECCOMP_32 1

#define BST_NR_MAX 259
#define BST_NR_MAX32 297
#define BST_NR_MAX32 383

/* THIS FILE WAS GENERATED BY arch/x86/gen-syscall.bash -- DO NOT EDIT */
14 changes: 14 additions & 0 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "util.h"
#include "path.h"
#include "util.h"
#include "sec.h"

enum {
OPTION_VERSION = 128,
Expand Down Expand Up @@ -63,6 +64,10 @@ enum {
OPTION_CLOSE_FD,
OPTION_CGROUP_DRIVER,

/* Opt-in feature flags */
OPTION_FIX_STAT_32BIT_OVERFLOW,

/* Opt-out feature flags */
OPTION_NO_FAKE_DEVTMPFS,
OPTION_NO_DERANDOMIZE,
OPTION_NO_PROC_REMOUNT,
Expand Down Expand Up @@ -316,6 +321,9 @@ int main(int argc, char *argv[], char *envp[])
{ "close-fd", optional_argument, NULL, OPTION_CLOSE_FD },
{ "cgroup-driver", required_argument, NULL, OPTION_CGROUP_DRIVER },

/* Opt-in feature flags */
{ "fix-stat-32bit-overflow", no_argument, NULL, OPTION_FIX_STAT_32BIT_OVERFLOW },

/* Opt-out feature flags */
{ "no-copy-hard-rlimits", no_argument, NULL, OPTION_NO_COPY_HARD_RLIMITS },
{ "no-fake-devtmpfs", no_argument, NULL, OPTION_NO_FAKE_DEVTMPFS },
Expand Down Expand Up @@ -781,6 +789,12 @@ int main(int argc, char *argv[], char *envp[])
break;
}

case OPTION_FIX_STAT_32BIT_OVERFLOW:
{
sec_seccomp_fix_stat_32bit = 1;
break;
}

case 'r':
opts.root = optarg;
break;
Expand Down
17 changes: 17 additions & 0 deletions man/bst.1.scd
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,23 @@ spacetime process.
be useful to pass out-of-band data to the setup program without leaking
file descriptors to the spacetime process.

\--fix-stat-32bit-overflow
Hijack calls to the stat64 family of system calls and return quantities
within 32-bit boundaries.

On most i686 distributions, glibc implements stat() for programs compiled
without -D_FILE_OFFSET_BITS=64 by calling the corresponding stat64 system
call, and if any of the 64-bit quantities in the statbuf are larger than
2^32-1, the glibc wrapper pretends the file does not exist by returning
ENOENT.

This flag mitigates the issue by pulling the rug under glibc and rewriting
the quantities to stay within bounds. For timestamps, a fixed date within
range is used. For inode numbers, the value is rewritten in a way that
keeps the (device, inode) pair unique.

This flag has no effect on programs running with a 64-bit personality.

\--no-copy-hard-rlimits
Do not copy hard limit values to soft limits for all resources mentioned above.

Expand Down
Loading

0 comments on commit 93bc506

Please sign in to comment.