check / check (push) Waiting to run
main's tree, with next merged on 26 October, as one commit onto prod, on sneak's order. Model: opus-5-5 Co-authored-by: clawbot <clawbot@noreply.example.org>
66 lines
2.0 KiB
Go
66 lines
2.0 KiB
Go
//go:build linux
|
|
|
|
package reportbuf
|
|
|
|
import (
|
|
"io/fs"
|
|
"log/slog"
|
|
"os"
|
|
"syscall"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
// chownFile gives name, a file inside root that is not a directory, to
|
|
// uid and gid if it is a regular file or symbolic link with one name.
|
|
// It leaves, and logs, a file of any kind with a second name (hard
|
|
// link): all the names of a file share its owner, and the other could
|
|
// be outside root. It leaves any other file with one name, such as a
|
|
// device, named pipe or socket: the server needs to own none of them.
|
|
// It opens name through root with O_PATH, which reads nothing from the
|
|
// file, so opening a device or named pipe neither waits nor acts on
|
|
// it; os.Root adds O_NOFOLLOW, and the two together open a symbolic
|
|
// link itself, never what it points to. It reads the kind of file and
|
|
// its number of names from the open file and gives that file to them,
|
|
// so a hard link swapped in at name is caught too.
|
|
//
|
|
// This file is built only on Linux: prepare-data-dir runs only in the
|
|
// Linux image, and macOS, where the backend is also built for
|
|
// development, has neither O_PATH nor AT_EMPTY_PATH. On any other
|
|
// system chownFile returns an error (see datadir_other.go).
|
|
func chownFile(root *os.Root, name string, uid, gid int) error {
|
|
file, err := root.OpenFile(name, unix.O_PATH, 0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer func() { _ = file.Close() }()
|
|
|
|
info, err := file.Stat()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
stat, ok := info.Sys().(*syscall.Stat_t)
|
|
if !ok || stat.Nlink > 1 {
|
|
slog.Warn("owner not changed: file has a second name (hard link)",
|
|
"path", file.Name())
|
|
|
|
return nil
|
|
}
|
|
|
|
if !info.Mode().IsRegular() && info.Mode().Type() != fs.ModeSymlink {
|
|
return nil
|
|
}
|
|
|
|
// File.Chown would fail: fchown refuses a file opened with O_PATH.
|
|
// Fchownat with an empty name and AT_EMPTY_PATH acts on the open
|
|
// file instead.
|
|
err = unix.Fchownat(int(file.Fd()), "", uid, gid, unix.AT_EMPTY_PATH)
|
|
if err != nil {
|
|
return &fs.PathError{Op: "chown", Path: file.Name(), Err: err}
|
|
}
|
|
|
|
return nil
|
|
}
|