diff options
author | Michael Pratt <mpratt@google.com> | 2019-04-25 17:45:56 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2019-04-25 17:47:05 -0700 |
commit | f17cfa4d53742923b5c91b149b82a05bcda3ea20 (patch) | |
tree | 3f945f2f0db9b1f87e5173e832498998047fbd65 /pkg/sentry/arch | |
parent | 6b76c172b48ecb2c342882c0fe6474b2b973dad0 (diff) |
Perform explicit CPUID and FP state compatibility checks on restore
PiperOrigin-RevId: 245341004
Change-Id: Ic4d581039d034a8ae944b43e45e84eb2c3973657
Diffstat (limited to 'pkg/sentry/arch')
-rw-r--r-- | pkg/sentry/arch/arch_state_x86.go | 59 |
1 files changed, 46 insertions, 13 deletions
diff --git a/pkg/sentry/arch/arch_state_x86.go b/pkg/sentry/arch/arch_state_x86.go index 604bd08a6..01949049d 100644 --- a/pkg/sentry/arch/arch_state_x86.go +++ b/pkg/sentry/arch/arch_state_x86.go @@ -15,14 +15,31 @@ package arch import ( - "sync" + "fmt" "syscall" - "gvisor.googlesource.com/gvisor/pkg/log" + "gvisor.googlesource.com/gvisor/pkg/cpuid" + "gvisor.googlesource.com/gvisor/pkg/sentry/usermem" ) -// warnOnce is used to warn about truncated state only once. -var warnOnce sync.Once +// ErrFloatingPoint indicates a failed restore due to unusable floating point +// state. +type ErrFloatingPoint struct { + // supported is the supported floating point state. + supported uint64 + + // saved is the saved floating point state. + saved uint64 +} + +// Error returns a sensible description of the restore error. +func (e ErrFloatingPoint) Error() string { + return fmt.Sprintf("floating point state contains unsupported features; supported: %#x saved: %#x", e.supported, e.saved) +} + +// XSTATE_BV does not exist if FXSAVE is used, but FXSAVE implicitly saves x87 +// and SSE state, so this is the equivalent XSTATE_BV value. +const fxsaveBV uint64 = cpuid.XSAVEFeatureX87 | cpuid.XSAVEFeatureSSE // afterLoad is invoked by stateify. func (s *State) afterLoad() { @@ -33,7 +50,8 @@ func (s *State) afterLoad() { // state that may be saved by the new CPU. Even if extraneous new state // is saved, the state we care about is guaranteed to be a subset of // new state. Later optimizations can use less space when using a - // smaller state component bitmap. Intel SDM section 13 has more info. + // smaller state component bitmap. Intel SDM Volume 1 Chapter 13 has + // more info. s.x86FPState = newX86FPState() // x86FPState always contains all the FP state supported by the host. @@ -41,15 +59,30 @@ func (s *State) afterLoad() { // which we cannot restore. // // The x86 FP state areas are backwards compatible, so we can simply - // truncate the additional floating point state. Applications should - // not depend on the truncated state because it should relate only to - // features that were not exposed in the app FeatureSet. + // truncate the additional floating point state. + // + // Applications should not depend on the truncated state because it + // should relate only to features that were not exposed in the app + // FeatureSet. However, because we do not *prevent* them from using + // this state, we must verify here that there is no in-use state + // (according to XSTATE_BV) which we do not support. if len(s.x86FPState) < len(old) { - warnOnce.Do(func() { - // This will occur on every instance of state, don't - // bother warning more than once. - log.Infof("dropping %d bytes of floating point state; the application should not depend on this state", len(old)-len(s.x86FPState)) - }) + // What do we support? + supportedBV := fxsaveBV + if fs := cpuid.HostFeatureSet(); fs.UseXsave() { + supportedBV = fs.ValidXCR0Mask() + } + + // What was in use? + savedBV := fxsaveBV + if len(old) >= xstateBVOffset+8 { + savedBV = usermem.ByteOrder.Uint64(old[xstateBVOffset:]) + } + + // Supported features must be a superset of saved features. + if savedBV&^supportedBV != 0 { + panic(ErrFloatingPoint{supported: supportedBV, saved: savedBV}) + } } // Copy to the new, aligned location. |