Modify SIP in normally booted system

I have MacBook Pro (2017) with macOS High Sierra (10.13.6). I have SIP and amfi disabled. I want to enable a part / the majority of SIP (e.g. csrutil enable --without fs) without having to reboot into the recovery partition and run the csrutil command there.

I tried to modify the nvram variable csr-active-config using nvram csr-active-config="w%01%00%00", but it returned an error: nvram: Error setting variable - 'csr-active-config': (iokit/common) general error. Modifying the variable name gave successful result:

# nvram ccsr-active-config="w%01%00%00"
# nvram ccsr-active-config
ccsr-active-config  w%01%00%00

Which indicated that there is still something protecting the SIP configuration even when SIP is completely disabled:

# csrutil status
System Integrity Protection status: disabled.

Note that I can change boot-args variable with nvram because I disabled SIP:

# nvram boot-args="amfi_get_out_of_my_way=0x1"
# nvram boot-args
boot-args   amfi_get_out_of_my_way=0x1

There is only one relevant log message while setting SIP nvram:

ERROR 09:47:22.096544 +0800 kernel  Sandbox: nvram(92857) System Policy: deny(1) nvram-set csr-active-config

Is it possible to change SIP configuration to become stricter (not less strict) booting into Recovery OS?

Preferably, the solution can enforce SIP configuration as soon as it's changed. The following logs in Console when I do chmod -x /bin/ls make me think it's possible:

INFO    11:07:38.852242 +0800   sandboxd    Symbolicator for chmod[94599] is NULL.
ERROR   11:07:38.862934 +0800   sandboxd    Failed to produce a full report for: chmod[94599].
ERROR   11:07:38.863015 +0800   sandboxd    Sandbox: chmod(94599) System Policy: allow file-write-mode /bin/ls

Your Mac can be configured so that you can enable a part / the majority of SIP without having to reboot into the recovery partition and run the csrutil command there. However, a reboot of macOS will still be necessary for any changes to take effect. This answer proposes one such configuration for use with Intel Macs. Although, adaption for use with Apple Silicon Macs seems theoretically possible.

The csrutil command sets the firmware NVRAM variable csr-active-config. The macOS operating system reads this 32 bit integer variable at startup to determine which parts of SIP to enable. Instead of using the csrutil command, this answer uses a bash script named mkcsrfile to create a csr.bin file containing the desired value for the csr-active-config variable. The format of this file is defined in this answer. Instead of booting to macOS by default, this answer changes the default to boot an UEFI Shell instead. This shell executes a script stored in the file startup.nsh. This script first copies the csr-active-config value from the csr.bin file to NVRAM, then boots macOS.

The bits of the csr-active-config variable are defined in the csr.h file. A version of this file can be found in opensource.apple.com. This developer.apple.com thread defines some additional csrutil arguments for the enable command. The relationship between these bits and select csrutil commands and arguments is summarized in the table below for macOS High Sierra version 10.13.6.

Note: The table below can vary between versions of macOS (OS X). For example, the table for Big Sur and Monterey can be found at this answer.

csrutil
commands
with
optional
arguments
csr-
active-
config
CSR_
ALLOW_
UNTRUSTED_
KEXTS
=0x001
CSR_
ALLOW_
UNRESTRICTED_
FS
=0x002
CSR_
ALLOW_
TASK_
FOR_
PID
=0x004
CSR_
ALLOW_
KERNEL_
DEBUGGER
=0x008
CSR_
ALLOW_
APPLE_
INTERNAL
=0x010
CSR_
ALLOW_
UNRESTRICTED_
DTRACE
=0x020
CSR_
ALLOW_
UNRESTRICTED_
NVRAM
=0x040
CSR_
ALLOW_
DEVICE_
CONFIGURATION
=0x080
CSR_
ALLOW_
ANY_
RECOVERY_
OS
=0x100
CSR_
ALLOW_
UNAPPROVED_
KEXTS
=0x200
CSR_
ALLOW_
EXECUTABLE_
POLICY_
OVERRIDE
=0x400
enable 0x00000010
enable ‑‑no‑internal 0x00000000
enable ‑‑without
kext
0x00000011
enable ‑‑without
fs
0x00000012
enable ‑‑without
debug
0x00000014
enable ‑‑without
dtrace
0x00000030
enable ‑‑without
nvram
0x00000050
disable 0x00000077

Examples of Use

Once the Mac is configured, the mkcsrfile command can be used from macOS. Some examples are given below.

  • Enable except for fs and internal.

    The csr-active-config variable needs to be set 0x00000012, which can be done from macOS Recovery by using the command shown below.

     csrutil enable --without fs
    

    This answer offers the following command, which can be entered from macOS, as one possible replacement for the above command.

     mkcsrfile 0x12
    
  • Enable except for fs, debug, dtrace and internal.

    The csr-active-config variable needs to be set 0x00000036, which can be done from macOS Recovery by using the command shown below.

     csrutil enable --without fs --without debug --without dtrace
    

    Any one of the following commands, which can be entered from macOS, could be used to replace the above command. The first command shown below has three arguments which will be ORed together bitwise by the mkcsrfile script.

     mkcsrfile 0x12 0x14 0x30
    

    Instead, a single argument can be used, where the bitwise OR operations are explicitly entered. This shown in the command below.

     mkcsrfile "0x12|0x14|0x30"
    

    Finally, you could perform the bitwise OR operations yourself and just enter the result, as shown below.

     mkcsrfile 0x36
    
  • Enable except for fs, debug and dtrace.

    The csr-active-config variable needs to be set 0x00000026, which can be done from macOS Recovery by using the command shown below.

    Note: The --no-internal option sets the CSR_ALLOW_APPLE_INTERNAL (0x10) bit to zero.

     csrutil enable --no-internal --without fs --without debug --without dtrace
    

    Any one of the following commands, which can be entered from macOS, could be used to replace the above command. The first command shown below has three arguments which will be ORed together bitwise by the mkcsrfile script. Here, each argument has the CSR_ALLOW_APPLE_INTERNAL (0x10) bit set to zero,

     mkcsrfile 2 4 0x20
    

    Instead, a single argument can be used, where the bitwise operations are explicitly entered. This shown in the command below.

     mkcsrfile "~10&(0x12|0x14|0x30)"
    

    Finally, you could perform the bitwise operations yourself and just enter the result, as shown below.

     mkcsrfile 0x26
    

