summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/platform/ring0
diff options
context:
space:
mode:
authorgVisor bot <gvisor-bot@google.com>2020-10-02 23:33:09 +0000
committergVisor bot <gvisor-bot@google.com>2020-10-02 23:33:09 +0000
commit0c7055c40f978bd8f0ca5aa362948ad9807efe54 (patch)
tree15e2db7ad577b015dabc47fe6e399e69d933df8a /pkg/sentry/platform/ring0
parent206a76f369cf78e0c62bbad15adbad006b548c98 (diff)
parent55f835d1fdd0a5d9dca0b19a65cb748caf326f79 (diff)
Merge release-20200921.0-106-g55f835d1f (automated)
Diffstat (limited to 'pkg/sentry/platform/ring0')
-rw-r--r--pkg/sentry/platform/ring0/defs_impl_amd64.go39
-rw-r--r--pkg/sentry/platform/ring0/entry_impl_amd64.s12
-rw-r--r--pkg/sentry/platform/ring0/entry_impl_arm64.s1
3 files changed, 42 insertions, 10 deletions
diff --git a/pkg/sentry/platform/ring0/defs_impl_amd64.go b/pkg/sentry/platform/ring0/defs_impl_amd64.go
index 7a06eb316..795cf86ba 100644
--- a/pkg/sentry/platform/ring0/defs_impl_amd64.go
+++ b/pkg/sentry/platform/ring0/defs_impl_amd64.go
@@ -270,6 +270,7 @@ func Emit(w io.Writer) {
fmt.Fprintf(w, "\n// Bits.\n")
fmt.Fprintf(w, "#define _RFLAGS_IF 0x%02x\n", _RFLAGS_IF)
+ fmt.Fprintf(w, "#define _RFLAGS_IOPL0 0x%02x\n", _RFLAGS_IOPL0)
fmt.Fprintf(w, "#define _KERNEL_FLAGS 0x%02x\n", KernelFlagsSet)
fmt.Fprintf(w, "\n// Vectors.\n")
@@ -343,7 +344,9 @@ const (
_RFLAGS_AC = 1 << 18
_RFLAGS_NT = 1 << 14
- _RFLAGS_IOPL = 3 << 12
+ _RFLAGS_IOPL0 = 1 << 12
+ _RFLAGS_IOPL1 = 1 << 13
+ _RFLAGS_IOPL = _RFLAGS_IOPL0 | _RFLAGS_IOPL1
_RFLAGS_DF = 1 << 10
_RFLAGS_IF = 1 << 9
_RFLAGS_STEP = 1 << 8
@@ -371,15 +374,45 @@ const (
KernelFlagsSet = _RFLAGS_RESERVED
// UserFlagsSet are always set in userspace.
- UserFlagsSet = _RFLAGS_RESERVED | _RFLAGS_IF
+ //
+ // _RFLAGS_IOPL is a set of two bits and it shows the I/O privilege
+ // level. The Current Privilege Level (CPL) of the task must be less
+ // than or equal to the IOPL in order for the task or program to access
+ // I/O ports.
+ //
+ // Here, _RFLAGS_IOPL0 is used only to determine whether the task is
+ // running in the kernel or userspace mode. In the user mode, the CPL is
+ // always 3 and it doesn't matter what IOPL is set if it is bellow CPL.
+ //
+ // We need to have one bit which will be always different in user and
+ // kernel modes. And we have to remember that even though we have
+ // KernelFlagsClear, we still can see some of these flags in the kernel
+ // mode. This can happen when the goruntime switches on a goroutine
+ // which has been saved in the host mode. On restore, the popf
+ // instruction is used to restore flags and this means that all flags
+ // what the goroutine has in the host mode will be restored in the
+ // kernel mode.
+ //
+ // _RFLAGS_IOPL0 is never set in host and kernel modes and we always set
+ // it in the user mode. So if this flag is set, the task is running in
+ // the user mode and if it isn't set, the task is running in the kernel
+ // mode.
+ UserFlagsSet = _RFLAGS_RESERVED | _RFLAGS_IF | _RFLAGS_IOPL0
// KernelFlagsClear should always be clear in the kernel.
KernelFlagsClear = _RFLAGS_STEP | _RFLAGS_IF | _RFLAGS_IOPL | _RFLAGS_AC | _RFLAGS_NT
// UserFlagsClear are always cleared in userspace.
- UserFlagsClear = _RFLAGS_NT | _RFLAGS_IOPL
+ UserFlagsClear = _RFLAGS_NT | _RFLAGS_IOPL1
)
+// IsKernelFlags returns true if rflags coresponds to the kernel mode.
+//
+// go:nosplit
+func IsKernelFlags(rflags uint64) bool {
+ return rflags&_RFLAGS_IOPL0 == 0
+}
+
// Vector is an exception vector.
type Vector uintptr
diff --git a/pkg/sentry/platform/ring0/entry_impl_amd64.s b/pkg/sentry/platform/ring0/entry_impl_amd64.s
index 3df00dee8..1216f3843 100644
--- a/pkg/sentry/platform/ring0/entry_impl_amd64.s
+++ b/pkg/sentry/platform/ring0/entry_impl_amd64.s
@@ -17,6 +17,7 @@
// Bits.
#define _RFLAGS_IF 0x200
+#define _RFLAGS_IOPL0 0x1000
#define _KERNEL_FLAGS 0x02
// Vectors.
@@ -263,13 +264,10 @@ TEXT ·Start(SB),NOSPLIT,$0
// See entry_amd64.go.
TEXT ·sysenter(SB),NOSPLIT,$0
- // Interrupts are always disabled while we're executing in kernel mode
- // and always enabled while executing in user mode. Therefore, we can
- // reliably look at the flags in R11 to determine where this syscall
- // was from.
- TESTL $_RFLAGS_IF, R11
+ // _RFLAGS_IOPL0 is always set in the user mode and it is never set in
+ // the kernel mode. See the comment of UserFlagsSet for more details.
+ TESTL $_RFLAGS_IOPL0, R11
JZ kernel
-
user:
SWAP_GS()
MOVQ AX, ENTRY_SCRATCH0(GS) // Save user AX on scratch.
@@ -348,7 +346,7 @@ TEXT ·exception(SB),NOSPLIT,$0
// ERROR_CODE (sp+8)
// VECTOR (sp+0)
//
- TESTL $_RFLAGS_IF, 32(SP)
+ TESTL $_RFLAGS_IOPL0, 32(SP)
JZ kernel
user:
diff --git a/pkg/sentry/platform/ring0/entry_impl_arm64.s b/pkg/sentry/platform/ring0/entry_impl_arm64.s
index f57fc369a..d654ebcb0 100644
--- a/pkg/sentry/platform/ring0/entry_impl_arm64.s
+++ b/pkg/sentry/platform/ring0/entry_impl_arm64.s
@@ -17,6 +17,7 @@
// Bits.
#define _RFLAGS_IF 0x200
+#define _RFLAGS_IOPL0 0x1000
#define _KERNEL_FLAGS 0x02
// Vectors.