{"uuid": "0b62c7a8-432e-40aa-adb5-f33ae3a22813", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-31431", "type": "seen", "source": "https://gist.github.com/inmediasit/a0387a5d338969501c2ef41d5886397d", "content": "---\n# Mitigation for \"Dirty Frag\" (xfrm-ESP Page-Cache Write + RxRPC Page-Cache Write LPE)\n# https://dirtyfrag.io / https://github.com/V4bel/dirtyfrag\n#\n# Apply:  ansible-playbook playbooks/dirtyfrag-mitigation.yml\n# Remove: once the vendor kernel is patched, delete the modprobe conf and reload modules.\n#\n# NOTE: Unlike Copy Fail (CVE-2026-31431), the algif_aead / AF_ALG mitigation is\n# NOT sufficient here.  The xfrm-ESP sink is reachable regardless of algif_aead.\n# This playbook can be applied in addition to the Copy Fail playbook.\n#\n# Affected: kernels &gt;= cac2661c53f3 (2017-01-17) for esp4/esp6\n#                   &gt;= 2dc334f1a63a (2023-06)    for rxrpc\n# Tested on: Ubuntu 24.04, RHEL/AlmaLinux 10, Fedora 44, openSUSE Tumbleweed, CentOS Stream 10\n\n- hosts: all\n  gather_facts: true\n  become: yes\n\n  tasks:\n    # ------------------------------------------------------------------ #\n    # 1. Block the three vulnerable modules via modprobe blacklist         #\n    # ------------------------------------------------------------------ #\n\n    - name: Install modprobe blacklist for esp4, esp6, rxrpc\n      ansible.builtin.copy:\n        dest: /etc/modprobe.d/dirtyfrag.conf\n        owner: root\n        group: root\n        mode: '0644'\n        content: |\n          # Dirty Frag mitigation \u2014 block vulnerable kernel modules.\n          # xfrm-ESP Page-Cache Write (esp4/esp6) and RxRPC Page-Cache Write (rxrpc)\n          # Remove once the vendor kernel ships a fix.\n          install esp4  /bin/false\n          install esp6  /bin/false\n          install rxrpc /bin/false\n\n    # ------------------------------------------------------------------ #\n    # 2. Unload the modules if currently loaded                           #\n    #    (rmmod fails gracefully when the module isn't present)           #\n    # ------------------------------------------------------------------ #\n\n    - name: Unload rxrpc if loaded\n      community.general.modprobe:\n        name: rxrpc\n        state: absent\n      ignore_errors: true\n\n    - name: Unload esp6 if loaded\n      community.general.modprobe:\n        name: esp6\n        state: absent\n      ignore_errors: true\n\n    - name: Unload esp4 if loaded\n      community.general.modprobe:\n        name: esp4\n        state: absent\n      ignore_errors: true\n\n    # ------------------------------------------------------------------ #\n    # 3. Fallback: rmmod via shell for distros where community.general    #\n    #    modprobe with state=absent is not idempotent                     #\n    # ------------------------------------------------------------------ #\n\n    - name: Force-remove modules via rmmod (best-effort)\n      ansible.builtin.shell: |\n        for mod in esp4 esp6 rxrpc; do\n          if lsmod | grep -q \"^${mod} \"; then\n            rmmod \"$mod\" 2&gt;/dev/null &amp;&amp; echo \"removed $mod\" || echo \"could not remove $mod (in use?)\"\n          else\n            echo \"$mod not loaded\"\n          fi\n        done\n      register: rmmod_result\n      changed_when: \"'removed' in rmmod_result.stdout\"\n\n    - name: Show rmmod output\n      ansible.builtin.debug:\n        msg: \"{{ rmmod_result.stdout_lines }}\"\n\n    # ------------------------------------------------------------------ #\n    # 4. Regenerate initramfs so the blacklist survives a reboot          #\n    #    (distro-aware: update-initramfs on Debian/Ubuntu,                #\n    #     dracut on RHEL/Fedora/SUSE)                                     #\n    # ------------------------------------------------------------------ #\n\n    - name: Regenerate initramfs (Debian/Ubuntu)\n      ansible.builtin.command: update-initramfs -u -k all\n      when: ansible_os_family == \"Debian\"\n      changed_when: true\n\n    - name: Regenerate initramfs (RHEL / Fedora / AlmaLinux / CentOS / SUSE)\n      ansible.builtin.command: dracut --force --regenerate-all\n      when: ansible_os_family in [\"RedHat\", \"Suse\"]\n      changed_when: true\n\n    # ------------------------------------------------------------------ #\n    # 5. Verification                                                     #\n    # ------------------------------------------------------------------ #\n\n    - name: Verify modprobe blacklist is in place\n      ansible.builtin.command: cat /etc/modprobe.d/dirtyfrag.conf\n      register: modprobe_conf\n      changed_when: false\n      failed_when: &gt;\n        \"install esp4\"  not in modprobe_conf.stdout or\n        \"install esp6\"  not in modprobe_conf.stdout or\n        \"install rxrpc\" not in modprobe_conf.stdout\n\n    - name: Verify esp4 is not loaded\n      ansible.builtin.shell: lsmod | grep -q '^esp4 ' &amp;&amp; echo LOADED || echo NOT_LOADED\n      register: esp4_check\n      changed_when: false\n      failed_when: esp4_check.stdout == \"LOADED\"\n\n    - name: Verify esp6 is not loaded\n      ansible.builtin.shell: lsmod | grep -q '^esp6 ' &amp;&amp; echo LOADED || echo NOT_LOADED\n      register: esp6_check\n      changed_when: false\n      failed_when: esp6_check.stdout == \"LOADED\"\n\n    - name: Verify rxrpc is not loaded\n      ansible.builtin.shell: lsmod | grep -q '^rxrpc ' &amp;&amp; echo LOADED || echo NOT_LOADED\n      register: rxrpc_check\n      changed_when: false\n      failed_when: rxrpc_check.stdout == \"LOADED\"\n\n    - name: Attempt to load esp4 (must fail due to blacklist)\n      ansible.builtin.command: modprobe esp4\n      register: esp4_load_attempt\n      changed_when: false\n      failed_when: esp4_load_attempt.rc == 0   # rc != 0 means blacklist worked\n\n    - name: Attempt to load rxrpc (must fail due to blacklist)\n      ansible.builtin.command: modprobe rxrpc\n      register: rxrpc_load_attempt\n      changed_when: false\n      failed_when: rxrpc_load_attempt.rc == 0\n\n    - name: Summary\n      ansible.builtin.debug:\n        msg:\n          - \"Dirty Frag mitigation applied successfully.\"\n          - \"esp4:  {{ esp4_check.stdout }}\"\n          - \"esp6:  {{ esp6_check.stdout }}\"\n          - \"rxrpc: {{ rxrpc_check.stdout }}\"\n          - \"Blacklist reboot-persistent: yes (initramfs regenerated)\"\n          - \"NOTE: If IPsec (ESP) is required in your environment, this mitigation\"\n          - \"      will break it. Apply only on hosts where ESP is not in use.\"", "creation_timestamp": "2026-05-08T06:26:34.000000Z"}