Steps to Configure an Intel Mac

  1. Download an UEFI Shell v1.

    The Arch Linux wiki web site section Obtaining UEFI Shell provides a link to Precompiled UEFI Shell v1 binaries from TianoCore. Since you have a Intel-based Mac, you will need to download the X64 version of the Shell_Full.efi file to your Downloads folder.

    Note: If any user can confirm that the Arm version works on a Mac with Apple silicon, then post a comment so this answer can be updated.

  2. Install UEFI Shell binary and startup script files to the EFI partition.

    Create a file containing the UEFI shell script shown below. Save as startup.nsh in your Downloads folder.

    @echo -off
    set -v uuid E43602C1-8CFF-4F74-AEC7-98E645C7BBEE
    set -v file csr.bin
    if "%StartupDelay%" == "" then
        set StartupDelay 0
    endif
    set -v found nothing
    for %a in "" 1 2 3 4 5 6
      for %b in 0 1 2 3 4 5 6 7 8 9 a b c d e f
        if not %found% == boot then
          if exist fs%a%b:\%uuid%\System\Library\CoreServices\boot.efi then
            alias -v macos fs%a%b:\%uuid%\System\Library\CoreServices\boot.efi
            if %found% == startup then
              goto BREAK
            endif
            set -v found boot
          endif
        endif
        if not %found% == startup then
          if exist fs%a%b:\EFI\BOOT\startup.nsh then
            fs%a%b:
            cd \EFI\BOOT
            if exist %file% then
              dmpstore -l %file%
              rm %file%
            endif
            if %found% == boot then
              goto BREAK
            endif
            set -v found startup
          endif
        endif
      endfor
    endfor
    alias -v macos "echo ^"Missing macOS^""
    :BREAK
    macos
    ver
    ver -s
    

    Next, you will need replace the UUID of E43602C1-8CFF-4F74-AEC7-98E645C7BBEE in the startup.nsh file with the volume UUID shown in the output from the command below.

    diskutil info / | grep "Volume UUID"
    

    Finally, enter the commands below to install the shell and script files to the EFI partition. If the desired EFI partition is not disk0s1, then make the appropriate substitutions.

    cd ~/Downloads
    sudo diskutil mount disk0s1
    mkdir -p /Volumes/EFI/EFI/BOOT
    bless --folder /Volumes/EFI/EFI/BOOT --label "UEFI Shell"
    mv Shell_Full.efi /Volumes/EFI/EFI/BOOT/bootx64.efi
    mv startup.nsh /Volumes/EFI/EFI/BOOT/.
    dot_clean -m /Volumes/EFI/EFI/BOOT
    diskutil unmount disk0s1
    
  3. Install mkcsrfile command as a bash script.

    Create a file containing the bash script shown below. Save as mkcsrfile in your Downloads folder,

    #!/bin/bash
    if [[ $0 != "$BASH_SOURCE" ]]; then
        bash "$BASH_SOURCE" "$@"
    fi
    trap exit ERR
    main() {
      local "file=/Volumes/EFI/EFI/BOOT/csr.bin"
      local "unmount=no" "value=0" operand data
      if [[ ! -e /Volumes/EFI ]]; then 
        sudo diskutil mount disk0s1
        unmount="yes"
      fi
      for operand in "$@"; do
        value="$((value|($operand)))"
      done
      printf -v value "%08X" "$value"
      echo "Setting to 0x$value"
      data="240000006300730072002d006100630074006900760065002d0063006f00"
      data+="6e0066006900670000001061437c2aabbb4ba880fe41995c9f8207000000"
      data+="04000000${value:6}${value:4:2}${value:2:2}${value::2}"
      xxd -r -p - "$file" <<<"$data"
      if [[ $unmount == yes ]]; then
        sleep 0.1
        diskutil unmount disk0s1
      fi
    }
    main "$@"
    

    Next, if the desired EFI partition is not disk0s1, then replace the two occurrences of the disk0s1 identifier in the mkcsrfile file with the desired EFI partition identifier.

    Finally, enter the commands below to install the mkcsrfile file to the /usr/local/bin folder.

    cd ~/Downloads
    chmod 755 mkcsrfile
    sudo chown root:wheel mkcsrfile
    sudo mkdir -p /usr/local/bin
    sudo mv mkcsrfile /usr/local/bin/.
    sudo xattr -c /usr/local/bin/mkcsrfile
    
  4. Change the default to boot from the UEFI shell.

    Restart the Mac and immediately hold down the option key until the Mac Startup Manager icons appear. Next, hold down the control key while selecting to boot from the "UEFI Shell".

    Note: When you first boot from the UEFI Shell there will be a startup delay. There should be no delay on subsequent boots.