Skip to content

Commit b3a3066

Browse files
authored
tsh: Add wrapper for syscall.Dup2 for linux/arm64 (#55925)
* tsh: Add wrapper for syscall.Dup2 for linux/arm64 Add a wrapper for `syscall.Dup2()` as linux ARM64 does not have that syscall. On that platform, `syscall.Dup3()` needs to be used instead. Fixes: 57c909d * Implement dup2 with syscall.Dup3 on all linux platforms * Add explicit "unix" constraint to dup2_unix.go to ensure Windows is excluded
1 parent 68b8269 commit b3a3066

File tree

3 files changed

+68
-5
lines changed

3 files changed

+68
-5
lines changed

tool/tsh/common/dup2_linux.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Teleport
2+
// Copyright (C) 2025 Gravitational, Inc.
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
//go:build linux
18+
19+
package common
20+
21+
import "syscall"
22+
23+
// dup2 implements syscall.Dup2(oldfd, newfd) in a way that works on all
24+
// current Linux platforms, and likely on any new platforms. New platforms
25+
// such as ARM64 do not implement syscall.Dup2() instead implementing
26+
// syscall.Dup3() which is largely a superset, with one special case.
27+
func dup2(oldfd, newfd int) error {
28+
if oldfd == newfd {
29+
// dup2 would do nothing in this case, but dup3 returns an error.
30+
// Emulate dup2 behavior.
31+
return nil
32+
}
33+
return syscall.Dup3(oldfd, newfd, 0)
34+
}

tool/tsh/common/dup2_unix.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Teleport
2+
// Copyright (C) 2025 Gravitational, Inc.
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
//go:build unix && !linux
18+
19+
package common
20+
21+
import "syscall"
22+
23+
// dup2 wraps syscall.Dup2(oldfd, newfd) on non-linux unix platforms. The
24+
// linux implementation uses syscall.Dup3() as Dup2() is not available
25+
// on all linux platforms.
26+
func dup2(oldfd, newfd int) error {
27+
return syscall.Dup2(oldfd, newfd)
28+
}

tool/tsh/common/reexec_unix.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,17 @@ func replaceStdin() (*os.File, error) {
5151
}
5252
var dupErr error
5353
if ctrlErr := rc.Control(func(fd uintptr) {
54-
dupErr = syscall.Dup2(int(fd), syscall.Stdin)
55-
// stdin is not O_CLOEXEC after dup2 but thankfully the three stdio
56-
// file descriptors must be not O_CLOEXEC anyway, so we can avoid
57-
// a linux-specific implementation or syscall.ForkLock shenanigans
54+
dupErr = dup2(int(fd), syscall.Stdin)
55+
// dup2() is sufficient here as the three stdio file
56+
// descriptors must not be O_CLOEXEC. Darwin does not have
57+
// dup3(), so would need to resort to syscall.ForkLock
58+
// shenanigans if we did need to set O_CLOEXEC.
5859
}); ctrlErr != nil {
5960
_ = devNull.Close()
6061
return nil, trace.Wrap(ctrlErr)
6162
}
6263
if dupErr != nil {
63-
// this is the error from Dup2
64+
// this is the error from dup2
6465
_ = devNull.Close()
6566
return nil, trace.Wrap(err)
6667
}

0 commit comments

Comments
 (0)