Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Tiny local-spec package that ships a macros.d drop-in to enable
# distro-wide hardening flags for stage1 builds. Mechanism mirrors how
# azurelinux-rpm-config layers on top of redhat-rpm-config — this pkg
# just adds the hardening macros without touching redhat-rpm-config.
#
# Intent: any spec that BuildRequires this package (or any buildroot that
# pre-installs it) gets %_hardened_build=1 plus appended global compiler
# and linker flags before %set_build_flags composes CFLAGS/LDFLAGS.
#
# Used to A/B against Option A (per-component build.defines) on the
# dracut pilot. See base/comps/dracut/dracut.comp.toml.
[components.azl-bootstrap-hardening]
spec = { type = "local", path = "azl-bootstrap-hardening.spec" }
release = { calculation = "manual" }
36 changes: 36 additions & 0 deletions base/comps/azl-bootstrap-hardening/azl-bootstrap-hardening.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
Name: azl-bootstrap-hardening
Version: 1
Release: 1%{?dist}
Summary: Stage1 BinSkim hardening macros for Azure Linux
License: MIT
URL: https://aka.ms/azurelinux
BuildArch: noarch

Source0: macros.azl-bootstrap-hardening

# rpm reads /usr/lib/rpm/macros.d/* at startup, so installing this drop-in
# is the only thing we need to do — no scriptlets required.
Requires: redhat-rpm-config

%description
Layers Azure Linux stage1 compiler/linker hardening defaults on top of
Fedora's redhat-rpm-config via a /usr/lib/rpm/macros.d/ drop-in. Pilot
package used to evaluate distro-wide BinSkim remediation for the
azl4-bootstrap-compliance build target before broader rollout.

%prep
# Nothing to unpack.

%build
# Nothing to build.

%install
install -d %{buildroot}%{_rpmconfigdir}/macros.d
install -m 0644 %{SOURCE0} %{buildroot}%{_rpmconfigdir}/macros.d/macros.azl-bootstrap-hardening

%files
%{_rpmconfigdir}/macros.d/macros.azl-bootstrap-hardening

%changelog
* Tue May 27 2026 Azure Linux Team <azurelinux-pmc@microsoft.com> - 1-1
- Initial package for stage1 hardening flag rollout pilot.
27 changes: 27 additions & 0 deletions base/comps/azl-bootstrap-hardening/macros.azl-bootstrap-hardening
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# macros.azl-bootstrap-hardening
#
# Distro-wide hardening defaults for stage1 builds. Layered ON TOP of
# Fedora's redhat-rpm-config via macros.d drop-in priority — does not
# fork or replace any redhat-rpm-config file.
#
# Effect: when this package is installed in the buildroot, any spec that
# uses %configure / %cmake / %meson / %make_build / %set_build_flags
# picks up these flags. Build systems that bypass those macros and call
# the compiler directly will still need per-spec fixes.
#
# Pilot scope: dracut (see base/comps/dracut/dracut.comp.toml).
# Distro-wide rollout will inject this package into the stage1 mock
# chroot_setup_cmd once the pilot results are good.

# Toggle Fedora's redhat-hardened-cc1 / redhat-hardened-ld spec files.
# Covers PIE, RELRO+now, stack protector, fortify on packages that
# honor Fedora's hardening hooks.
%_hardened_build 1

# Explicit appends for build systems that override %optflags / LDFLAGS
# but still respect %__global_compiler_flags / %__global_ldflags via
# %set_build_flags. Arch-guard CET (only meaningful on x86_64).
%__global_compiler_flags %{__global_compiler_flags} -fstack-protector-strong -fstack-clash-protection -fPIE -D_FORTIFY_SOURCE=3 %{?_cet_flag}
%__global_ldflags %{__global_ldflags} -Wl,-z,relro,-z,now -Wl,-z,noexecstack -pie

