merge: integrate proxyctl ticket 07
# Conflicts: # cmd/proxyctl/main.go # internal/securefs/securefs.go
This commit is contained in:
@@ -18,6 +18,22 @@ import (
|
||||
|
||||
type Owner struct{ UID, GID int }
|
||||
|
||||
// ExistingTrustedRoot returns the nearest existing ancestor without resolving
|
||||
// symlinks. Descriptor traversal will subsequently reject a symlink ancestor.
|
||||
func ExistingTrustedRoot(path string) string {
|
||||
candidate := filepath.Dir(filepath.Clean(path))
|
||||
for {
|
||||
if _, err := os.Lstat(candidate); err == nil || !errors.Is(err, fs.ErrNotExist) {
|
||||
return candidate
|
||||
}
|
||||
parent := filepath.Dir(candidate)
|
||||
if parent == candidate {
|
||||
return candidate
|
||||
}
|
||||
candidate = parent
|
||||
}
|
||||
}
|
||||
|
||||
func OpenNoFollow(path string, flags int, mode uint32) (*os.File, error) {
|
||||
fd, err := unix.Open(path, flags|unix.O_CLOEXEC|unix.O_NOFOLLOW, mode)
|
||||
if err != nil {
|
||||
@@ -55,6 +71,45 @@ type Store struct {
|
||||
Owner *Owner
|
||||
}
|
||||
|
||||
// OpenRegular opens a regular file through a descriptor-anchored parent path.
|
||||
// Parent components and the final file are never followed through symlinks.
|
||||
func (s Store) OpenRegular(path string, flags int, mode os.FileMode) (*os.File, error) {
|
||||
directory, base, err := s.openParent(path, flags&unix.O_CREAT != 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := directory.Chmod(0o700); err != nil {
|
||||
_ = directory.Close()
|
||||
return nil, err
|
||||
}
|
||||
if s.Owner != nil && (s.Owner.UID != os.Geteuid() || s.Owner.GID != os.Getegid()) {
|
||||
if err := directory.Chown(s.Owner.UID, s.Owner.GID); err != nil {
|
||||
_ = directory.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
file, err := OpenAt(directory, base, flags, uint32(mode.Perm()))
|
||||
_ = directory.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := regular(file); err != nil {
|
||||
_ = file.Close()
|
||||
return nil, err
|
||||
}
|
||||
if err := file.Chmod(mode.Perm()); err != nil {
|
||||
_ = file.Close()
|
||||
return nil, err
|
||||
}
|
||||
if s.Owner != nil && (s.Owner.UID != os.Geteuid() || s.Owner.GID != os.Getegid()) {
|
||||
if err := file.Chown(s.Owner.UID, s.Owner.GID); err != nil {
|
||||
_ = file.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return file, nil
|
||||
}
|
||||
|
||||
type fileLock struct{ file *os.File }
|
||||
|
||||
func (l *fileLock) Close() error {
|
||||
@@ -66,32 +121,12 @@ func (l *fileLock) Close() error {
|
||||
return closeErr
|
||||
}
|
||||
|
||||
// LockFile acquires an exclusive advisory lock without following symbolic
|
||||
// links. The returned closer releases the lock and closes its descriptor.
|
||||
// LockFile acquires an exclusive advisory lock without following symlinks.
|
||||
func (s Store) LockFile(path string) (io.Closer, error) {
|
||||
directory, base, err := s.openParent(path, true)
|
||||
file, err := s.OpenRegular(path, unix.O_CREAT|unix.O_RDWR, 0o600)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer directory.Close()
|
||||
file, err := OpenAt(directory, base, unix.O_CREAT|unix.O_RDWR, 0o600)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := regular(file); err != nil {
|
||||
_ = file.Close()
|
||||
return nil, err
|
||||
}
|
||||
if s.Owner != nil && (s.Owner.UID != os.Geteuid() || s.Owner.GID != os.Getegid()) {
|
||||
if err := file.Chown(s.Owner.UID, s.Owner.GID); err != nil {
|
||||
_ = file.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err := file.Chmod(0o600); err != nil {
|
||||
_ = file.Close()
|
||||
return nil, err
|
||||
}
|
||||
if err := unix.Flock(int(file.Fd()), unix.LOCK_EX); err != nil {
|
||||
_ = file.Close()
|
||||
return nil, err
|
||||
|
||||
Reference in New Issue
Block a user