Source file src/runtime/secret.go

     1  // Copyright 2024 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build (amd64 || arm64) && linux
     6  
     7  package runtime
     8  
     9  import (
    10  	"internal/goarch"
    11  	"unsafe"
    12  )
    13  
    14  //go:linkname secret_count runtime/secret.count
    15  func secret_count() int32 {
    16  	return getg().secret
    17  }
    18  
    19  //go:linkname secret_inc runtime/secret.inc
    20  func secret_inc() {
    21  	gp := getg()
    22  	gp.secret++
    23  }
    24  
    25  //go:linkname secret_dec runtime/secret.dec
    26  func secret_dec() {
    27  	gp := getg()
    28  	gp.secret--
    29  }
    30  
    31  //go:linkname secret_eraseSecrets runtime/secret.eraseSecrets
    32  func secret_eraseSecrets() {
    33  	// zero all the stack memory that might be dirtied with
    34  	// secrets. We do this from the systemstack so that we
    35  	// don't have to figure out which holes we have to keep
    36  	// to ensure that we can return from memclr. gp.sched will
    37  	// act as a pigeonhole for our actual return.
    38  	lo := getg().stack.lo
    39  	systemstack(func() {
    40  		// Note, this systemstack call happens within the secret mode,
    41  		// so we don't have to call out to erase our registers, the systemstack
    42  		// code will do that.
    43  		mp := acquirem()
    44  		sp := mp.curg.sched.sp
    45  		// we need to keep systemstack return on top of the stack being cleared
    46  		// for traceback
    47  		sp -= goarch.PtrSize
    48  		// TODO: keep some sort of low water mark so that we don't have
    49  		// to zero a potentially large stack if we used just a little
    50  		// bit of it. That will allow us to use a higher value for
    51  		// lo than gp.stack.lo.
    52  		memclrNoHeapPointers(unsafe.Pointer(lo), sp-lo)
    53  		releasem(mp)
    54  	})
    55  	// Don't put any code here: the stack frame's contents are gone!
    56  }
    57  
    58  // specialSecret tracks whether we need to zero an object immediately
    59  // upon freeing.
    60  type specialSecret struct {
    61  	special special
    62  }
    63  
    64  // addSecret records the fact that we need to zero p immediately
    65  // when it is freed.
    66  func addSecret(p unsafe.Pointer) {
    67  	// TODO(dmo): figure out the cost of these. These are mostly
    68  	// intended to catch allocations that happen via the runtime
    69  	// that the user has no control over and not big buffers that user
    70  	// code is allocating. The cost should be relatively low,
    71  	// but we have run into a wall with other special allocations before.
    72  	lock(&mheap_.speciallock)
    73  	s := (*specialSecret)(mheap_.specialSecretAlloc.alloc())
    74  	s.special.kind = _KindSpecialSecret
    75  	unlock(&mheap_.speciallock)
    76  	addspecial(p, &s.special, false)
    77  }
    78  
    79  // send a no-op signal to an M for the purposes of
    80  // clobbering the signal stack
    81  //
    82  // Use sigpreempt. If we don't have a preemption queued, this just
    83  // turns into a no-op
    84  func noopSignal(mp *m) {
    85  	signalM(mp, sigPreempt)
    86  }
    87  
    88  // secret_getStack returns the memory range of the
    89  // current goroutine's stack.
    90  // For testing only.
    91  // Note that this is kind of tricky, as the goroutine can
    92  // be copied and/or exit before the result is used, at which
    93  // point it may no longer be valid.
    94  //
    95  //go:linkname secret_getStack runtime/secret.getStack
    96  func secret_getStack() (uintptr, uintptr) {
    97  	gp := getg()
    98  	return gp.stack.lo, gp.stack.hi
    99  }
   100  
   101  // return a slice of all Ms signal stacks
   102  // For testing only.
   103  //
   104  //go:linkname secret_appendSignalStacks runtime/secret.appendSignalStacks
   105  func secret_appendSignalStacks(sigstacks []stack) []stack {
   106  	// This is probably overkill, but it's what
   107  	// doAllThreadsSyscall does
   108  	stw := stopTheWorld(stwAllThreadsSyscall)
   109  	allocmLock.lock()
   110  	acquirem()
   111  	for mp := allm; mp != nil; mp = mp.alllink {
   112  		sigstacks = append(sigstacks, mp.gsignal.stack)
   113  	}
   114  	releasem(getg().m)
   115  	allocmLock.unlock()
   116  	startTheWorld(stw)
   117  	return sigstacks
   118  }
   119  

View as plain text