Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0fd1371da |
No files matched your search
@@ -30,11 +30,8 @@ Run `make frontend-viewport-test` in CI as its own step; it is not part of
|
|||||||
link is opened without following it and given to the netwatch user itself, so
|
link is opened without following it and given to the netwatch user itself, so
|
||||||
the server can still follow one in a sticky directory that anyone can write
|
the server can still follow one in a sticky directory that anyone can write
|
||||||
to. Other files that are neither directories, regular files nor symbolic links
|
to. Other files that are neither directories, regular files nor symbolic links
|
||||||
keep their owner. Setting the owner on an open file or link needs Linux, the
|
keep their owner. The test that runs as root hard-links a file from outside
|
||||||
system of the image; on any other system the package still builds, and
|
the volume into it and finds its owner unchanged
|
||||||
`prepare-data-dir` fails at the first regular file or symbolic link. The test
|
|
||||||
that runs as root hard-links a file from outside the volume into it and finds
|
|
||||||
its owner unchanged
|
|
||||||
- 2026-10-18: after an interval change, the summary's Reachable slot reads
|
- 2026-10-18: after an interval change, the summary's Reachable slot reads
|
||||||
`--/--` in white, as at page load, until the second round since the change
|
`--/--` in white, as at page load, until the second round since the change
|
||||||
ends ([#140](https://git.eeqj.de/sneak/netwatch/issues/140)). It used to read
|
ends ([#140](https://git.eeqj.de/sneak/netwatch/issues/140)). It used to read
|
||||||
|
|||||||
@@ -3,11 +3,14 @@ package reportbuf
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrDataDirOutsideVolume is returned by PrepareDataDir for a DATA_DIR
|
// ErrDataDirOutsideVolume is returned by PrepareDataDir for a DATA_DIR
|
||||||
@@ -24,9 +27,7 @@ var ErrDataDirOutsideVolume = errors.New(
|
|||||||
// with a second name (hard link), as that name could be outside volume,
|
// with a second name (hard link), as that name could be outside volume,
|
||||||
// and any other file, such as a device (see chownAll). dir must be
|
// and any other file, such as a device (see chownAll). dir must be
|
||||||
// volume or a path below it, with no '.', '..', empty part or '/' at
|
// volume or a path below it, with no '.', '..', empty part or '/' at
|
||||||
// the end. It gives a regular file or symbolic link to owner only on
|
// the end.
|
||||||
// Linux, the system of the image; on any other it fails at the first
|
|
||||||
// one (see chownFile).
|
|
||||||
//
|
//
|
||||||
// bin/entrypoint.sh runs this as root, which would follow a symbolic
|
// bin/entrypoint.sh runs this as root, which would follow a symbolic
|
||||||
// link anywhere, so every step goes through an os.Root opened on
|
// link anywhere, so every step goes through an os.Root opened on
|
||||||
@@ -154,6 +155,41 @@ func chownDir(root *os.Root, name string, uid, gid int) ([]fs.DirEntry, error) {
|
|||||||
return dir.ReadDir(-1)
|
return dir.ReadDir(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// chownFile gives name, a regular file or symbolic link inside root, to
|
||||||
|
// uid and gid, unless it has a second name (hard link): all the names
|
||||||
|
// of a file share its owner, and the other could be outside root. It
|
||||||
|
// opens name through root with O_PATH, which reads nothing from the
|
||||||
|
// file; os.Root adds O_NOFOLLOW, and the two together open a symbolic
|
||||||
|
// link itself, never what it points to. It reads the number of names
|
||||||
|
// from the open file and gives that file to them, so a hard link
|
||||||
|
// swapped in at name is caught too. It logs a file it leaves.
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
stat, ok := info.Sys().(*syscall.Stat_t)
|
||||||
|
if ok && stat.Nlink == 1 {
|
||||||
|
return unix.Fchownat(int(file.Fd()), "", uid, gid, unix.AT_EMPTY_PATH)
|
||||||
|
}
|
||||||
|
|
||||||
|
slog.Warn("owner not changed: file has a second name (hard link)",
|
||||||
|
"path", file.Name())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// chmodDir gives name, a directory inside root, the mode the server
|
// chmodDir gives name, a directory inside root, the mode the server
|
||||||
// gives a directory it creates. Root.Chmod would not hold: on Linux it
|
// gives a directory it creates. Root.Chmod would not hold: on Linux it
|
||||||
// checks that name is not a symbolic link, then sets the mode by name,
|
// checks that name is not a symbolic link, then sets the mode by name,
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
//go:build linux
|
|
||||||
|
|
||||||
package reportbuf
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log/slog"
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
// chownFile gives name, a regular file or symbolic link inside root, to
|
|
||||||
// uid and gid, unless it has a second name (hard link): all the names
|
|
||||||
// of a file share its owner, and the other could be outside root. It
|
|
||||||
// opens name through root with O_PATH, which reads nothing from the
|
|
||||||
// file; os.Root adds O_NOFOLLOW, and the two together open a symbolic
|
|
||||||
// link itself, never what it points to. It reads the number of names
|
|
||||||
// from the open file and gives that file to them, so a hard link
|
|
||||||
// swapped in at name is caught too. It logs a file it leaves.
|
|
||||||
//
|
|
||||||
// This file is built only on Linux, because O_PATH and AT_EMPTY_PATH
|
|
||||||
// exist only there; prepare-data-dir runs only in the Linux image. 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
stat, ok := info.Sys().(*syscall.Stat_t)
|
|
||||||
if ok && stat.Nlink == 1 {
|
|
||||||
return unix.Fchownat(int(file.Fd()), "", uid, gid, unix.AT_EMPTY_PATH)
|
|
||||||
}
|
|
||||||
|
|
||||||
slog.Warn("owner not changed: file has a second name (hard link)",
|
|
||||||
"path", file.Name())
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
//go:build !linux
|
|
||||||
|
|
||||||
package reportbuf
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"io/fs"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
// chownFile returns an error on every system but Linux. Giving a
|
|
||||||
// regular file or symbolic link to a user on the open file, never by
|
|
||||||
// name, needs O_PATH and AT_EMPTY_PATH, which only Linux has (see
|
|
||||||
// datadir_linux.go), and prepare-data-dir runs only in the Linux
|
|
||||||
// image. This file lets the package build elsewhere, such as on macOS,
|
|
||||||
// where a developer runs make build and make run.
|
|
||||||
func chownFile(_ *os.Root, name string, _, _ int) error {
|
|
||||||
return &fs.PathError{Op: "chown", Path: name, Err: errors.ErrUnsupported}
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user