Read the Running Kernel's Build Options from /proc/config.gz

Forgot whether this kernel was built with a feature, /proc/config.gz settles it without a rebuild. This guide inspects the running kernel's build options, searches for a particular CONFIG_ setting, and compares the result with the kernel build directory when one exists. Allow about ten minutes. You need a shell; every example only reads files and needs no sudo.

1. Check whether the interface exists

The file comes from the kernel's procfs interface, not the manpages package, and it only exists when the kernel was built with CONFIG_IKCONFIG_PROC. Check that before trying to decompress anything.

$ test -r /proc/config.gz && echo 'kernel config is available' || echo 'kernel config is unavailable'
kernel config is available

2. Read the configuration without creating a file

/proc/config.gz is compressed, so zcat expands it to standard output and leaves the system untouched:

$ zcat /proc/config.gz | sed -n '1,12p'
#
# Automatically generated file; DO NOT EDIT.
# Linux/x86 6.8.0 Kernel Configuration
#
CONFIG_CC_VERSION_TEXT="x86_64-linux-gnu-gcc-13"
CONFIG_CC_IS_GCC=y
CONFIG_GCC_VERSION=130201
CONFIG_CLANG_VERSION=0
CONFIG_AS_IS_GNU=y
CONFIG_AS_VERSION=240
CONFIG_LD_IS_BFD=y

The exact header, compiler details and values depend on the kernel you're running. What stays constant is the .config format also used by make xconfig or make config: a line ending in =y is built in, =m is a module, and # CONFIG_NAME is not set records a disabled option.

Checkpoint: if zcat reports that the input is not in gzip format or cannot be opened, stop and re-check the path and the interface test above. Do not swap in cat: the contents are compressed.

3. Search for one kernel option

Use zgrep when you know the option name, and anchor the pattern to the start of a line so you don't match a comment or a similarly named option:

$ zgrep -E '^(CONFIG_IKCONFIG|# CONFIG_IKCONFIG)' /proc/config.gz
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y

Swap the placeholder for the option you actually need:

$ option='CONFIG_PREEMPT'
$ zgrep -E "^${option}=|^# ${option} is not set$" /proc/config.gz
CONFIG_PREEMPT_DYNAMIC=y

Trap: that last result is a broad prefix catching a related option, not the exact one you asked for. Prefer a literal exact match:

$ zgrep -E '^CONFIG_PREEMPT=|^# CONFIG_PREEMPT is not set$' /proc/config.gz
# CONFIG_PREEMPT is not set

No output means the option is either absent from this kernel's configuration or your pattern is wrong. A matching zgrep returns status 0; no match normally returns status 1. Capture that status right away if a script needs to tell a match from an ordinary miss.

4. Save a copy only when you need one

For repeated searches or an audit record, expand the stream into a new file. Name it after the running kernel and check the command status before treating the file as complete.

$ kernel_release=$(uname -r)
$ output="kernel-config-${kernel_release}.config"
$ zcat /proc/config.gz > "$output"
$ status=$?
$ if test "$status" -eq 0; then
>     wc -l "$output"
> else
>     printf 'could not read /proc/config.gz (status %s)\n' "$status" >&2
>     rm -f -- "$output"
> fi
1542 kernel-config-6.8.0-139-generic.config

Warning: shell redirection truncates an existing destination before zcat even starts. If the file name matters, write to a temporary file in the same directory and rename it only after a successful read:

$ temporary=$(mktemp "${output}.XXXXXX")
$ if zcat /proc/config.gz > "$temporary"; then
>     mv -- "$temporary" "$output"
> else
>     rm -f -- "$temporary"
>     printf '%s\n' 'configuration export failed' >&2
> fi

Recovery: the mv only touches your working directory, not the kernel. If you no longer need the exported copy, just remove it, and keep it protected if it reveals build choices your documentation treats as sensitive.

5. Compare the running copy with the build directory

The manual gives this as an equivalent source when the build configuration hasn't changed:

$ cat /lib/modules/$(uname -r)/build/.config

That path is often a symlink to kernel headers or a separate build tree. It can be missing on a minimal install, and it can describe a different build if packages or symlinks changed since boot, so check it before comparing:

$ build_config="/lib/modules/$(uname -r)/build/.config"
$ if test -r "$build_config"; then
>     diff -u <(zcat /proc/config.gz) "$build_config"
> else
>     printf 'no readable build configuration at %s\n' "$build_config"
> fi
no readable build configuration at /lib/modules/6.8.0-139-generic/build/.config

An empty diff means the two streams matched. A difference is evidence the files differ, not automatically evidence of a running-kernel problem: the build tree might belong to another release, or have been edited after the kernel was built. Check uname -r for the running release before drawing conclusions.

6. Handle missing or surprising results

Keep three separate questions apart: does /proc/config.gz exist and can your user read it, can zcat decompress it, and does the configuration contain the exact option you're checking. A failure in one does not answer the others.

Do not treat a configuration read as proof that a feature is active at runtime. A setting can enable a built-in feature, permit a module, or be affected by other kernel and boot conditions entirely. Use the relevant runtime interface or module state for that separate question.

Done means