Intel® ISA Extensions
Use hardware-based isolation and memory encryption to provide more code protection in your solutions.
1095 Discussions

BNDLDX/BNDSTX, BNDSTATUS error = 2, expected behavior?

c_43
Beginner
703 Views

Consider the example given at https://software.intel.com/en-us/blogs/2013/07/22/intel-memory-protection-extensions-intel-mpx-support-in-the-gnu-toolchain in particular the example "Another simple example demonstrates using of bndldx and bndstx instructions.".

Adapting this example to include a main function calling foo and having p and q defined in a different source file and pointed to a couple buffers each (source included at the bottom of this post), I get BNDSTATUS set to error = 2 (invalid BD entry) for some of the BNDSTX and BNDLDX instructions. I've noticed this also happens in other test/example programs. Why does this happen? Is this behavior normal and to be expected? The program otherwise works as expected and detects the bound violation, so I'm guessing there is something obvious I'm missing.

Program received signal SIGSEGV, Segmentation fault.
0x000000000040071e in _GLOBAL__sub_P_00102_0_p () at externs.c:5
5       int *q = array_q;
   0x0000000000400700 <_GLOBAL__sub_P_00102_0_p+0>:     55      push   rbp
   0x0000000000400701 <_GLOBAL__sub_P_00102_0_p+1>:     48 89 e5        mov    rbp,rsp
   0x0000000000400704 <_GLOBAL__sub_P_00102_0_p+4>:     66 0f 1a 05 54 09 20 00 bndmov bnd0,[rip+0x200954]        # 0x601060 <__mpx_bounds_of_array_q>
   0x000000000040070c <_GLOBAL__sub_P_00102_0_p+12>:    66 0f 1a 0d 3c 09 20 00 bndmov bnd1,[rip+0x20093c]        # 0x601050 <__mpx_bounds_of_array_p>
   0x0000000000400714 <_GLOBAL__sub_P_00102_0_p+20>:    b8 40 10 60 00  mov    eax,0x601040
   0x0000000000400719 <_GLOBAL__sub_P_00102_0_p+25>:    ba c0 14 60 00  mov    edx,0x6014c0
=> 0x000000000040071e <_GLOBAL__sub_P_00102_0_p+30>:    0f 1b 0c 10     bndstx DWORD PTR [rax+rdx*1],bnd1
   0x0000000000400722 <_GLOBAL__sub_P_00102_0_p+34>:    b8 48 10 60 00  mov    eax,0x601048
   0x0000000000400727 <_GLOBAL__sub_P_00102_0_p+39>:    ba c0 10 60 00  mov    edx,0x6010c0
   0x000000000040072c <_GLOBAL__sub_P_00102_0_p+44>:    0f 1b 04 10     bndstx DWORD PTR [rax+rdx*1],bnd0
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x00000000004006de in main (argc=2, argv=0x7fff17c06718) at mpx_bndldx_bndstx_main.c:15
15              foo(atoi(argv[1]));
   0x00000000004006d3 <main+20>:        48 8b 45 f0     mov    rax,QWORD PTR [rbp-0x10]
   0x00000000004006d7 <main+24>:        48 83 c0 08     add    rax,0x8
   0x00000000004006db <main+28>:        48 8b 10        mov    rdx,QWORD PTR [rax]
=> 0x00000000004006de <main+31>:        0f 1a 04 10     bndldx bnd0,DWORD PTR [rax+rdx*1]
   0x00000000004006e2 <main+35>:        48 89 d7        mov    rdi,rdx
   0x00000000004006e5 <main+38>:        b8 00 00 00 00  mov    eax,0x0
   0x00000000004006ea <main+43>:        f2 e8 70 fe ff ff       bnd call 0x400560 <atoi@plt>
   0x00000000004006f0 <main+49>:        89 c7   mov    edi,eax
   0x00000000004006f2 <main+51>:        f2 e8 65 ff ff ff       bnd call 0x40065d <foo>

