"/etc/sysctl.d/60-link-protection.conf" import {LINK_PROTECTION_SYSCTL_PATH} from '@fuzdev/zap/recipe_sysctl.js'; Where a config writes LINK_PROTECTION_SYSCTLS.
Recipes for kernel parameters a hardened host keeps set: a sysctl.d file that
holds them across boots, and a script that puts them in force now.
O_CREAT in one, each refused. They close the class of attack in which one account
plants a link or file at a path a more privileged process (root's apply, a
service) then opens. systemd sets all four on Debian and Ubuntu; Alpine sets only
the first two, so an Alpine host declares them.sysctl.d file text for a set of parameters.script that loads that file when a parameter's live value
differs from it.Distro-neutral: both families read /etc/sysctl.d/*.conf at boot (systemd's
systemd-sysctl, OpenRC's sysctl service in the boot runlevel), and both
sysctl commands (procps and BusyBox) load a file with -p.
Pure functions evaluated in zap's sandboxed config eval (fgro eval: no I/O,
clock, or randomness); the output is deterministic.
The caller writes the file and orders the script after it, e.g.
zap.file({id: 'sysctl-links', path: LINK_PROTECTION_SYSCTL_PATH, content: {type: 'inline', content: sysctl_conf(LINK_PROTECTION_SYSCTLS)}})
and
zap.script({id: 'sysctl-links-applied', ...sysctl_apply(LINK_PROTECTION_SYSCTL_PATH, LINK_PROTECTION_SYSCTLS), depends_on: ['sysctl-links']}).
6 declarations
"/etc/sysctl.d/60-link-protection.conf" import {LINK_PROTECTION_SYSCTL_PATH} from '@fuzdev/zap/recipe_sysctl.js'; Where a config writes LINK_PROTECTION_SYSCTLS.
Readonly<Record<string, string>> type Readonly<Record<string, string>>
import {LINK_PROTECTION_SYSCTLS} from '@fuzdev/zap/recipe_sysctl.js'; The link and file protections: protected_hardlinks and protected_symlinks at
1, protected_fifos at 1, and protected_regular at 2 (a group-writable
sticky directory counts too), the values systemd ships.
(path: string, values: Readonly<Record<string, string>>): SysctlApplyScript import {sysctl_apply} from '@fuzdev/zap/recipe_sysctl.js'; Build the script that puts values in force from the file at path.
check reads each parameter's live value from /proc/sys, readable by any
account, with its tabs and runs of blanks read as one space (a multi-value
parameter such as net.ipv4.ip_local_port_range reads 32768<tab>60999 there),
and passes when every one is the declared value; run loads the file
with sysctl -p and fails when a value still differs. Pass the same values the
file was written from.
paththe absolute path of the sysctl.d file
stringvaluesthe parameters the file holds
Readonly<Record<string, string>>SysctlApplyScript the script check/run pair.
(values: Readonly<Record<string, string>>): string import {sysctl_conf} from '@fuzdev/zap/recipe_sysctl.js'; Build the sysctl.d file text for values, one name = value line each, in the
order given.
valuesReadonly<Record<string, string>>string the file text, terminated by a trailing newline.
SysctlApplyScript import type {SysctlApplyScript} from '@fuzdev/zap/recipe_sysctl.js'; The check/run sysctl_apply returns (caller supplies id/name/depends_on).
checkCheck command — exit 0 means the script is already applied (skip).
type string
runThe command the planner emits when the check fails.
type string
Readonly<Record<string, string>> type Readonly<Record<string, string>>
import type {SysctlValues} from '@fuzdev/zap/recipe_sysctl.js'; Kernel parameters by sysctl name, each with the value it is set to.
[key: string]type string