Version: 2026.11.08-0018-rolling (generic, x86_64)
Component: system_option.py (conf_mode)
Summary
system_option.py apply() writes to /sys/kernel/debug/dynamic_debug/control on every system option commit, also when system option kernel debug wireguard is not configured (it then writes module wireguard -p). With kernel lockdown in integrity (or confidentiality) mode, debugfs writes are denied, so every commit touching system option fails with PermissionError.
After boot the whole system option subtree can no longer be changed.
The failure also comes after earlier side effects of apply(): in the reproduction below vyos-beep.service gets enabled, the commit fails, and exit discard leaves the service enabled - running state and config disagree.
Code
src/conf_mode/system_option.py, apply() (line numbers from the 2026.11.08-0018-rolling image):
# Enable/disable dynamic debugging for kernel modules modules = ['wireguard'] modules_enabled = dict_search('kernel.debug', options) or [] for module in modules: if module in modules_enabled: check_kmod(module) write_file(kernel_dynamic_debug, f'module {module} +p') else: write_file(kernel_dynamic_debug, f'module {module} -p') # line 702
Every run of apply() - i.e. every commit that changes anything under system option, whatever the change - performs exactly one of the two writes: +p when kernel debug wireguard is set, -p otherwise. Neither depends on whether the debug setting changed, so both fail under lockdown. (Commits elsewhere are unaffected: config-mode-dependencies has no entry that calls system_option.)
The write came in with T3202.
Steps to reproduce
On a stock image (no other changes needed):
- Enable kernel lockdown (one-way until reboot): echo integrity | sudo tee /sys/kernel/security/lockdown
- configure
- set system option startup-beep
- commit
Actual result
Traceback (most recent call last):
File "/usr/libexec/vyos/conf_mode/system_option.py", line 738, in <module>
apply(c)
File "/usr/libexec/vyos/conf_mode/system_option.py", line 702, in apply
write_file(kernel_dynamic_debug, f'module {module} -p')
File "/usr/lib/python3/dist-packages/vyos/utils/file.py", line 84, in write_file
raise e
File "/usr/lib/python3/dist-packages/vyos/utils/file.py", line 73, in write_file
with open(fname, 'w' if not append else 'a') as f:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
PermissionError: [Errno 1] Operation not permitted: '/sys/kernel/debug/dynamic_debug/control'
noteworthy:
cmd 'systemctl enable vyos-beep.service'
...
[[system option]] failed
Commit failedAfter exit discard: systemctl is-enabled vyos-beep.service -> enabled.
Expected result
A system option change that doesn't involve kernel debug commits under lockdown. Suggested fixes, any of:
- write to dynamic_debug/control only when kernel debug changed (or only +p when enabled, and -p only when it was enabled before);
- tolerate EPERM/ENOENT on that write (lockdown, debugfs not mounted) with a warning instead of failing the commit;
- if a hard failure is wanted, raise in verify() before apply() has side effects.
Context
We run kernel lockdown integrity from a post-config boot hook as hardening (VyOS modules are signed, nothing we run needs debugfs).
AI disclosure
This bug was found, diagnosed and written up by Claude Opus 5.5 (Anthropic, model claude-opus-5-5), running in Claude Code during a test run of our VyOS automation in a VM. Specifically, Claude:
- hit the failed commit when our Ansible playbook re-applied system option on the rolling image,
- traced it to the unconditional dynamic_debug write in system_option.py apply() and the lockdown denial,
- reproduced it by hand on the VM (including the leftover vyos-beep.service side effect) and searched vyos.dev and the forum for an existing report,
- drafted this report.
A human (the reporter) reviewed it and filed it.