← Back to Wiki
Security / Linux

apport Quietly Undoes Your sysctl Hardening After Every Reboot

You set fs.suid_dumpable = 0 in /etc/sysctl.d/. You reboot. It reads 2. You grep every sysctl path on the system for the key and find nothing setting it to 2. Nothing is misconfigured, and the value is still wrong. On Ubuntu the answer is that this is not a config problem at all.

Share on X

Confirm the file really is being applied

Rule out the boring explanations first, because they are more common:

# what is it now
sysctl fs.suid_dumpable

# does anything at all set it, anywhere
grep -rn suid_dumpable /etc/sysctl.conf /etc/sysctl.d /usr/lib/sysctl.d /run/sysctl.d 2>/dev/null

# does applying by hand work
sudo sysctl --system | grep -i suid_dumpable

If your file is listed, applying by hand gives you 0, and nothing else in any of those directories mentions the key, then sysctl is doing its job correctly and something else is changing the value afterwards.

BE WARNED: grep finding nothing is itself the clue. The instinct is to grep harder, or to suspect file ordering. Ordering matters when two files disagree. Here no file disagrees, which rules the whole config layer out. A value that is correct immediately after sysctl --system and wrong later is being written by a running process, not by a file.

The culprit

Ubuntu's crash-report handler, apport, sets fs.suid_dumpable at runtime as part of installing its core-dump hook. It runs after systemd-sysctl has applied everything in sysctl.d, so it wins by being later, and it leaves no trace in any configuration file because it is not configuration.

Watch it happen:

grep -rn suid_dumpable /usr/share/apport/apport
systemctl status apport
cat /proc/sys/kernel/core_pattern      # apport present means it owns core dumps

Disable it at both layers

One layer is not enough here. The init script and the service both need turning off, or a package update or a reboot quietly restores it:

sudo sed -i 's/^enabled=1/enabled=0/' /etc/default/apport
sudo systemctl disable --now apport.service

sudo sysctl --system | grep suid_dumpable
sudo reboot
# then confirm it survived
sysctl fs.suid_dumpable

Verify after a real reboot, not just after applying sysctl. The entire nature of this bug is that it only shows up on the next boot, so a check that skips the reboot proves nothing.

You almost certainly have it on more than one host

This is a distribution default, not a local mistake, so it is wherever Ubuntu is. A sweep here found the same thing on three more hosts immediately, all Ubuntu, all with suid_dumpable=2 and apport enabled:

for h in host1 host2 host3; do
  echo -n "$h: "
  ssh "$h" 'sysctl -n fs.suid_dumpable; systemctl is-enabled apport 2>/dev/null || echo no-apport'
done

Debian hosts are unaffected. apport is not installed there, so the value stays where you put it.

Skip your containers, and know why. fs.suid_dumpable is not namespaced. Containers share the host kernel's value and cannot set their own, so running this sweep against LXCs gives you readings you cannot act on and changes that cannot apply. Fix it on the host and the containers inherit it.

What the setting is for

Worth one paragraph, so the fix is a decision rather than cargo cult. fs.suid_dumpable controls whether a setuid program can produce a core dump when it crashes. A core dump is a copy of process memory, and a setuid process's memory is exactly where privileged material lives. 2 permits dumps under restricted ownership, 0 disables them for setuid binaries entirely. Hardening baselines want 0, and a crash-reporting tool wants dumps, which is the whole conflict in one line.

If you actively use crash reports, keeping apport and accepting the value is a defensible choice. Make it deliberately rather than discovering it in a scanner report.

The general lesson

When a setting reverts and no config file is responsible, stop searching the config layer. Ask what runs after the thing that applies your setting. Crash handlers, container runtimes, VPN clients, tuning daemons and cloud agents all write kernel parameters at runtime, none of them appear in a sysctl.d grep, and all of them win simply by going last.

When this isn't your problem