summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorLiu Hua <sdu.liu@huawei.com>2019-07-09 22:20:45 -0700
committergVisor bot <gvisor-bot@google.com>2019-07-09 22:21:56 -0700
commit7581e84cb6b709019c51a1e7d86414f696470554 (patch)
tree3d3f83615896429df1a0dd52b6d271518d2b2bf6
parent7965b1272bb0579da47960e64ea902c74f49483d (diff)
tss: block userspace access to all I/O ports.
A userspace process (CPL=3) can access an i/o port if the bit corresponding to the port is set to 0 in the I/O permission bitmap. Configure the I/O permission bitmap address beyond the last valid byte in the TSS so access to all i/o ports is blocked. Signed-off-by: Liu Hua <sdu.liu@huawei.com> Change-Id: I3df76980c3735491db768f7210e71703f86bb989 PiperOrigin-RevId: 257336518
-rw-r--r--pkg/sentry/platform/ring0/kernel_amd64.go8
-rw-r--r--test/syscalls/linux/exceptions.cc34
2 files changed, 42 insertions, 0 deletions
diff --git a/pkg/sentry/platform/ring0/kernel_amd64.go b/pkg/sentry/platform/ring0/kernel_amd64.go
index 3577b5127..0feff8778 100644
--- a/pkg/sentry/platform/ring0/kernel_amd64.go
+++ b/pkg/sentry/platform/ring0/kernel_amd64.go
@@ -70,6 +70,14 @@ func (c *CPU) init() {
c.tss.ist1Lo = uint32(stackAddr)
c.tss.ist1Hi = uint32(stackAddr >> 32)
+ // Set the I/O bitmap base address beyond the last byte in the TSS
+ // to block access to the entire I/O address range.
+ //
+ // From section 18.5.2 "I/O Permission Bit Map" from Intel SDM vol1:
+ // I/O addresses not spanned by the map are treated as if they had set
+ // bits in the map.
+ c.tss.ioPerm = tssLimit + 1
+
// Permanently set the kernel segments.
c.registers.Cs = uint64(Kcode)
c.registers.Ds = uint64(Kdata)
diff --git a/test/syscalls/linux/exceptions.cc b/test/syscalls/linux/exceptions.cc
index 0da4c817d..370e85166 100644
--- a/test/syscalls/linux/exceptions.cc
+++ b/test/syscalls/linux/exceptions.cc
@@ -56,6 +56,26 @@ void inline Int3Normal() { asm(".byte 0xcd, 0x03\r\n"); }
void inline Int3Compact() { asm(".byte 0xcc\r\n"); }
+void InIOHelper(int width, int value) {
+ EXPECT_EXIT(
+ {
+ switch (width) {
+ case 1:
+ asm volatile("inb %%dx, %%al" ::"d"(value) : "%eax");
+ break;
+ case 2:
+ asm volatile("inw %%dx, %%ax" ::"d"(value) : "%eax");
+ break;
+ case 4:
+ asm volatile("inl %%dx, %%eax" ::"d"(value) : "%eax");
+ break;
+ default:
+ FAIL() << "invalid input width, only 1, 2 or 4 is allowed";
+ }
+ },
+ ::testing::KilledBySignal(SIGSEGV), "");
+}
+
TEST(ExceptionTest, Halt) {
// In order to prevent the regular handler from messing with things (and
// perhaps refaulting until some other signal occurs), we reset the handler to
@@ -87,6 +107,20 @@ TEST(ExceptionTest, DivideByZero) {
::testing::KilledBySignal(SIGFPE), "");
}
+TEST(ExceptionTest, IOAccessFault) {
+ // See above.
+ struct sigaction sa = {};
+ sa.sa_handler = SIG_DFL;
+ auto const cleanup = ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGSEGV, sa));
+
+ InIOHelper(1, 0x0);
+ InIOHelper(2, 0x7);
+ InIOHelper(4, 0x6);
+ InIOHelper(1, 0xffff);
+ InIOHelper(2, 0xffff);
+ InIOHelper(4, 0xfffd);
+}
+
TEST(ExceptionTest, Alignment) {
SetAlignmentCheck();
ClearAlignmentCheck();