FreeBSD 13.0-RELEASE is out, and one of the new features is W^X memory mapping policy for user processes. This feature is also naturally available for users of 13.0-STABLE and 14.0-CURRENT.

Enable the feature by adding these lines to /etc/sysctl.conf:

kern.elf32.allow_wx=0
kern.elf64.allow_wx=0

For immediate effect, run these commands as root:

sysctl kern.elf32.allow_wx=0
sysctl kern.elf64.allow_wx=0

It’s possible to mark an executable as needing its pages to be both executable and writable:

# elfctl -e +wxneeded /usr/local/bin/synth
# elfctl -e +wxneeded /usr/local/lib/libreoffice/program/soffice.bin

Checking the results, reveals:

$ elfctl /usr/local/bin/synth
File '/usr/local/bin/synth' features:
noaslr          'Disable ASLR' is unset.
noprotmax       'Disable implicit PROT_MAX' is unset.
nostackgap      'Disable stack gap' is unset.
wxneeded        'Requires W+X mappings' is set.
la48            'amd64: Limit user VA to 48bit' is unset.
noaslrstkgap    'Disable ASLR stack gap' is unset.

$ elfctl /usr/local/lib/libreoffice/program/soffice.bin
File '/usr/local/lib/libreoffice/program/soffice.bin' features:
noaslr          'Disable ASLR' is unset.
noprotmax       'Disable implicit PROT_MAX' is unset.
nostackgap      'Disable stack gap' is unset.
wxneeded        'Requires W+X mappings' is set.
la48            'amd64: Limit user VA to 48bit' is unset.
noaslrstkgap    'Disable ASLR stack gap' is unset.

A few ports are unable to be built or live under such restrictions. So far, the list includes:

  • editors/libreoffice
  • java/openjdk8
  • lang/mono
  • ports-mgmt/synth

My shell script for building packages re-enables kern.elf64.allow_wx before running ports-mgmt/synth. An exit handler in the same script will disable kern.elf64.allow_wx once all packages are built.

Here’s a shell script I concocted to mark the /usr/local/bin/synth executable as needing write and execute:

#!/bin/sh
#set -x
set -eu -o pipefail

# Disable wx system-wide:
# sysctl kern.elf64.allow_wx=0
# sysctl kern.elf32.allow_wx=0

# Enable wx system-wide:
# sysctl kern.elf64.allow_wx=1
# sysctl kern.elf32.allow_wx=1

ELFCTL="elfctl"
GREP="grep"
SYNTH="/usr/local/bin/synth"

if ! ${ELFCTL} ${SYNTH} | ${GREP} "wxneeded" | ${GREP} -q "unset"; then
  echo "${0}: wxneeded is already set on ${SYNTH}."
  exit
fi

echo "${0}: elfctl(1) feature flags on ${SYNTH} before any changes:"
${ELFCTL} ${SYNTH}
echo

echo "${0}: Setting wxneeded on ${SYNTH} ..."
${ELFCTL} -e +wxneeded ${SYNTH}
echo "... done."
echo

echo "${0}: elfctl(1) feature flags afterwards:"
${ELFCTL} ${SYNTH}

# EOF

On a related noted, if you use ASLR, then Firefox must be allowed to run without ASLR.

#!/bin/sh
#set -x
set -eu -o pipefail

# Disable aslr system-wide:
# sysctl kern.elf64.aslr.enable=0
# sysctl kern.elf32.aslr.enable=0

# Enable aslr system-wide:
# sysctl kern.elf64.aslr.enable=1
# sysctl kern.elf32.aslr.enable=1

ELFCTL="elfctl"
GREP="grep"
FIREFOX="/usr/local/lib/firefox/firefox"

if ! ${ELFCTL} ${FIREFOX} | ${GREP} "noaslr " | ${GREP} -q "unset"; then
  echo "${0}: noaslr is already set on ${FIREFOX}."
  exit
fi

echo "${0}: elfctl(1) feature flags on ${FIREFOX} before any changes:"
${ELFCTL} ${FIREFOX}
echo

echo "${0}: Setting noaslr on ${FIREFOX} ..."
${ELFCTL} -e +noaslr ${FIREFOX}
echo "... done."
echo

echo "${0}: elfctl(1) feature flags afterwards:"
${ELFCTL} ${FIREFOX}

# EOF

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>