fix(auth): harden tht auth mutations
This commit is contained in:
@@ -118,6 +118,15 @@ func ReplaceCanonicalRegular(path string, contents []byte, mode os.FileMode) err
|
||||
return replaceCanonicalRegular(path, contents)
|
||||
}
|
||||
|
||||
// RemoveCanonicalPrivateRegular removes one existing private regular file without following a
|
||||
// symlinked path component. It is intended only for rolling back a file this process published.
|
||||
func RemoveCanonicalPrivateRegular(path string) error {
|
||||
if err := ValidatePrivateRegular(path); err != nil {
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
return removeCanonicalPrivateRegular(path)
|
||||
}
|
||||
|
||||
func randomTemporaryName() (string, error) {
|
||||
bytes := make([]byte, 16)
|
||||
if _, err := rand.Read(bytes); err != nil {
|
||||
|
||||
@@ -43,6 +43,24 @@ func replaceCanonicalRegular(path string, contents []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeCanonicalPrivateRegular(path string) error {
|
||||
directory, target, err := openCanonicalParentDirectory(path)
|
||||
if err != nil {
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
defer unix.Close(directory)
|
||||
if err := requirePrivateRegularAt(directory, target); err != nil {
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
if err := unix.Unlinkat(directory, target, 0); err != nil {
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
if err := unix.Fsync(directory); err != nil {
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func openCanonicalParentDirectory(path string) (int, string, error) {
|
||||
components := strings.Split(strings.TrimPrefix(path, string(os.PathSeparator)), string(os.PathSeparator))
|
||||
if len(components) < 2 || components[0] == "" || components[len(components)-1] == "" {
|
||||
@@ -72,6 +90,14 @@ func requireSingleRegularAt(directory int, name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func requirePrivateRegularAt(directory int, name string) error {
|
||||
var stat unix.Stat_t
|
||||
if err := unix.Fstatat(directory, name, &stat, unix.AT_SYMLINK_NOFOLLOW); err != nil || stat.Mode&unix.S_IFMT != unix.S_IFREG || stat.Nlink != 1 || stat.Mode&0o7777 != 0o600 {
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writePrivateTemporaryAt(directory int, contents []byte) (string, error) {
|
||||
for attempt := 0; attempt < 16; attempt++ {
|
||||
name, err := randomTemporaryName()
|
||||
|
||||
@@ -47,6 +47,21 @@ func replaceCanonicalRegular(path string, contents []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeCanonicalPrivateRegular(path string) error {
|
||||
parents, target, err := openCanonicalWindowsParent(path)
|
||||
if err != nil {
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
defer parents.Close()
|
||||
if err := ValidatePrivateRegular(path); err != nil {
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
if err := windows.DeleteFile(windows.StringToUTF16Ptr(filepath.Join(parents.directory, target))); err != nil {
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func safeExistingRegular(path string) bool {
|
||||
return ValidatePrivateRegular(path) == nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user