Skip to content

Commit b22cc03

Browse files
committed
fusefrontend: -allow_other: set file mode *after* chown in Create()
Reported by @slackner at #327 : Possible race-conditions between file creation and Fchownat * Assume a system contains a gocryptfs mount as root user with -allow_other * As a regular user create a new file with mode containing the SUID flag and write access for other users * Before gocryptfs executes the Fchownat call, try to open the file again, write some exploit code to it, and try to run it. For a short time, the file is owned by root and has the SUID flag, so this is pretty dangerous.
1 parent 4170ef0 commit b22cc03

File tree

1 file changed

+20
-2
lines changed
  • internal/fusefrontend

1 file changed

+20
-2
lines changed

internal/fusefrontend/fs.go

+20-2
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,14 @@ func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Conte
239239
return nil, fuse.ToStatus(err)
240240
}
241241
defer syscall.Close(dirfd)
242+
// Don't set full mode before we have set the correct owner. Files with SUID/SGID
243+
// mode belonging to the wrong owner would be a security risk. Even for other
244+
// modes, we don't want anyone else to open the file in the meantime: the fd would
245+
// stay open and could later be used to read the file.
246+
origMode := mode
247+
if fs.args.PreserveOwner {
248+
mode = 0000
249+
}
242250
fd := -1
243251
// Handle long file name
244252
if !fs.args.PlaintextNames && nametransform.IsLongContent(cName) {
@@ -253,7 +261,6 @@ func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Conte
253261
nametransform.DeleteLongNameAt(dirfd, cName)
254262
return nil, fuse.ToStatus(err)
255263
}
256-
257264
} else {
258265
// Create content, normal (short) file name
259266
fd, err = syscallcompat.Openat(dirfd, cName, newFlags|syscall.O_CREAT|syscall.O_EXCL, mode)
@@ -271,7 +278,18 @@ func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Conte
271278
if fs.args.PreserveOwner {
272279
err = syscall.Fchown(fd, int(context.Owner.Uid), int(context.Owner.Gid))
273280
if err != nil {
274-
tlog.Warn.Printf("Create: Fchown() failed: %v", err)
281+
tlog.Warn.Printf("Create %q: Fchown %d:%d failed: %v", cName, context.Owner.Uid, context.Owner.Gid, err)
282+
// In case of a failure, we don't want to proceed setting more
283+
// permissive modes.
284+
syscall.Close(fd)
285+
return nil, fuse.ToStatus(err)
286+
}
287+
}
288+
// Set mode
289+
if mode != origMode {
290+
err = syscall.Fchmod(fd, origMode)
291+
if err != nil {
292+
tlog.Warn.Printf("Create %q: Fchmod %#o -> %#o failed: %v", cName, mode, origMode, err)
275293
}
276294
}
277295
f := os.NewFile(uintptr(fd), cName)

0 commit comments

Comments
 (0)