Skip to content

Commit 99d5958

Browse files
prattmicshentubot
authored andcommitted
Validate FS_BASE in Task.Clone
arch_prctl already verified that the new FS_BASE was canonical, but Task.Clone did not. Centralize these checks in the arch packages. Failure to validate could cause an error in PTRACE_SET_REGS when we try to switch to the app. PiperOrigin-RevId: 224862398 Change-Id: Iefe63b3f9aa6c4810326b8936e501be3ec407f14
1 parent 25b8424 commit 99d5958

File tree

6 files changed

+38
-11
lines changed

6 files changed

+38
-11
lines changed

pkg/sentry/arch/arch.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ type Context interface {
115115
// SetStack sets the current stack pointer.
116116
SetStack(value uintptr)
117117

118+
// TLS returns the current TLS pointer.
119+
TLS() uintptr
120+
121+
// SetTLS sets the current TLS pointer. Returns false if value is invalid.
122+
SetTLS(value uintptr) bool
123+
118124
// SetRSEQInterruptedIP sets the register that contains the old IP when a
119125
// restartable sequence is interrupted.
120126
SetRSEQInterruptedIP(value uintptr)

pkg/sentry/arch/arch_amd64.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,22 @@ func (c *context64) SetStack(value uintptr) {
158158
c.Regs.Rsp = uint64(value)
159159
}
160160

161+
// TLS returns the current TLS pointer.
162+
func (c *context64) TLS() uintptr {
163+
return uintptr(c.Regs.Fs_base)
164+
}
165+
166+
// SetTLS sets the current TLS pointer. Returns false if value is invalid.
167+
func (c *context64) SetTLS(value uintptr) bool {
168+
if !isValidSegmentBase(uint64(value)) {
169+
return false
170+
}
171+
172+
c.Regs.Fs = 0
173+
c.Regs.Fs_base = uint64(value)
174+
return true
175+
}
176+
161177
// SetRSEQInterruptedIP implements Context.SetRSEQInterruptedIP.
162178
func (c *context64) SetRSEQInterruptedIP(value uintptr) {
163179
c.Regs.R10 = uint64(value)

pkg/sentry/arch/arch_x86.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,10 +353,10 @@ func (s *State) PtraceSetRegs(src io.Reader) (int, error) {
353353
if !isUserSegmentSelector(regs.Ss) {
354354
return 0, syscall.EIO
355355
}
356-
if regs.Fs_base >= uint64(maxAddr64) {
356+
if !isValidSegmentBase(regs.Fs_base) {
357357
return 0, syscall.EIO
358358
}
359-
if regs.Gs_base >= uint64(maxAddr64) {
359+
if !isValidSegmentBase(regs.Gs_base) {
360360
return 0, syscall.EIO
361361
}
362362
// CS and SS are validated, but changes to them are otherwise silently
@@ -389,6 +389,12 @@ func isUserSegmentSelector(reg uint64) bool {
389389
return reg&3 == 3
390390
}
391391

392+
// isValidSegmentBase returns true if the given segment base specifies a
393+
// canonical user address.
394+
func isValidSegmentBase(reg uint64) bool {
395+
return reg < uint64(maxAddr64)
396+
}
397+
392398
// ptraceFPRegsSize is the size in bytes of Linux's user_i387_struct, the type
393399
// manipulated by PTRACE_GETFPREGS and PTRACE_SETFPREGS on x86. Equivalently,
394400
// ptraceFPRegsSize is the size in bytes of the x86 FXSAVE area.

pkg/sentry/kernel/task_clone.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,9 @@ func (t *Task) Clone(opts *CloneOptions) (ThreadID, *SyscallControl, error) {
210210
tc.Arch.SetStack(uintptr(opts.Stack))
211211
}
212212
if opts.SetTLS {
213-
tc.Arch.StateData().Regs.Fs_base = uint64(opts.TLS)
213+
if !tc.Arch.SetTLS(uintptr(opts.TLS)) {
214+
return 0, nil, syserror.EPERM
215+
}
214216
}
215217

216218
var fsc *FSContext

pkg/sentry/platform/ptrace/subprocess.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -480,10 +480,10 @@ func (s *subprocess) switchToApp(c *context, ac arch.Context) bool {
480480

481481
// Set registers.
482482
if err := t.setRegs(regs); err != nil {
483-
panic(fmt.Sprintf("ptrace set regs failed: %v", err))
483+
panic(fmt.Sprintf("ptrace set regs (%+v) failed: %v", regs, err))
484484
}
485485
if err := t.setFPRegs(fpState, uint64(fpLen), useXsave); err != nil {
486-
panic(fmt.Sprintf("ptrace set fpregs failed: %v", err))
486+
panic(fmt.Sprintf("ptrace set fpregs (%+v) failed: %v", fpState, err))
487487
}
488488

489489
for {

pkg/sentry/syscalls/linux/sys_tls.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"gvisor.googlesource.com/gvisor/pkg/abi/linux"
2323
"gvisor.googlesource.com/gvisor/pkg/sentry/arch"
2424
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel"
25-
"gvisor.googlesource.com/gvisor/pkg/sentry/usermem"
2625
)
2726

2827
// ArchPrctl implements linux syscall arch_prctl(2).
@@ -31,19 +30,17 @@ func ArchPrctl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sys
3130
switch args[0].Int() {
3231
case linux.ARCH_GET_FS:
3332
addr := args[1].Pointer()
34-
_, err := t.CopyOut(addr, &t.Arch().StateData().Regs.Fs_base)
33+
fsbase := t.Arch().TLS()
34+
_, err := t.CopyOut(addr, uint64(fsbase))
3535
if err != nil {
3636
return 0, nil, err
3737
}
3838

3939
case linux.ARCH_SET_FS:
4040
fsbase := args[1].Uint64()
41-
if _, ok := t.MemoryManager().CheckIORange(usermem.Addr(fsbase), 0); !ok {
41+
if !t.Arch().SetTLS(uintptr(fsbase)) {
4242
return 0, nil, syscall.EPERM
4343
}
44-
regs := &t.Arch().StateData().Regs
45-
regs.Fs = 0
46-
regs.Fs_base = fsbase
4744

4845
case linux.ARCH_GET_GS, linux.ARCH_SET_GS:
4946
t.Kernel().EmitUnimplementedEvent(t)

0 commit comments

Comments
 (0)