From 7ff4c85be58defab86d8ad8b7efd5ae8fb72d783 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Tue, 22 Jul 2025 16:23:28 +1000 Subject: [PATCH] internal/sys: add VerifyInode helper This will be used for a few security patches in later patches in this patchset. The need to verify what kind of inode we are operating on in a race-free way turns out to be quite a common pattern... Signed-off-by: Aleksa Sarai --- internal/sys/doc.go | 5 +++++ internal/sys/verify_inode_unix.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 internal/sys/doc.go create mode 100644 internal/sys/verify_inode_unix.go diff --git a/internal/sys/doc.go b/internal/sys/doc.go new file mode 100644 index 000000000..075387f7a --- /dev/null +++ b/internal/sys/doc.go @@ -0,0 +1,5 @@ +// Package sys is an internal package that contains helper methods for dealing +// with Linux that are more complicated than basic wrappers. Basic wrappers +// usually belong in internal/linux. If you feel something belongs in +// libcontainer/utils or libcontainer/system, it probably belongs here instead. +package sys diff --git a/internal/sys/verify_inode_unix.go b/internal/sys/verify_inode_unix.go new file mode 100644 index 000000000..d5019db57 --- /dev/null +++ b/internal/sys/verify_inode_unix.go @@ -0,0 +1,30 @@ +package sys + +import ( + "fmt" + "os" + "runtime" + + "golang.org/x/sys/unix" +) + +// VerifyInodeFunc is the callback passed to [VerifyInode] to check if the +// inode is the expected type (and on the correct filesystem type, in the case +// of filesystem-specific inodes). +type VerifyInodeFunc func(stat *unix.Stat_t, statfs *unix.Statfs_t) error + +// VerifyInode verifies that the underlying inode for the given file matches an +// expected inode type (possibly on a particular kind of filesystem). This is +// mainly a wrapper around [VerifyInodeFunc]. +func VerifyInode(file *os.File, checkFunc VerifyInodeFunc) error { + var stat unix.Stat_t + if err := unix.Fstat(int(file.Fd()), &stat); err != nil { + return fmt.Errorf("fstat %q: %w", file.Name(), err) + } + var statfs unix.Statfs_t + if err := unix.Fstatfs(int(file.Fd()), &statfs); err != nil { + return fmt.Errorf("fstatfs %q: %w", file.Name(), err) + } + runtime.KeepAlive(file) + return checkFunc(&stat, &statfs) +}