I think we’re saying that it’s been 30+ years since .rodata instead of .text has been the section for read-only data and that your software will be *more* portable (particularly looking to the future) if it uses .rodata instead of .text for data it wants to read-and-not-execute.
I guess you could write a configure test for “doesn’t have working .rodata so use .text instead” but it was the previous millenium when I last saw a working system like that… Philip Guenther On Saturday, July 27, 2024, Shein Asker <sheinas...@gmail.com> wrote: > Dear Mr. Claudio, @misc readers, > > Thank you for your prompt reply. > > I see, OpenBSD has a restriction that .text segments are executable-only > mapped. > > In porting the software, I would like to make work-around modifications, > preferably without modifying the source. > Does OpenBSD provide a way to loosen these restrictions? > > On Sat, Jul 27, 2024 at 10:22 PM Claudio Jeker <cje...@diehard.n-r-g.com> > wrote: > >> On Sat, Jul 27, 2024 at 08:14:42PM +0900, Shein Asker wrote: >> > Dear @misc readers, >> > >> > I have recently started using OpenBSD and have encountered the problem >> > shown in the subject when porting a software used on Linux to OpenBSD. >> > The problem is outlined as follows: SEGV occurs when trying to read huge >> > size data placed in a .text section that exceeds the `PAGE_SIZE` by a >> large >> > amount. >> > >> > My environments are as follows: >> > machine: >> > 1. QEMU/KVM x86_64 6.2.0 >> > 2. Dynabook R63/J (Intel Core i5-7300U) >> > OS: OpenBSD 7.5 >> > compiler: clang 16.0.6 >> > >> > Below is the minimal code that reproduces the problem. >> > https://github.com/sheinasker/data-asm/tree/main >> > >> > What this code does is to copy the contents of a global string variable >> > defined in the assembler to a dynamically allocated area and display the >> > address, size, and leading and trailing data. The entity of >> `sample_code` >> > is defined in assembler and its content is a string of 12289 bytes >> filled >> > with 'A'. The SEGV occurs in the part of the code below that executes >> > `memcpy`. >> > >> > ```cpp >> > #include <iostream> >> > #include <string> >> > #include <cstring> >> > >> > extern "C" char sample_code[]; >> > extern "C" std::uint32_t sample_code_size; >> > >> > int main() { >> > std::cout << "address: " << reinterpret_cast<void*>(sample_code) << >> > std::endl; >> > char* buf = (char*)std::malloc(sample_code_size); >> > >> > // SEGV >> > std::memcpy(buf, sample_code, sample_code_size); >> > >> > std::cout << "size: " << std::strlen(buf) << std::endl; >> > std::cout << "head: " << std::string(buf, buf + 10) << std::endl; >> > std::cout << "tail: " << std::string(buf + sample_code_size - 11, >> buf + >> > sample_code_size - 1) << std::endl; >> > } >> > ``` >> > >> > Running it with `make run1`, you will see that it crashes with SIGSEGV. >> > >> > The log when debugging with `lldb` is as follows: >> > ``` >> > openbsd-host$ lldb sample1 >> > (lldb) target create "sample1" >> > Current executable set to '/home/asker/src/data-asm/sample1' (x86_64). >> > (lldb) b main >> > Breakpoint 1: where = sample1`main, address = 0x0000000000006410 >> > (lldb) run >> > Process 8967 launched: '/home/asker/src/data-asm/sample1' (x86_64) >> > Process 8967 stopped >> > * thread #1, stop reason = breakpoint 1.1 >> > frame #0: 0x00000befee364410 sample1`main >> > sample1`main: >> > -> 0xbefee364410 <+0>: endbr64 >> > 0xbefee364414 <+4>: movq 0x372d(%rip), %r11 ; >> __retguard_831 >> > 0xbefee36441b <+11>: xorq (%rsp), %r11 >> > 0xbefee36441f <+15>: pushq %rbp >> > (lldb) c >> > Process 8967 resuming >> > address: 0xbefee361400 >> > Process 8967 stopped >> > * thread #1, stop reason = signal SIGSEGV >> > frame #0: 0x00000bf2b0c282b0 >> > libc.so.99.0`memcpy(dst0=0x00000bf29066c000, src0=<unavailable>, >> > length=12289) at memcpy.c:103:2 >> > (lldb) c >> > Process 8967 resuming >> > Process 8967 exited with status = 11 (0x0000000b) >> > (lldb) q >> > ``` >> > >> > At the same time, the history of system calls was also recorded by >> > `ktrace`, so that is also shown. >> > ``` >> > 8967 sample1 CALL kbind(0x6fe6698ee708,24,0x3e7ebd77b6a5befb) >> > 8967 sample1 RET kbind 0 >> > 8967 sample1 CALL kbind(0x6fe6698ee6b8,24,0x3e7ebd77b6a5befb) >> > 8967 sample1 RET kbind 0 >> > 8967 sample1 CALL kbind(0x6fe6698ee628,24,0x3e7ebd77b6a5befb) >> > 8967 sample1 RET kbind 0 >> > 8967 sample1 CALL kbind(0x6fe6698ee608,24,0x3e7ebd77b6a5befb) >> > 8967 sample1 RET kbind 0 >> > 8967 sample1 CALL kbind(0x6fe6698ee628,24,0x3e7ebd77b6a5befb) >> > 8967 sample1 RET kbind 0 >> > 8967 sample1 CALL kbind(0x6fe6698ee5d8,24,0x3e7ebd77b6a5befb) >> > 8967 sample1 RET kbind 0 >> > 8967 sample1 CALL >> > mprotect(0xbf24ee36000,0x1000,0x3<PROT_READ|PROT_WRITE>) >> > 8967 sample1 RET mprotect 0 >> > 8967 sample1 CALL mprotect(0xbf24ee36000,0x1000,0x1<PROT_READ>) >> > 8967 sample1 RET mprotect 0 >> > 8967 sample1 CALL fstat(1,0x6fe6698ee500) >> > 8967 sample1 STRU struct stat { dev=0, ino=104192, mode=crw--w---- , >> > nlink=1, uid=1000<"asker">, gid=4<"tty">, rdev=1283, >> atime=1722062206<"Jul >> > 27 15:36:46 2024">.276320559, mtime=1722062206<"Jul 27 15:36:46 >> > 2024">.276320559, ctime=1722062206<"Jul 27 15:36:46 2024">.276320559, >> > size=0, blocks=0, blksize=65536, flags=0x0, gen=0x0 } >> > 8967 sample1 RET fstat 0 >> > 8967 sample1 CALL >> > mmap(0,0x10000,0x3<PROT_READ|PROT_WRITE>,0x1002<MAP_ >> PRIVATE|MAP_ANON>,-1,0) >> > 8967 sample1 RET mmap 13137847422976/0xbf2e4ba9000 >> > 8967 sample1 CALL fcntl(1,F_ISATTY) >> > 8967 sample1 RET fcntl 1 >> > 8967 sample1 CALL kbind(0x6fe6698ee6b8,24,0x3e7ebd77b6a5befb) >> > 8967 sample1 RET kbind 0 >> > 8967 sample1 CALL kbind(0x6fe6698ee798,24,0x3e7ebd77b6a5befb) >> > 8967 sample1 RET kbind 0 >> > 8967 sample1 CALL kbind(0x6fe6698ee738,24,0x3e7ebd77b6a5befb) >> > 8967 sample1 RET kbind 0 >> > 8967 sample1 CALL kbind(0x6fe6698ee738,24,0x3e7ebd77b6a5befb) >> > 8967 sample1 RET kbind 0 >> > 8967 sample1 CALL kbind(0x6fe6698ee668,24,0x3e7ebd77b6a5befb) >> > 8967 sample1 RET kbind 0 >> > 8967 sample1 CALL kbind(0x6fe6698ee568,24,0x3e7ebd77b6a5befb) >> > 8967 sample1 RET kbind 0 >> > 8967 sample1 CALL kbind(0x6fe6698ee738,24,0x3e7ebd77b6a5befb) >> > 8967 sample1 RET kbind 0 >> > 8967 sample1 CALL kbind(0x6fe6698ee738,24,0x3e7ebd77b6a5befb) >> > 8967 sample1 RET kbind 0 >> > 8967 sample1 CALL write(1,0xbf2e4ba9000,0x17) >> > 8967 sample1 GIO fd 1 wrote 23 bytes >> > "address: 0xbefee361400 >> > " >> > 8967 sample1 RET write 23/0x17 >> > 8967 sample1 CALL kbind(0x6fe6698ee738,24,0x3e7ebd77b6a5befb) >> > 8967 sample1 RET kbind 0 >> > 8967 sample1 CALL kbind(0x6fe6698ee6a8,24,0x3e7ebd77b6a5befb) >> > 8967 sample1 RET kbind 0 >> > 8967 sample1 CALL kbind(0x6fe6698ee798,24,0x3e7ebd77b6a5befb) >> > 8967 sample1 RET kbind 0 >> > 8967 sample1 CALL >> > mmap(0,0x4000,0x3<PROT_READ|PROT_WRITE>,0x1002<MAP_ >> PRIVATE|MAP_ANON>,-1,0) >> > 8967 sample1 RET mmap 13136432644096/0xbf29066c000 >> > 8967 sample1 CALL kbind(0x6fe6698ee798,24,0x3e7ebd77b6a5befb) >> > 8967 sample1 RET kbind 0 >> > 8967 sample1 PSIG SIGSEGV SIG_DFL code=SEGV_ACCERR >> addr=0xbefee362000 >> > trapno=6 >> > 8967 sample1 NAMI "sample1.core" >> > ``` >> > >> > As these logs show, the first address of `sample_code` is 0xbefee361400 >> and >> > the first 3072 bytes can be read, but a SEGV occurs when trying to read >> > 0xbefee362000. Looking at the address values, it appears that this >> issue is >> > happening at the boundary of the page. >> > Oddly enough, if I run the same executable directly after debugging with >> > lldb, it succeeds, but when I recompile it, the symptoms return. >> > >> > >> > I want to know two things. >> > - Whether this behavior is due to OpenBSD's protection feature (i.e., >> > whether it is an OpenBSD specification). >> > - How to resolve this. >> > >> > >> > As a supplement, when I ran the exact same code on Ubuntu and FreeBSD, >> no >> > problems occurred. >> >> On OpenBSD .text segments are mapped execute only. If your hardware >> support X-only it will crash immediatly, on systems without X-only support >> the vm fault handler does the check. This is why it crashes on the page >> boundary. >> >> You need to put data into the .data or .rodata section. End of story. >> >> -- >> :wq Claudio >> >