Skip to content

Commit

Permalink
mkdirall: explicitly return an error for suid/sgid bits
Browse files Browse the repository at this point in the history
These bits are ignored by mkdirat(2) on every POSIX system (Linux does
honour the sticky bit, though it is an outlier). We could ignore them
but this seems less than ideal (a user could be under the impression
their code works when actually the bit is not getting set) so returning
an informative error is preferable.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
  • Loading branch information
cyphar committed Sep 13, 2024
1 parent 43b1026 commit 350d697
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 6 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased] ##

### Changed ###
- Passing the `S_ISUID` or `S_ISGID` modes to `MkdirAllInRoot` will now return
an explicit error saying that those bits are ignored by `mkdirat(2)`. In the
past a different error was returned, but since the silent ignoring behaviour
is codified in the man pages a more explicit error seems apt. While silently
ignoring these bits would be the most compatible option, it could lead to
users thinking their code sets these bits when it doesn't. Programs that need
to deal with compatibility can mask the bits themselves. (#23, #25)

## [0.3.1] - 2024-07-23 ##

### Changed ###
Expand Down
7 changes: 7 additions & 0 deletions mkdir_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ func MkdirAllHandle(root *os.File, unsafePath string, mode int) (_ *os.File, Err
if mode&^0o7777 != 0 {
return nil, fmt.Errorf("%w for mkdir 0o%.3o", errInvalidMode, mode)
}
// On Linux, mkdirat(2) (and os.Mkdir) silently ignore the suid and sgid
// bits. We could also silently ignore them but since we have very few
// users it seems more prudent to return an error so users notice that
// these bits will not be set.
if mode&^0o1777 != 0 {
return nil, fmt.Errorf("%w for mkdir 0o%.3o: suid and sgid are ignored by mkdir", errInvalidMode, mode)
}

// Try to open as much of the path as possible.
currentDir, remainingPath, err := partialLookupInRoot(root, unsafePath)
Expand Down
11 changes: 5 additions & 6 deletions mkdir_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,12 +204,11 @@ func testMkdirAll_InvalidMode(t *testing.T, mkdirAll func(t *testing.T, root, un
{unix.S_IFDIR | 0o777, errInvalidMode},
{unix.S_IFREG | 0o777, errInvalidMode},
{unix.S_IFIFO | 0o777, errInvalidMode},
// suid/sgid bits are valid but you get an error because they don't get
// applied by mkdirat.
// TODO: Figure out if we want to allow this.
{unix.S_ISUID | 0o777, errPossibleAttack},
{unix.S_ISGID | 0o777, errPossibleAttack},
{unix.S_ISUID | unix.S_ISGID | unix.S_ISVTX | 0o777, errPossibleAttack},
// suid/sgid bits are silently ignored by mkdirat and so we return an
// error explicitly.
{unix.S_ISUID | 0o777, errInvalidMode},
{unix.S_ISGID | 0o777, errInvalidMode},
{unix.S_ISUID | unix.S_ISGID | unix.S_ISVTX | 0o777, errInvalidMode},
// Proper sticky bit should work.
{unix.S_ISVTX | 0o777, nil},
// Regular mode bits.
Expand Down

0 comments on commit 350d697

Please sign in to comment.