diff options
| -rw-r--r-- | internal/fusefrontend/fs.go | 34 | ||||
| -rw-r--r-- | internal/syscallcompat/sys_darwin.go | 5 | ||||
| -rw-r--r-- | internal/syscallcompat/sys_linux.go | 23 | 
3 files changed, 34 insertions, 28 deletions
| diff --git a/internal/fusefrontend/fs.go b/internal/fusefrontend/fs.go index 2cd4630..2c6ac5a 100644 --- a/internal/fusefrontend/fs.go +++ b/internal/fusefrontend/fs.go @@ -238,15 +238,11 @@ func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Conte  		return nil, fuse.ToStatus(err)  	}  	defer syscall.Close(dirfd) -	// Don't set full mode before we have set the correct owner. Files with SUID/SGID -	// mode belonging to the wrong owner would be a security risk. Even for other -	// modes, we don't want anyone else to open the file in the meantime: the fd would -	// stay open and could later be used to read the file. -	origMode := mode -	if fs.args.PreserveOwner { -		mode = 0000 -	}  	fd := -1 +	// Make sure context is nil if we don't want to preserve the owner +	if !fs.args.PreserveOwner { +		context = nil +	}  	// Handle long file name  	if !fs.args.PlaintextNames && nametransform.IsLongContent(cName) {  		// Create ".name" @@ -255,14 +251,14 @@ func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Conte  			return nil, fuse.ToStatus(err)  		}  		// Create content -		fd, err = syscallcompat.Openat(dirfd, cName, newFlags|os.O_CREATE|os.O_EXCL, mode) +		fd, err = syscallcompat.OpenatUser(dirfd, cName, newFlags|os.O_CREATE|os.O_EXCL, mode, context)  		if err != nil {  			nametransform.DeleteLongNameAt(dirfd, cName)  			return nil, fuse.ToStatus(err)  		}  	} else {  		// Create content, normal (short) file name -		fd, err = syscallcompat.Openat(dirfd, cName, newFlags|syscall.O_CREAT|syscall.O_EXCL, mode) +		fd, err = syscallcompat.OpenatUser(dirfd, cName, newFlags|syscall.O_CREAT|syscall.O_EXCL, mode, context)  		if err != nil {  			// xfstests generic/488 triggers this  			if err == syscall.EMFILE { @@ -273,24 +269,6 @@ func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Conte  			return nil, fuse.ToStatus(err)  		}  	} -	// Set owner -	if fs.args.PreserveOwner { -		err = syscall.Fchown(fd, int(context.Owner.Uid), int(context.Owner.Gid)) -		if err != nil { -			tlog.Warn.Printf("Create %q: Fchown %d:%d failed: %v", cName, context.Owner.Uid, context.Owner.Gid, err) -			// In case of a failure, we don't want to proceed setting more -			// permissive modes. -			syscall.Close(fd) -			return nil, fuse.ToStatus(err) -		} -	} -	// Set mode -	if mode != origMode { -		err = syscall.Fchmod(fd, origMode) -		if err != nil { -			tlog.Warn.Printf("Create %q: Fchmod %#o -> %#o failed: %v", cName, mode, origMode, err) -		} -	}  	f := os.NewFile(uintptr(fd), cName)  	return NewFile(f, fs)  } diff --git a/internal/syscallcompat/sys_darwin.go b/internal/syscallcompat/sys_darwin.go index 993c229..7defc5f 100644 --- a/internal/syscallcompat/sys_darwin.go +++ b/internal/syscallcompat/sys_darwin.go @@ -46,6 +46,11 @@ func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)  	return emulateOpenat(dirfd, path, flags, mode)  } +func OpenatUser(dirfd int, path string, flags int, mode uint32, context *fuse.Context) (fd int, err error) { +	// FIXME: take into account context.Owner +	return Openat(dirfd, path, flags, mode) +} +  func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {  	return emulateRenameat(olddirfd, oldpath, newdirfd, newpath)  } diff --git a/internal/syscallcompat/sys_linux.go b/internal/syscallcompat/sys_linux.go index 5c180ec..595aa1d 100644 --- a/internal/syscallcompat/sys_linux.go +++ b/internal/syscallcompat/sys_linux.go @@ -3,6 +3,7 @@ package syscallcompat  import (  	"fmt" +	"runtime"  	"sync"  	"syscall" @@ -75,6 +76,28 @@ func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)  	return syscall.Openat(dirfd, path, flags, mode)  } +// OpenatUser runs the Openat syscall in the context of a different user. +func OpenatUser(dirfd int, path string, flags int, mode uint32, context *fuse.Context) (fd int, err error) { +	if context != nil { +		runtime.LockOSThread() +		defer runtime.UnlockOSThread() + +		err = syscall.Setregid(-1, int(context.Owner.Gid)) +		if err != nil { +			return -1, err +		} +		defer syscall.Setregid(-1, 0) + +		err = syscall.Setreuid(-1, int(context.Owner.Uid)) +		if err != nil { +			return -1, err +		} +		defer syscall.Setreuid(-1, 0) +	} + +	return Openat(dirfd, path, flags, mode) +} +  // Renameat wraps the Renameat syscall.  func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {  	return syscall.Renameat(olddirfd, oldpath, newdirfd, newpath) | 