BNDCFGU, BNDSTATUS (on the last SIGSEGV:

bndcfgu        {raw = 0x7fbda0cd1001, config = {base = 0x7fbda0cd1, reserved = 0x0, preserved = 0x0, enabled = 0x1}}    {raw = 0x7fbda0cd1001, config = {
    base = 34290142417, reserved = 0, preserved = 0, enabled = 1}}
bndstatus      {raw = 0x7fbde0cce692, status = {bde = 0x1fef783339a4, error = 0x2}}     {raw = 0x7fbde0cce692, status = {bde = 35113374267812, error = 2}}

I'm using:

gcc (GCC) 4.9.0 20130715 (experimental)
sde-external-7.1.0-2014-07-20-lin
sde-external-6.22.0-2014-03-06-lin (both SDEs give the same result)
2014-02-13-mpx-runtime-external-lin

mpx_bndldx_bndstx_main:

#include <stdio.h>

extern int * p;
extern int * q;

int foo( int c)
{
        q = p;

        return p;
}

int main(int argc, char **argv)
{
        foo(atoi(argv[1]));

        return 0;
}

externs.c:

int array_p[256];
int array_q[256];

int *p = array_p;
int *q = array_q;

0 Kudos
3 Replies
Michael_B_Intel2
Employee
703 Views

Hi,

MPX is using a 2 level hash table of data with entry for each pointer.

The first table is allocated at the start of the run, but second level tables are allocated on demand.

BNDSTX is storing pointers bound data to the table.

BNDLDX is loading pointers bound data from the table.

MPX needs  to know that it stores/loads a pointer for the first time in-order to allocate the required second level table.

BNDSTATUS error = 2 indicates that “this is the first time” and MPX runtime should allocate this table.

 

0 Kudos
c_43
Beginner
703 Views

Thank you for your answer.

So BNDSTATUS error = 2 is never an indication of an actual error, but rather an indication that allocation needs to be performed by the runtime, somewhat similar (but of course different) to a page fault?

However it seems a little strange to me that the BNDSTATUS error 2 persists, even after subsequent BNDLDX/BNDSTX instructions.

Such as:

Program received signal SIGSEGV, Segmentation fault.
0x000000000040071e in init () at mpx_bndldx_bndstx_main.c:21
21                      q = 0x00;
   0x0000000000400710 <init+67>:        3c 09   cmp    al,0x9
   0x0000000000400712 <init+69>:        20 00   and    BYTE PTR [rax],al
   0x0000000000400714 <init+71>:        b8 40 10 60 00  mov    eax,0x601040
   0x0000000000400719 <init+76>:        ba c0 14 60 00  mov    edx,0x6014c0
=> 0x000000000040071e <init+81>:        0f 1b 0c 10     bndstx DWORD PTR [rax+rdx*1],bnd1
   0x0000000000400722 <init+85>:        b8 48 10 60 00  mov    eax,0x601048
   0x0000000000400727 <init+90>:        ba c0 10 60 00  mov    edx,0x6010c0
   0x000000000040072c <init+95>:        0f 1b 04 10     bndstx DWORD PTR [rax+rdx*1],bnd0

Here, we have status:

(gdb) i r bndstatus
bndstatus      {raw = 0x7f9561e4d032, status = {bde = 0x1fe55879340c, error = 0x2}}     {raw = 0x7f9561e4d032, status = {bde = 35069892310028, error = 2}}

Which seems to be fine, as it executes the runtime in libmpx-runtime64.so to deal with this.

However, should not the BNDSTATUS error be cleared once this handler is finished?

Consider after this bndstx instruction which segfaulted:

   0x000000000040071e <init+81>:        0f 1b 0c 10     bndstx DWORD PTR [rax+rdx*1],bnd1
   0x0000000000400722 <init+85>:        b8 48 10 60 00  mov    eax,0x601048
=> 0x0000000000400727 <init+90>:        ba c0 10 60 00  mov    edx,0x6010c0

(gdb) i r bndstatus
bndstatus      {raw = 0x7f9561e4d032, status = {bde = 0x1fe55879340c, error = 0x2}}     {raw = 0x7f9561e4d032, status = {bde = 35069892310028, error = 2}}

Even after executing the subsequent bndstx (at init+95):

   0x000000000040072c <init+95>:        0f 1b 04 10     bndstx DWORD PTR [rax+rdx*1],bnd0
=> 0x0000000000400730 <init+99>:        5d      pop    rbp

(gdb) i r bndstatus
bndstatus      {raw = 0x7f9561e4d032, status = {bde = 0x1fe55879340c, error = 0x2}}     {raw = 0x7f9561e4d032, status = {bde = 35069892310028, error = 2}}

Is this behavior normal and to be expected as well?

 

0 Kudos
Michael_B_Intel2
Employee
703 Views

> somewhat similar (but of course different) to a page fault?

yes, it is quite similar

 > However it seems a little strange to me that the BNDSTATUS error 2 persists

You are right, currently BNDSTATUS.error is not been reset after handling the #BR.

I’ll check for the correct behavior and update accordingly.

0 Kudos
Reply