-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
runtime: enforce standard file descriptors open on init on unix
On Unix-like platforms, enforce that the standard file descriptions (0, 1, 2) are always open during initialization. If any of the FDs are closed, we open them pointing at /dev/null, or fail. Fixes #60641 Change-Id: Iaab6b3f3e5ca44006ae3ba3544d47da9a613f58f Reviewed-on: https://go-review.googlesource.com/c/go/+/509020 Reviewed-by: Michael Pratt <[email protected]> Run-TryBot: Roland Shoemaker <[email protected]> Auto-Submit: Roland Shoemaker <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
- Loading branch information
1 parent
862fa6d
commit d4dd1de
Showing
6 changed files
with
165 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// Copyright 2023 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
//go:build !unix | ||
|
||
package runtime | ||
|
||
func checkfds() { | ||
// Nothing to do on non-Unix platforms. | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
// Copyright 2023 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
//go:build unix | ||
|
||
package runtime_test | ||
|
||
import ( | ||
"internal/testenv" | ||
"os" | ||
"strings" | ||
"testing" | ||
) | ||
|
||
func TestCheckFDs(t *testing.T) { | ||
if *flagQuick { | ||
t.Skip("-quick") | ||
} | ||
|
||
testenv.MustHaveGoBuild(t) | ||
|
||
fdsBin, err := buildTestProg(t, "testfds") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
i, err := os.CreateTemp(t.TempDir(), "fds-input") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if _, err := i.Write([]byte("stdin")); err != nil { | ||
t.Fatal(err) | ||
} | ||
if err := i.Close(); err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
o, err := os.CreateTemp(t.TempDir(), "fds-output") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
outputPath := o.Name() | ||
if err := o.Close(); err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
env := []string{"TEST_OUTPUT=" + outputPath} | ||
for _, e := range os.Environ() { | ||
if strings.HasPrefix(e, "GODEBUG=") || strings.HasPrefix(e, "GOTRACEBACK=") { | ||
continue | ||
} | ||
env = append(env, e) | ||
} | ||
|
||
proc, err := os.StartProcess(fdsBin, []string{fdsBin}, &os.ProcAttr{ | ||
Env: env, | ||
Files: []*os.File{}, | ||
}) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
ps, err := proc.Wait() | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if ps.ExitCode() != 0 { | ||
t.Fatalf("testfds failed: %d", ps.ExitCode()) | ||
} | ||
|
||
fc, err := os.ReadFile(outputPath) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if string(fc) != "" { | ||
t.Errorf("unexpected file content, got: %q", string(fc)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// Copyright 2023 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
//go:build unix | ||
|
||
package runtime | ||
|
||
func checkfds() { | ||
if islibrary || isarchive { | ||
// If the program is actually a library, presumably being consumed by | ||
// another program, we don't want to mess around with the file | ||
// descriptors. | ||
return | ||
} | ||
|
||
const ( | ||
// F_GETFD, EBADF, O_RDWR are standard across all unixes we support, so | ||
// we define them here rather than in each of the OS specific files. | ||
F_GETFD = 0x01 | ||
EBADF = 0x09 | ||
O_RDWR = 0x02 | ||
) | ||
|
||
devNull := []byte("/dev/null\x00") | ||
for i := 0; i < 3; i++ { | ||
ret, errno := fcntl(int32(i), F_GETFD, 0) | ||
if ret >= 0 { | ||
continue | ||
} | ||
if errno != EBADF { | ||
print("runtime: unexpected error while checking standard file descriptor ", i, ", errno=", errno, "\n") | ||
throw("cannot open standard fds") | ||
} | ||
|
||
if ret := open(&devNull[0], O_RDWR, 0); ret < 0 { | ||
print("runtime: standard file descriptor ", i, " closed, unable to open /dev/null, errno=", errno, "\n") | ||
throw("cannot open standard fds") | ||
} else if ret != int32(i) { | ||
print("runtime: opened unexpected file descriptor ", ret, " when attempting to open ", i, "\n") | ||
throw("cannot open standard fds") | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -741,6 +741,7 @@ func schedinit() { | |
goargs() | ||
goenvs() | ||
secure() | ||
checkfds() | ||
parsedebugvars() | ||
gcinit() | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Copyright 2023 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package main | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"log" | ||
"os" | ||
) | ||
|
||
func main() { | ||
f, err := os.OpenFile(os.Getenv("TEST_OUTPUT"), os.O_CREATE|os.O_RDWR, 0600) | ||
if err != nil { | ||
log.Fatalf("os.Open failed: %s", err) | ||
} | ||
defer f.Close() | ||
b, err := io.ReadAll(os.Stdin) | ||
if err != nil { | ||
log.Fatalf("io.ReadAll(os.Stdin) failed: %s", err) | ||
} | ||
if len(b) != 0 { | ||
log.Fatalf("io.ReadAll(os.Stdin) returned non-nil: %x", b) | ||
} | ||
fmt.Fprintf(os.Stdout, "stdout\n") | ||
fmt.Fprintf(os.Stderr, "stderr\n") | ||
} |