MEE
MEE

Reputation: 2412

Code (.text) not execute-only? .rodata is executable?

I am trying to understand how ELF segments are memory mapped. I noticed that various sections are mapped to the same ELF segment. For example, .rodata is mapped to the same segment as .text.

Why is this the case? Why not map .rodata to a separate read-only and not executable segment?

Also, what does it entail to map the .text section to an "execute ONLY" segment (not readable)? Are there any kernel/HW limitations that may hinder this?

EDIT: I may as well add that I am using the GNU linker, if that makes a difference.

Upvotes: 6

Views: 2911

Answers (3)

yuanjianpeng
yuanjianpeng

Reputation: 328

section and segment are two different concept, program load use segment, you can even strip section table. a segment can contain multiple sections. .rodata and .text both are read only. so they can be put to same segment.

Upvotes: -1

Iwillnotexist Idonotexist
Iwillnotexist Idonotexist

Reputation: 13457

Gathered from comments above

It is not possible on several computer architectures, including x86-64, to mark memory as executable but not readable.

While x86 16- and 32-bit did allow segmentation in legacy modes, and memory segments could in theory be used to mark memory as executable-only, the benefits of a flat address space were so great that x86-64 now mostly ignores its segments registers:

3.2.4 Segmentation in IA-32e Mode

In IA-32e mode of Intel 64 architecture, the effects of segmentation depend on whether the processor is running in compatibility mode or 64-bit mode. In compatibility mode, segmentation functions just as it does using legacy 16-bit or 32-bit protected mode semantics.

In 64-bit mode, segmentation is generally (but not completely) disabled, creating a flat 64-bit linear-address space. The processor treats the segment base of CS, DS, ES, SS as zero, creating a linear address that is equal to the effective address. The FS and GS segments are exceptions. These segment registers (which hold the segment base) can be used as additional base registers in linear address calculations. They facilitate addressing local data and certain operating system data structures.

Note that the processor does not perform segment limit checks at runtime in 64-bit mode.

Kernels thus simply set their segments to cover the entire address space and do not rely on segmentation to achieve memory protection.

What they do use is the page table's attributes. Every page that exists in a process's memory map has a page table entry governing access to it. An overview of their format can be seen here, but most crucially there are two bits that control what type of access is permitted:

  • Bit 1 (R/W): 0 indicates read-only, 1 indicates read-write.
  • Bit 63 (XD): 0 indicates executable, 1 indicates non-executable.

It is not possible to indicate an executable-noread-nowrite combination with these flags. If the page is at all present in the memory map, it must be readable.

A solution is fast approaching in Intel's latest microarchitecture, Skylake, which will allow execute-only memory: It is the feature baptized MPK (memory protection keys), support for which landed in Linux kernel 4.6 just recently released. The keys occupy the four bits 62:59 of the page table entry, and areas of memory can be tagged with a key indicating execute-noread-nowrite access.

Upvotes: 8

Zang MingJie
Zang MingJie

Reputation: 5275

% objdump -h /bin/ls

/bin/ls:     file format elf64-x86-64

Sections:     
Idx Name          Size      VMA               LMA               File off  Algn
  0 .interp       0000001c  0000000000400238  0000000000400238  00000238  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .note.ABI-tag 00000020  0000000000400254  0000000000400254  00000254  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .note.gnu.build-id 00000024  0000000000400274  0000000000400274  00000274  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .gnu.hash     000000c0  0000000000400298  0000000000400298  00000298  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .dynsym       00000cd8  0000000000400358  0000000000400358  00000358  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .dynstr       000005dc  0000000000401030  0000000000401030  00001030  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .gnu.version  00000112  000000000040160c  000000000040160c  0000160c  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .gnu.version_r 00000070  0000000000401720  0000000000401720  00001720  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .rela.dyn     000000a8  0000000000401790  0000000000401790  00001790  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .rela.plt     00000a98  0000000000401838  0000000000401838  00001838  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 10 .init         0000001a  00000000004022d0  00000000004022d0  000022d0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 11 .plt          00000720  00000000004022f0  00000000004022f0  000022f0  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 12 .text         0001112a  0000000000402a10  0000000000402a10  00002a10  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 13 .fini         00000009  0000000000413b3c  0000000000413b3c  00013b3c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 14 .rodata       00006754  0000000000413b80  0000000000413b80  00013b80  2**6
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 15 .eh_frame_hdr 0000081c  000000000041a2d4  000000000041a2d4  0001a2d4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 16 .eh_frame     00002c7c  000000000041aaf0  000000000041aaf0  0001aaf0  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 17 .init_array   00000008  000000000061de00  000000000061de00  0001de00  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 18 .fini_array   00000008  000000000061de08  000000000061de08  0001de08  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 19 .jcr          00000008  000000000061de10  000000000061de10  0001de10  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 20 .dynamic      000001e0  000000000061de18  000000000061de18  0001de18  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 21 .got          00000008  000000000061dff8  000000000061dff8  0001dff8  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 22 .got.plt      000003a0  000000000061e000  000000000061e000  0001e000  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 23 .data         000002a0  000000000061e3c0  000000000061e3c0  0001e3c0  2**6
                  CONTENTS, ALLOC, LOAD, DATA
 24 .bss          00000e08  000000000061e680  000000000061e680  0001e660  2**6
                  ALLOC

Each section has its own attrs, like READONLY, CONTENTS, ALLOC, LOAD, DATA

sections with same attrs can be mapped together.

According to elf format

   sh_flags  Sections support one-bit flags that describe miscellaneous
             attributes.  If a flag bit is set in sh_flags, the
             attribute is "on" for the section.  Otherwise, the
             attribute is "off" or does not apply.  Undefined attributes
             are set to zero.

             SHF_WRITE      This section contains data that should be
                            writable during process execution.

             SHF_ALLOC      This section occupies memory during process
                            execution.  Some control sections do not
                            reside in the memory image of an object
                            file.  This attribute is off for those
                            sections.

             SHF_EXECINSTR  This section contains executable machine
                            instructions.

             SHF_MASKPROC   All bits included in this mask are reserved
                            for processor-specific semantics.

ELF has SHF_EXECINSTR section attr, so it is the compiler or link doesn't set the attr.

Upvotes: -1

Related Questions