Confine cleanup and use held session locks
This commit is contained in:
@@ -183,6 +183,39 @@ func syncOpenedDirectory(parent *os.Root) error {
|
||||
return syncDirectoryFile(directory, parent.Name())
|
||||
}
|
||||
|
||||
// OpenFileConfined opens a file after verifying its parent hierarchy without
|
||||
// following symbolic links. Existing symbolic-link leaves are rejected.
|
||||
func OpenFileConfined(path string, flags int, mode os.FileMode) (*os.File, error) {
|
||||
parent, name, err := openConfinedParent(path, false, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() { _ = parent.Close() }()
|
||||
if info, err := parent.Lstat(name); err == nil && info.Mode()&os.ModeSymlink != 0 {
|
||||
return nil, fmt.Errorf("destination file %q is a symbolic link", name)
|
||||
} else if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
return nil, fmt.Errorf("inspect destination file %q: %w", name, err)
|
||||
}
|
||||
file, err := parent.OpenFile(name, flags, mode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opened, err := file.Stat()
|
||||
if err != nil {
|
||||
_ = file.Close()
|
||||
return nil, fmt.Errorf("inspect opened destination file %q: %w", name, err)
|
||||
}
|
||||
current, err := parent.Lstat(name)
|
||||
if err != nil || current.Mode()&os.ModeSymlink != 0 || !os.SameFile(opened, current) {
|
||||
_ = file.Close()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reinspect destination file %q: %w", name, err)
|
||||
}
|
||||
return nil, fmt.Errorf("destination file %q changed while being opened", name)
|
||||
}
|
||||
return file, nil
|
||||
}
|
||||
|
||||
// DownloadedTempFile is a completed, destination-confined temporary file. It
|
||||
// keeps its parent directory open until the caller installs or cleans it up.
|
||||
type DownloadedTempFile struct {
|
||||
|
||||
Reference in New Issue
Block a user