[LINUX] Cause a bus error on x86

Introduction

Bus errors are rarely seen on x86 systems. I investigated when a bus error (SIGBUS) occurs. I wrote x86 in the title, but I also checked SPARC.

About Bus error

Bus error (SIGBUS) is, as the name implies, an error that occurs on a bus. Occurs when an error occurs when the CPU makes an access request to physical memory (it is supposed to). Normally, what is visible to the user program is the logical address, and since the physical address is not directly touched, it is difficult for the user program to cause a Bus error. It is also known to occur due to alignment errors, but this does not happen on x86 because the alignment check is normally off. As far as I investigated, it was found that Bus error can be caused by two ways, "call a system call that causes SIGBUS" and "cause an alignment error after enabling alignment check".

Use mmap

An example from StackOverflow. SIGBUS appears when you touch outside the area secured by mmap.

bus.c


#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
int main() {
    FILE *f = tmpfile();
    int *m = (int*)mmap(0, 4, PROT_WRITE, MAP_PRIVATE, fileno(f), 0);
    *m = 0;
    return 0;
}
$ gcc bus.c
$ ./a.out
[1]    16871 bus error  ./bus

The man mmap also has a statement to that effect.

The system shall always zero-fill any partial page at the end of an object. Further, the system shall never write out any modified portions of the last page of an object which are beyond its end. References within the address range starting at pa and continuing for len bytes to whole pages following the end of an object shall result in delivery of a SIGBUS signal.

Also, mmap's Source explicitly returns VM_FAULT_SIGBUS.

Examples of alignment inconsistencies

An example found in here that is secured by char and accessed by int.

bus2.c


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char *p = (char*)malloc(sizeof(int) + 1);
    memset(p, 0, sizeof(int) + 1);
    p++;
    printf("%d\n", *(int *)p);
    return 0;
}

This ends normally despite the alignment inconsistency. This is because the x86 EFLAGS Alignment Check (AC) flag is turned off. If this is turned on, a Bus error will occur.

bus2p.c


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    asm( "pushf\n\torl $0x40000,(%rsp)\n\tpopf");
    char *p = (char*)malloc(sizeof(int) + 1);
    memset(p, 0, sizeof(int) + 1);
    p++;
    printf("%d\n", *(int *)p);
    return 0;
}

Even if the AC flag is turned on, the bus error does not occur on Mac OS X and it ends normally.

Unauthorized access to the string area

Try to access the string area.

bus3.c


#include <stdio.h>
#include <stdlib.h>

int
main(void){
  char *s = "test";
  s[0] = '0';
  printf("%s\n",s);
}

This results in a Segmentation Fault (SIGSEGV) on Linux, but gives a Bus error on Mac.


$ clang bus3.c
$ ./a.out
Bus error: 10

Summary

In summary, it looks like this. I also included the results of Cygwin. I also had a SPARC Linux system, so I checked it there as well (excluding bus2p.c, which uses inline assembly).

bus.c bus2.c bus2p.c bus3.c
Linux SIGBUS Successful completion SIGBUS SIGSEGV
Mac OS X SIGBUS Successful completion Successful completion SIGBUS
Cygwin SIGBUS Successful completion Successful completion SIGSEGV
SPARC SIGSEGV SIGBUS ---- SIGSEGV

In today's x86 system, Bus error doesn't seem to come out of the user program unless you explicitly enable alignment check to make alignment inconsistent access or use a system call that issues SIGBUS. The exception is Mac, which has been pointed out as the distinction between SIGBUS and SIGSEGV is ambiguous, and a bus error occurs just by accessing a character string. Even on the same Linux, if it is SPARC, the operation is quite different. I think it's true that SIGBUS is issued due to improper alignment, but I'm not sure why it is issued SIGSEGV due to improper mmap (Isn't it decided by POSIX?).

I don't like the fact that all the systems I checked have different behaviors.

Recommended Posts

Cause a bus error on x86
A story about a 503 error on Heroku open
Build a Python development environment on Mac OS X
Create a Python development environment on OS X Lion
Build a machine learning environment natively on Windows 10 (x64)
A comment on Boruta algorithm
Put Python 3.x on Ubuntu
Run Tensorflow 2.x on Python 3.7
Create a classroom on Jupyterhub
Memo on Mac OS X