systrap: don't restart the task after replacing a syscall with a function call

PiperOrigin-RevId: 627556852
This commit is contained in:
Andrei Vagin
2024-04-23 17:43:28 -07:00
committed by gVisor bot
parent 06c085fae5
commit 38f63e832a
2 changed files with 9 additions and 16 deletions
+1 -4
View File
@@ -186,10 +186,7 @@ restart:
return nil, hostarch.NoAccess, err
}
if needPatch {
restart, _ := s.usertrap.PatchSyscall(ctx, ac, mm)
if restart {
goto restart
}
s.usertrap.PatchSyscall(ctx, ac, mm)
}
if !isSyscall && linux.Signal(c.signalInfo.Signo) == linux.SIGILL {
err := s.usertrap.HandleFault(ctx, ac, mm)
@@ -187,12 +187,10 @@ func loadUsertrap(ctx context.Context, mm memoryManager, addr hostarch.Addr) err
}
// PatchSyscall changes the syscall instruction into a function call.
//
// Returns true if the thread has to be restarted.
func (s *State) PatchSyscall(ctx context.Context, ac *arch.Context64, mm memoryManager) (bool, error) {
func (s *State) PatchSyscall(ctx context.Context, ac *arch.Context64, mm memoryManager) error {
task := kernel.TaskFromContext(ctx)
if task == nil {
return false, fmt.Errorf("no task found")
return fmt.Errorf("no task found")
}
s.mu.Lock()
@@ -203,7 +201,7 @@ func (s *State) PatchSyscall(ctx context.Context, ac *arch.Context64, mm memoryM
prevCode := make([]uint8, len(jmpInst))
if _, err := primitive.CopyUint8SliceIn(task.OwnCopyContext(usermem.IOOpts{AddressSpaceActive: false}), hostarch.Addr(patchAddr), prevCode); err != nil {
return false, err
return err
}
// Check that another thread has not patched this syscall yet.
@@ -214,7 +212,7 @@ func (s *State) PatchSyscall(ctx context.Context, ac *arch.Context64, mm memoryM
trapAddr, err := s.addTrapLocked(ctx, ac, mm, uint32(sysno))
if trapAddr == 0 || err != nil {
ctx.Warningf("Failed to add a new trap: %v", err)
return false, nil
return nil
}
// Replace "mov sysno, %eax; syscall" with "jmp trapAddr".
@@ -258,24 +256,22 @@ func (s *State) PatchSyscall(ctx context.Context, ac *arch.Context64, mm memoryM
// the invalid instruction and restart a patched code.
faultInstB := primitive.ByteSlice(faultInst[:])
if _, err := faultInstB.CopyOut(ignorePermContext, hostarch.Addr(patchAddr+faultInstOffset)); err != nil {
return false, err
return err
}
// The second step is to replace all bytes except the first one
// which is the opcode of the mov instruction, so that the first
// five bytes remain "mov XXX, %rax".
if _, err := primitive.CopyUint8SliceOut(ignorePermContext, hostarch.Addr(patchAddr+1), newCode[1:]); err != nil {
return false, err
return err
}
// The final step is to replace the first byte of the patch.
// After this point, all threads will read the valid jmp
// instruction.
if _, err := primitive.CopyUint8SliceOut(ignorePermContext, hostarch.Addr(patchAddr), newCode[0:1]); err != nil {
return false, err
return err
}
}
ac.RestartSyscall()
ac.SetIP(patchAddr)
return true, nil
return nil
}
// HandleFault handles a fault on a patched syscall instruction.