%_cet_flag %{lua: if rpm.expand("%{_target_cpu}") == "x86_64" then print("-fcf-protection=full") end}
2 changes: 1 addition & 1 deletion base/comps/components.toml
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ includes = ["**/*.comp.toml", "component-check-disablement.toml", "component-min
[components.doxygen]
[components.dpdk]
[components.dpkg]
[components.dracut]
# dracut: see base/comps/dracut/dracut.comp.toml (hardening-flag evaluation)
[components.driverctl]
[components.drpm]
[components.duktape]
Expand Down
38 changes: 38 additions & 0 deletions base/comps/dracut/dracut.comp.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# dracut — used as a pilot package for evaluating stage1 BinSkim-hardening
# remediation options. We failed 802 packages in azl4-bootstrap-compliance with
# BA3001 (PIE), BA3003 (stack protector), BA3011 (RELRO). This file stages two
# mechanisms for injecting the hardening flags so we can A/B them.
#
# Pick ONE of the two options below by commenting/uncommenting. Do not enable
# both simultaneously (they would apply the same flags twice).
#
# ──────────────────────────────────────────────────────────────────────
# Option A (DISABLED) - per-component build.defines.
# Pros: zero new packages, scoped to just dracut, trivial to revert,
# lets us validate the flag list against a real build before
# committing to a distro-wide rollout.
# Cons: per-spec mechanism - not how we'd ship this distro-wide.
#
# Option B (ACTIVE) - pull in a new "azl-bootstrap-hardening" RPM that
# drops a macros.d file into the buildroot. Same flags, but delivered
# the way we'd eventually ship them for the whole distro.
# See base/comps/azl-bootstrap-hardening/.
# ──────────────────────────────────────────────────────────────────────

[components.dracut]

# -- Option A (DISABLED): macro overrides via build.defines ------------
# Kept commented as a per-package escape hatch for bisecting flag changes
# without touching the distro-wide macros file.
# [components.dracut.build.defines]
# _hardened_build = "1"
# __global_compiler_flags = "-O2 -g -fstack-protector-strong -fstack-clash-protection -fPIE -D_FORTIFY_SOURCE=3"
# __global_ldflags = "-Wl,-z,relro,-z,now -Wl,-z,noexecstack -pie"

# -- Option B (ACTIVE): macros package via BuildRequires ---------------
# Pulls in azl-bootstrap-hardening, which ships a macros.d drop-in that
# sets %_hardened_build and appends the global compiler/ld flags. Same
# delivery mechanism we want for the distro-wide rollout.
overlays = [
{ type = "spec-add-tag", tag = "BuildRequires", value = "azl-bootstrap-hardening", description = "Inject AzL stage1/2 hardening macros (PIE, RELRO, stack protector, FORTIFY) via the azl-bootstrap-hardening macros.d drop-in. Pilot for the broader azl4-bootstrap-compliance BinSkim remediation." },
]
83 changes: 83 additions & 0 deletions docs/hardening-flags.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Hardening Flags for Azure Linux 4.0 Builds

## Why this matters

Azure Linux 4.0 builds use Fedora's `redhat-rpm-config` as-is, which does not
enable `%_hardened_build` by default. As a result, BinSkim compliance scans
fail on most native packages with three rules:

| Rule | Issue | Flag needed |
| ------ | ---------------------- | ---------------------------- |
| BA3001 | Not PIE | `-fPIE -pie` |
| BA3003 | No stack protector | `-fstack-protector-strong` |
| BA3011 | RELRO not enabled | `-Wl,-z,relro,-z,now` |

The fix is to inject these flags through RPM macros so every spec that uses
`%configure`, `%cmake`, `%meson`, or `%make_build` picks them up automatically.
The same approach works for both stage1 and stage2.

## The flags we want set

```
%_hardened_build 1
%__global_compiler_flags -O2 -g -fstack-protector-strong -fstack-clash-protection -fPIE -D_FORTIFY_SOURCE=3
%__global_ldflags -Wl,-z,relro,-z,now -Wl,-z,noexecstack -pie
```

## Option A — set macros per component

Add the macros to a component's `[components.<name>.build.defines]` block in
its `comp.toml`. `azldev` will write a sidecar `<name>.azl.macros` file and
add `%{load:…}` to the rendered spec.

Example: [base/comps/dracut/dracut.comp.toml](../base/comps/dracut/dracut.comp.toml).

**Good for**: trying flag changes on one package without affecting anything else.

**Bad for**: distro-wide rollout — you'd repeat the same block in every
component's TOML.

## Option B — ship the macros in an RPM

Build a tiny noarch package (`azl-bootstrap-hardening`) that drops a
`macros.azl-bootstrap-hardening` file into `/usr/lib/rpm/macros.d/`. When
that package is installed in the buildroot, `rpm` reads the file at startup
and the macros apply to every build.

Install it everywhere by adding it once to `chroot_setup_cmd` in each mock
template:

| Stage | File |
| ------ | ---- |
| stage1 | [distro/mock/azl4/stage1/azurelinux-4.0.tpl](../distro/mock/azl4/stage1/azurelinux-4.0.tpl) |
| stage2 | [distro/mock/azl4/stage2/azurelinux-4.0.tpl](../distro/mock/azl4/stage2/azurelinux-4.0.tpl) |

No spec edits required.

Package definition: [base/comps/azl-bootstrap-hardening/](../base/comps/azl-bootstrap-hardening/).

## Which to use

| | Option A | Option B |
| ---------------------------- | ----------------- | ------------------ |
| Spec edits | per component | none |
| Source of truth | many TOML files | one RPM |
| Arch-conditional macros | no | yes (`%ifarch`) |
| Revert | per component | one mock line |
| Works in stage1 | yes | yes |
| Works in stage2 | yes | yes |

**Recommendation: Option B.** Single source of truth, no per-spec churn, and
the same package can be dropped into both stage1 and stage2 buildroots.

Keep Option A available as a way to test flag changes on one package before
updating the distro-wide macros file.

## What this won't fix

Some packages will still fail compliance after the flags are set globally.
These need per-spec work and aren't solved by either option:

- Build systems that clobber `CFLAGS`/`LDFLAGS` (raw `cmake`, raw `go build`).
- Rust uses `RUSTFLAGS`, not `CFLAGS` — needs a separate macro.
- Asm-only or prebuilt-blob packages — candidates for a "known exceptions" list.
39 changes: 39 additions & 0 deletions specs/a/azl-bootstrap-hardening/azl-bootstrap-hardening.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# This spec file has been modified by azldev to include build configuration overlays.
# Do not edit manually; changes may be overwritten.

Name: azl-bootstrap-hardening
Version: 1
Release: 1%{?dist}
Summary: Stage1 BinSkim hardening macros for Azure Linux
License: MIT
URL: https://aka.ms/azurelinux
BuildArch: noarch

Source0: macros.azl-bootstrap-hardening

# rpm reads /usr/lib/rpm/macros.d/* at startup, so installing this drop-in
# is the only thing we need to do — no scriptlets required.
Requires: redhat-rpm-config

%description
Layers Azure Linux stage1 compiler/linker hardening defaults on top of
Fedora's redhat-rpm-config via a /usr/lib/rpm/macros.d/ drop-in. Pilot
package used to evaluate distro-wide BinSkim remediation for the
azl4-bootstrap-compliance build target before broader rollout.

%prep
# Nothing to unpack.

%build
# Nothing to build.

%install
install -d %{buildroot}%{_rpmconfigdir}/macros.d
install -m 0644 %{SOURCE0} %{buildroot}%{_rpmconfigdir}/macros.d/macros.azl-bootstrap-hardening

%files
%{_rpmconfigdir}/macros.d/macros.azl-bootstrap-hardening

%changelog
* Tue May 27 2026 Azure Linux Team <azurelinux-pmc@microsoft.com> - 1-1
- Initial package for stage1 hardening flag rollout pilot.
27 changes: 27 additions & 0 deletions specs/a/azl-bootstrap-hardening/macros.azl-bootstrap-hardening
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# macros.azl-bootstrap-hardening
#
# Distro-wide hardening defaults for stage1 builds. Layered ON TOP of
# Fedora's redhat-rpm-config via macros.d drop-in priority — does not
# fork or replace any redhat-rpm-config file.
#
# Effect: when this package is installed in the buildroot, any spec that
# uses %configure / %cmake / %meson / %make_build / %set_build_flags
# picks up these flags. Build systems that bypass those macros and call
# the compiler directly will still need per-spec fixes.
#
# Pilot scope: dracut (see base/comps/dracut/dracut.comp.toml).
# Distro-wide rollout will inject this package into the stage1 mock
# chroot_setup_cmd once the pilot results are good.

# Toggle Fedora's redhat-hardened-cc1 / redhat-hardened-ld spec files.
# Covers PIE, RELRO+now, stack protector, fortify on packages that
# honor Fedora's hardening hooks.
%_hardened_build 1

# Explicit appends for build systems that override %optflags / LDFLAGS
# but still respect %__global_compiler_flags / %__global_ldflags via
# %set_build_flags. Arch-guard CET (only meaningful on x86_64).
%__global_compiler_flags %{__global_compiler_flags} -fstack-protector-strong -fstack-clash-protection -fPIE -D_FORTIFY_SOURCE=3 %{?_cet_flag}
%__global_ldflags %{__global_ldflags} -Wl,-z,relro,-z,now -Wl,-z,noexecstack -pie

%_cet_flag %{lua: if rpm.expand("%{_target_cpu}") == "x86_64" then print("-fcf-protection=full") end}
3 changes: 2 additions & 1 deletion specs/d/dracut/dracut.spec
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

Name: dracut
Version: 107
Release: 9%{?dist}
Release: 10%{?dist}

Summary: Initramfs generator using udev

Expand Down Expand Up @@ -124,6 +124,7 @@ Requires: procps-ng

Requires: libkcapi-hmaccalc

BuildRequires: azl-bootstrap-hardening
%description
dracut contains tools to create bootable initramfses for the Linux
kernel. Unlike other implementations, dracut hard-codes as little
Expand Down
Loading