Patching a critical Exim vulnerability

On Friday the 24th of November a remote code execution vulnerability has been reported for Exim, a popular mail transfer agent for Unix-like platforms. The vulnerability has been found in the SMTP extension chunking (ESMTP CHUNKING), which has been introduced in Exim 4.88. It allows remote attackers to execute arbitrary code or cause a denial of service (use-after-free) via vectors involving BDAT commands.

The workaround for Exim 4.88 or newer (4.89 is current, 4.90 is upcoming) is to add the following parameter in the main section of the Exim configuration:

chunking_advertise_hosts =

We have many DirectAdmin servers running Exim 4.88 (or newer) which required this workaround. For various reasons we couldn’t simply update the existing exim.conf using DirectAdmin’s update scripts. To apply the workaround on hundreds of servers (with different exim.conf versions) we used the following Ansible playbook:

---
- hosts: all
  gather_facts: false

  handlers:
    - name: restart exim
      service:
        name: exim
        pattern: exim
        state: restarted

  tasks:
    - name: check if the remote host runs directadmin
      stat:
        path: /usr/local/directadmin/directadmin
      register: directadmin_installed

    - name: check which version of exim is installed
      shell: "/usr/sbin/exim -bV | head -n1 | grep -Eo '[4].[0-9][0-9]'"
      changed_when: false
      register: exim_version
      when: directadmin_installed.stat.exists

    - name: check which version of exim_conf is installed
      shell: "cat /etc/exim.conf | grep ' SpamBlocker.*exim.conf[.,]' | grep -Eo '*[0-9].[0-9].[0-9]*'"
      changed_when: false
      register: exim_conf_version
      when: directadmin_installed.stat.exists

    - name: ensure chunking_advertise_hosts is set when exim_conf version is 2.x
      lineinfile:
        dest: /etc/exim.conf
        insertafter: "^daemon_smtp_ports(.*)"
        line: "chunking_advertise_hosts="
      notify: restart exim
      when: directadmin_installed.stat.exists and exim_version.stdout|version_compare('4.88', '>=') and exim_conf_version.stdout|version_compare('2.1.2', '<=')

    - name: ensure chunking_advertise_hosts is set when exim_conf version is 4.2.x
      lineinfile:
        dest: /etc/exim.conf
        insertafter: "# CONFIGURATION STARTS HERE"
        line: "chunking_advertise_hosts="
      notify: restart exim
      when: directadmin_installed.stat.exists and exim_version.stdout|version_compare('4.88', '>=') and exim_conf_version.stdout|version_compare('4.2.0', '>=') and exim_conf_version.stdout|version_compare('4.3.0', '<')

    - name: ensure chunking_advertise_hosts is set when exim_conf version is 4.3.x or newer
      lineinfile:
        dest: /etc/exim.variables.conf
        insertafter: EOF
        line: "chunking_advertise_hosts="
      notify: restart exim
      when: directadmin_installed.stat.exists and exim_version.stdout|version_compare('4.88', '>=') and exim_conf_version.stdout|version_compare('4.3.0', '>=')