Se refiere a una política en los permisos de las secciones de un programa en OpenBSD. Una sección ejecutable no puede ser escribible, y una sección escribible no puede ser ejecutable.

Esto descarta programas que intentan automodificarse y programas que pretendan ejecutar instrucciones entre los datos.

A continuación se presentan 2 programas que ponen a prueba esta política.

Programa que intenta modificarse

 .intel_syntax noprefix

.section ".note.openbsd.ident", "a"
        .p2align   2
        .long      8,4,1
        .ascii      "OpenBSD\0"
        .long      0

.global _start

.global puts
.global exit

.text
_start:

  # Lo siguiente usaría libc
  lea rdi, [rip + hola]
  mov rsi, rdi
  call puts@plt

  # Modificamos cadena por imprimir e imprimimos
  mov rdi,rsi 
  movb [rdi], 65
  call puts@plt

  # Mostramos algunos bytes del programa (usando gdb determinamos el 28 del inicio al call
  lea rdi, [rip - 33]
  call puts@plt

   # Intentamos modificar primer byte del programa y mostrar
  lea rdi, [rip - 45]
  movb [rdi], 66  # En esta instrucción se produce un SIGSEGV
  call puts@plt

  # Terminar
  xor rdi, rdi
  call exit@plt

.data
hola:
    .asciz "Hola mundo!\n\0"

Si llamamos automod.s a este programa, podemos compilarlo con:

export N=automod; as -gstabs+ $N.s -o $N.o; ld  --dynamic-linker=/usr/libexec/ld.so -pie -L/usr/lib -lc $N.o -o $N; 

y su ejecución detallando llamados al sistema puede verse con:

ktrace ./$N; kdump

Que generará:

Hola Mundo!
        
Aola Mundo!
        
H=!
zsh: segmentation fault (core dumped) 
...
 19739 automod  CALL  fcntl(1,F_ISATTY)
 19739 automod  RET   fcntl 1
 19739 automod  CALL  write(1,0x942be953000,0xc)
 19739 automod  GIO   fd 1 wrote 12 bytes
 "Hola mundo!
 "
 19739 automod  RET   write 12/0xc
 19739 automod  CALL  write(1,0x942be953000,0x1)
 19739 automod  GIO   fd 1 wrote 1 bytes
 "
 "
 19739 automod  RET   write 1
 19739 automod  CALL  write(1,0x942be953000,0xc)
 19739 automod  GIO   fd 1 wrote 12 bytes
 "Aola mundo!
 19739 automod  RET   write 12/0xc
 19739 automod  CALL  write(1,0x942be953000,0x1)
 19739 automod  GIO   fd 1 wrote 1 bytes
 "
 "
 19739 automod  RET   write 1
 19739 automod  CALL  write(1,0x942be953000,0x6)
 19739 automod  GIO   fd 1 wrote 6 bytes
 "H\M^M=\M-9!
 "
 19739 automod  RET   write 6
 19739 automod  PSIG  SIGSEGV SIG_DFL code=SEGV_ACCERR addr=0x940ab6bf398 trapno=6
 19739 automod  NAMI  "automod.core"

Programa que pretende ejecutar código entre sus datos

 .intel_syntax noprefix

.section ".note.openbsd.ident", "a"
        .p2align   2
        .long      8,4,1
        .ascii      "OpenBSD\0"
        .long      0

.global _start

.global puts
.global exit

.text
_start:

  # Lo siguiente usaría libc para mostrar prop
  lea rdi, [rip + prop]
  push rdi
  mov rsi, rdi
  call puts@plt

  # Copiamos de _start a prop
  pop rdi
  push rdi
  lea rsi, [rip - 25]  # 25 calculado experimentado con egdb
  mov rcx, 10
  rep
  movsb

  # Imprimimos tras copiar
  pop rdi
  push rdi
  call puts@plt

  pop rdi
  jmp [rdi]  # Producirá un SIGSEGV

  # Terminar
  xor rdi, rdi
  call exit@plt

.data
prop:
    .asciz "Por sobreescribir con código binario que imprime\n\0"
hola:
    .asciz "Hola mundo!\n\0"

Si llamamos xdat.s a este programa, podemos compilarlo con:

export N=xdat; as -gstabs+ $N.s -o $N.o; ld  --dynamic-linker=/usr/libexec/ld.so -pie -L/usr/lib -lc $N.o -o $N; 

y ejecutarlo con ktrace con:

ktrace ./xdat; kdump

que produce

  Por sobreescribir con código binario que imprime
  H=!                                          
  zsh: segmentation fault (core dumped)  ktrace ./xdat
  ...
  9755 xdat     CALL  fcntl(1,F_ISATTY)
  9755 xdat     RET   fcntl 1
  9755 xdat     CALL  write(1,0x3e9ef3d4000,0x32)
  9755 xdat     GIO   fd 1 wrote 50 bytes
       "Por sobreescribir con c\M-C\M-3digo binario que imprime
       "
  9755 xdat     RET   write 50/0x32
  9755 xdat     CALL  write(1,0x3e9ef3d4000,0x1)
  9755 xdat     GIO   fd 1 wrote 1 bytes
       "
       "
  9755 xdat     RET   write 1
  9755 xdat     CALL  write(1,0x3e9ef3d4000,0x6)
  9755 xdat     GIO   fd 1 wrote 6 bytes
       "H\M^M=\M-)!
       "
  9755 xdat     RET   write 6
  9755 xdat     PSIG  SIGSEGV SIG_DFL code=SEGV_MAPERR addr=0x3e705a153c2 trapno=4
  9755 xdat     NAMI  "xdat.core"

Al ejecutar

readelf -t xdat

Vemos que la sección text permite ejecución pero no escritura mientras que la sección data no permite ejecución pero si escritura:

 ...
 [ 8] .text
       PROGBITS         0000000000001398  0000000000000398  0
       0000000000000034 0000000000000000  0                 4
       [0000000000000006]: ALLOC, EXEC
 ...
 
  [12] .data
       PROGBITS         0000000000003548  0000000000000548  0
       0000000000000042 0000000000000000  0                 4
       [0000000000000003]: WRITE, ALLOC

Conclusión

Los binarios ELF producidos en OpenBSD con sus herramientas estándar (experimentado con 7.4 sobre amd64) implementan la política W^X en sus secciones.