创建带有和不带有IO位图的正确的任务状态段(TSS)结构? [英] Creating a proper Task State Segment (TSS) structure with and without an IO Bitmap?

查看:155
本文介绍了创建带有和不带有IO位图的正确的任务状态段(TSS)结构?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Intel和AMD之间阅读文档并查看代码有时会使您难以理解如何创建没有IO端口位图(IOPB)的适当任务状态段(TSS)。在使用IOPB创建TSS时似乎也有些困惑,因为在IO位图(IOPB)是否要求尾随 0xff 字节方面似乎模棱两可。



我知道TSS和TSS描述符(在GDT中)之间存在依赖关系。 TSS描述符控制TSS的基地址以及限制。描述符中的限制比结构的实际大小小一(本质上类似于GDT和IDT记录中指定的大小)。 TSS限制用于确定IOPB大小。



我知道:




  • TSS描述符限制比整个TSS结构的大小小一个

  • 16位TSS没有IOPB,并且结构是固定大小的

  • 基本的32位和64位TSS结构的大小相似(数据含义不同)

  • 32位TSS可以支持控制流通过在基本结构中添加额外的DWORD来强制执行。

  • TSS中的IOPB偏移量(单词)指向相对于Task段开头的偏移量。

  • IOPB偏移量指向IOPB结构的开始,并带有



    该链接还包含16位TSS和64位TSS结构。






    问题:




    • 如果我想要一个没有IOPB的TSS,我应该为+ 66h的IOPB偏移量填写什么值?

    • 如果我想要具有IOPB的TSS是否必须添加 0xff 字节到IOPB的末尾?

    • 在上图中,为什么末尾的额外字节表示为 xxxxx111 。如果最后一个字节假定为 0xff ,那不是 11111111 吗?


    解决方案

    这是一个非常公平的问题。尽管乍看之下,带有或不带有IO端口位图(IOPB)的TSS似乎微不足道,但它一直是激烈讨论的重点;辩论;不正确的文件;含糊的文件;和CPU设计人员提供的信息有时会使水变得浑浊。可以在 OS中找到关于此主题的很好的阅读。 / 2博物馆。尽管名称,但信息不限于OS / 2。可以从那篇文章中总结一下:


    显然,正确地使用IOPB并非易事。此外,错误设置的IOPB不太可能引起明显的问题,但可能不允许访问所需的端口,或者(更糟糕的是,从安全角度而言)允许访问不需要的端口。


    与386BSD,NetBSD,OpenBSD中的安全漏洞和错误有关的TSS和IOPB的肮脏历史使我们读到了有趣的东西,并且应该指示您提出的问题是否合理您希望避免引入错误。






    问题的答案



    如果您不希望使用IOPB,则可以简单地用整个TSS结构的长度填充IOPB偏移字段(不要减去1)。您的TSS结构中不应包含结尾的 0xff 字节。 TSS描述符中的TSS限制(如您所知)将比该值小1。英特尔手册说,如果IOPB偏移值中的值大于TSS限制,则没有IOPB。如果IOPB偏移字段中的值始终大于限制1,则满足此条件。



    如果使用IOPB,则在末尾将另一个字节设置为 0xff 根据英特尔文档。通过为所有 0xff 设置一个额外的字节,可以防止任何多端口访问(INW / OUTW / INL / OUTL)从最后8个端口开始或结束。这样可以避免多端口读/写可能跨越IOPB的末端,从而导致访问超出IOPB范围的端口的情况。它还将拒绝从最后8个端口之前的端口开始的多端口访问,该端口与随后的8个端口交叉。如果多端口访问的任何端口的权限位设置为1,则整个端口访问都会被拒绝(根据Intel文档)



    目前尚不清楚 x 在图的上下文中代表什么,但是如果将这些位设置为0,它们将显示为允许的端口,这不是您想要的。同样,请遵守英特尔文档,并在 0xff 处设置一个额外的尾随字节(所有位均设置为拒绝访问)。



    摘录自 Intel386 DX微处理器数据表


    I / O权限位图中的每个位对应于单个字节宽的I / O端口,如图4-15a所示。如果某个位为0,则可以在不生成异常的情况下对相应的字节宽端口进行I / O。否则,I / O指令将导致异常13错误。由于每个字节宽的I / O端口都必须是
    可保护的,因此与字宽或dword宽端口相对应的所有位都必须为0,以允许字宽或dword宽的I / O。如果所有引用的
    位均为0,则将允许I / O。如果任何引用的位为1,则尝试的I / O将导致异常13错误。



    **重要实现注:在I / O许可位图中I / O映射信息的最后一个字节之外,必须是一个包含全1的字节。全1的字节必须在Intel386 DX TSS段的限制内(见图4-15a)。







    在NASM程序集中,您可以创建一个如下结构:

      tss_entry:
    .back_link:dd 0
    .esp0:dd 0;在环形过渡
    .ss0:dd 0上使用的内核堆栈指针;环形过渡上使用的内核堆栈段
    .esp1:dd 0
    .ss1:dd 0
    .esp2:dd 0
    .ss2:dd 0
    .cr3: dd 0
    .eip:dd 0
    .eflags:dd 0
    .eax:dd 0
    .ecx:dd 0
    .edx:dd 0
    .ebx:dd 0
    .esp:dd 0
    .ebp:dd 0
    .esi:dd 0
    .edi:dd 0
    .es:dd 0
    .cs:dd 0
    .ss:dd 0
    .ds:dd 0
    .fs:dd 0
    .gs:dd 0
    .ldt:dd 0
    .trap:dw 0
    .iomap_base:dw TSS_SIZE; IOPB偏移量
    ; .cetssp:dd 0;如果启用了CET,则需要此功能

    ;在这里将任何内核定义的任务实例数据插入
    ; ...

    ;如果使用VME(虚拟模式扩展),则需要bean附加32个字节
    ;在iomap之前提供。如果使用VME取消注释,则接下来的2行
    ; .vmeintmap:;如果启用了VME,则取消注释此行和下一个
    ; TIMES 32 db 0; 32 * 8位= 256位(每个中断一个位)

    .iomap:
    TIMES TSS_IO_BITMAP_SIZE db 0x0
    ; IO位图(IOPB)大小8192(8 * 8192 = 65536),表示
    ;所有端口。 IO位图大小为0会使所有IO
    出错;如果IOPL< CPL(CPL = 3,v8086)
    %如果TSS_IO_BITMAP_SIZE> 0
    .iomap_pad:db 0xff;填充字节必须用0xff
    填充;使用IOPB时要处理某些CPU上的问题
    %endif
    TSS_SIZE EQU $ -tss_entry






    特别说明:




    • 如果使用高级语言并创建TSS结构,请确保您使用打包结构(即:使用GCC的 __ attribute __((packed))或MSVC的 #pragma pack )。查看您的编译器文档以获取更多详细信息。如果不注意此建议,可能会导致将额外的字节添加到TSS结构的末尾,如果您具有IOPB,可能会导致问题。如果TSS中存在IOPB并添加了额外的填充字节,则这些字节将成为IO位图的一部分,并可能授予/拒绝您不希望的权限。这是在BSD内核中产生错误的故障之一。

    • 在创建带有或不带有IOPB的TSS时,用于64位TSS的规则是相同的。即使在长模式(64位和兼容模式)下,仍然使用64位TSS,并且通过 LTR 指令。


    Reading the documentation between Intel and AMD and looking at code makes it difficult at times to understand how to create a proper Task State Segment (TSS) that has no IO port bitmap (IOPB). There also seems to be confusion over creating a TSS with an IOPB as well since it seems ambiguous as to whether an IO Bitmap (IOPB) requires a trailing 0xff byte.

    I'm aware that there are is a dependency between the TSS and a TSS Descriptor (in the GDT). The TSS descriptor governs the base address of the TSS as well as the limit. The limit in the descriptor is one less than the actual size of the structure (similar in nature to the size specified in a GDT and IDT record). The TSS limit comes into play to determine the IOPB size.

    I know that:

    • The TSS descriptor limit is one less than the size of the entire TSS structure
    • 16-bit TSS doesn't have an IOPB and the structure is a fixed size
    • The basic 32-bit and 64-bit TSS structures are similar in size (the data has different meaning)
    • the 32-bit TSS can support Control-flow Enforcement by adding an extra DWORD to the base structure.
    • The IOPB offset (word) in the TSS points to an offset relative to the beginning of the Task segment.
    • The IOPB offset points to the beginning of an IOPB structure, and with Virtual Mode Enhancements (VME) enabled the 32 bytes before IOPB are the interrupt redirection table.
    • If VME is not enabled the kernel can place extra per task instance data between the end of the basic TSS structure and the IOPB offset
    • If VME is enabled the kernel can place extra per task instance data between the end of the basic TSS structure and the offset 32 bytes below the IOPB.
    • If there is an IOPB present, each 0 bit is permission for port access and 1 denies permission.

    The 32-bit TSS structure can be visualized this way:

    The link also contains the layout of the 16-bit TSS and the 64-bit TSS structures.


    Questions:

    • If I want a TSS without an IOPB, what value should I fill in for the IOPB offset at +66h?
    • If I want a TSS with an IOPB do I have to add a 0xff byte to the end of the IOPB?
    • In the diagram above why does the extra byte at the end get represented as xxxxx111. If the last byte is suppose to be 0xff wouldn't that be 11111111?

    解决方案

    This is a very fair question. Although at first glance the TSS with or without an IO Port Bitmap (IOPB) seems rather trivial in nature, it has been the focus of intense discussion; debate; incorrect documentation; ambiguous documentation; and information from the CPU designers that at times muddied the waters. A very good read about this subject can be found in the OS/2 Museum. Despite the name, the information isn't limited to OS/2. One take away from that article that sums it up:

    It is obviously not trivial to use the IOPB correctly. In addition, an incorrectly set up IOPB is unlikely to cause obvious problems, but may disallow access to desired ports or (much worse, security-wise) allow access to undesired ports.

    The sordid history of the TSS and IOPB as it pertained to security holes and bugs in 386BSD, NetBSD, OpenBSD makes for an interesting read and should be an indicator that the questions you pose are reasonable if you wish to avoid introducing bugs.


    Answers to Questions

    If you want no IOPB, you can simply fill the IOPB offset field with the length of your entire TSS structure (do not subtract 1). Your TSS Structure should have no trailing 0xff byte in it. The TSS limit in the TSS descriptor (as you already are aware) will be one less than that value. The Intel manuals say that there is no IOPB if the value in the IOPB offset value is greater than the TSS limit. If the value in the IOPB offset field is always 1 greater than the limit this condition is satisfied. This is how modern Microsoft Windows handles it.

    If using an IOPB set an additional byte at the end to 0xff per the Intel documentation. By setting an extra byte to all 0xff would prevent any multi port access (INW/OUTW/INL/OUTL) starting in or ending in the last 8 ports. This would avoid the situation where a multi port read/write could straddle the end of the IOPB causing accesses to ports that fall outside the range of the IOPB. It would also deny multi port access that started on a port preceding the last 8 ports that crosses into the following 8 ports. If any port of a multi port access has a permission bit set to 1, the entire port access is denied (per the Intel documentation)

    It is unclear what the x represents in the context of the diagram, but if those bits were set to 0 they would appear as permissible ports which isn't what you want. Again, stick with the Intel documentation and set an extra trailing byte to 0xff (all bits set to deny access).

    From the Intel386 DX Microprocessor Data Sheet:

    Each bit in the I/O Permission Bitmap corresponds to a single byte-wide I/O port, as illustrated in Figure 4-15a. If a bit is 0, I/O to the corresponding byte-wide port can occur without generating an exception. Otherwise the I/O instruction causes an exception 13 fault. Since every byte-wide I/O port must be protectable, all bits corresponding to a word-wide or dword-wide port must be 0 for the word-wide or dword-wide I/O to be permitted. If all the referenced bits are 0, the I/O will be allowed. If any referenced bits are 1, the attempted I/O will cause an exception 13 fault.

    and

    **IMPORTANT IMPLEMENTATION NOTE: Beyond the last byte of I/O mapping information in the I/O Permission Bitmap must be a byte containing all 1’s. The byte of all 1’s must be within the limit of the Intel386 DX TSS segment (see Figure 4-15a).


    In NASM assembly you could create a structure that looks like:

    tss_entry:
    .back_link: dd 0
    .esp0:      dd 0              ; Kernel stack pointer used on ring transitions
    .ss0:       dd 0              ; Kernel stack segment used on ring transitions
    .esp1:      dd 0
    .ss1:       dd 0
    .esp2:      dd 0
    .ss2:       dd 0
    .cr3:       dd 0
    .eip:       dd 0
    .eflags:    dd 0
    .eax:       dd 0
    .ecx:       dd 0
    .edx:       dd 0
    .ebx:       dd 0
    .esp:       dd 0
    .ebp:       dd 0
    .esi:       dd 0
    .edi:       dd 0
    .es:        dd 0
    .cs:        dd 0
    .ss:        dd 0
    .ds:        dd 0
    .fs:        dd 0
    .gs:        dd 0
    .ldt:       dd 0
    .trap:      dw 0
    .iomap_base:dw TSS_SIZE         ; IOPB offset
    ;.cetssp:    dd 0              ; Need this if CET is enabled
    
    ; Insert any kernel defined task instance data here
    ; ...
    
    ; If using VME (Virtual Mode extensions) there need to bean additional 32 bytes
    ; available immediately preceding iomap. If using VME uncomment next 2 lines
    ;.vmeintmap:                     ; If VME enabled uncomment this line and the next
    ;TIMES 32    db 0                ;     32*8 bits = 256 bits (one bit for each interrupt)
    
    .iomap:
    TIMES TSS_IO_BITMAP_SIZE db 0x0
                                    ; IO bitmap (IOPB) size 8192 (8*8192=65536) representing
                                    ; all ports. An IO bitmap size of 0 would fault all IO
                                    ; port access if IOPL < CPL (CPL=3 with v8086)
    %if TSS_IO_BITMAP_SIZE > 0
    .iomap_pad: db 0xff             ; Padding byte that has to be filled with 0xff
                                    ; To deal with issues on some CPUs when using an IOPB
    %endif
    TSS_SIZE EQU $-tss_entry
    


    Special Note:

    • If you are using a high level language and creating a TSS structure, ensure you use a packed structure (ie: using GCC's __attribute__((packed)) or MSVC's #pragma pack). Review your compiler documentation for more details. Failure to heed this advice could cause extra bytes to be added to the end of your TSS structure that could cause problems if you have an IOPB. If an IOPB is present in the TSS and extra padding bytes are added those bytes will become part of the IO bitmap and may grant/deny permissions you didn't intend. This was one of the failures that produced bugs in BSD kernels.
    • The rules for the 64-bit TSS are the same when it comes to creating a TSS with or without an IOPB. A 64-bit TSS is still used even in Long Modes (64-bit and compatibility mode) and is loaded into the Task Register the same way it is done in legacy protected mode via the LTR instruction.

    这篇关于创建带有和不带有IO位图的正确的任务状态段(TSS)结构?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