mirror of
https://github.com/netbirdio/netbird.git
synced 2026-08-04 03:25:19 -04:00
64 lines
1.8 KiB
Go
64 lines
1.8 KiB
Go
package ipcauth
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
)
|
|
|
|
// OpenOwnedFile opens path for reading on behalf of the IPC caller identified by
|
|
// id, and fails unless the opened file is a regular file that id owns.
|
|
//
|
|
// It exists for the paths a local caller hands to the daemon over the IPC. The
|
|
// daemon runs as root, so opening such a path unchecked lets any local user read
|
|
// any file through it. Ownership is the invariant that keeps the daemon from
|
|
// reading, with its own privileges, a file the caller could not read itself: a
|
|
// symlink or hard link planted at the path resolves to a file someone else owns
|
|
// and is refused.
|
|
//
|
|
// The check is made against the open descriptor rather than the path, so
|
|
// swapping the path between the check and the read cannot change the answer.
|
|
//
|
|
// A privileged caller is exempt: it can read the file directly, so refusing it
|
|
// here would protect nothing. The regular-file requirement still applies to
|
|
// everyone, since a fifo or device planted at the path is never a log file.
|
|
func OpenOwnedFile(id Identity, path string) (*os.File, error) {
|
|
f, err := openForRead(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := checkOwnership(id, f); err != nil {
|
|
if cerr := f.Close(); cerr != nil {
|
|
return nil, fmt.Errorf("%w (close: %v)", err, cerr)
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
return f, nil
|
|
}
|
|
|
|
func checkOwnership(id Identity, f *os.File) error {
|
|
info, err := f.Stat()
|
|
if err != nil {
|
|
return fmt.Errorf("stat %s: %w", f.Name(), err)
|
|
}
|
|
|
|
if !info.Mode().IsRegular() {
|
|
return fmt.Errorf("%s is not a regular file", f.Name())
|
|
}
|
|
|
|
if IsPrivilegedCaller(id) {
|
|
return nil
|
|
}
|
|
|
|
owned, err := fileOwnedBy(id, f)
|
|
if err != nil {
|
|
return fmt.Errorf("read owner of %s: %w", f.Name(), err)
|
|
}
|
|
if !owned {
|
|
return fmt.Errorf("%s is not owned by the caller (%s)", f.Name(), id)
|
|
}
|
|
|
|
return nil
|
|
}
|