a13xp0p0v / kernel-hardening-checker

A tool for checking the security hardening options of the Linux kernel
GNU General Public License v3.0
1.69k stars 156 forks source link

drop check for dependency-only CONFIG_GCC_PLUGINS due to Clang #102

Closed thestinger closed 7 months ago

thestinger commented 10 months ago

It makes sense to check for the functionality provided by the plugins if there's no Clang alternative, but it doesn't make sense to fail from an irrelevant dependency for those features being unavailable. For example, using CONFIG_INIT_STACK_ALL_ZERO is more secure than the STRUCTLEAK plugin anyway, and has insignificant performance overhead. There are already checks for the latent entropy, RANDSTRUCT and STACKLEAK plugins, but there could be alternatives to those for Clang, and not having GCC_PLUGINS enabled is irrelevant.

a13xp0p0v commented 10 months ago

@thestinger, I agree. I'll think and return with the solution.

a13xp0p0v commented 7 months ago

Hello @thestinger,

I've found the solution.

1) Dropped the CONFIG_GCC_PLUGINS check. This check is not security-relevant and it's not needed in case of building the kernel with clang.

2) Added the CONFIG_CC_IS_GCC dependency for gcc plugins, that don't have analogues in clang.

Let's see the output of kernel-hardening-checker for a kernel config created with clang.

[+] Special report mode: verbose
[+] Kconfig file to check: my/arm64_full_hardened_6.6_clang.config
[+] Detected microarchitecture: ARM64
[+] Detected kernel version: (6, 6, 7)
[+] Detected compiler: CLANG 150006

clang and gcc support CONFIG_INIT_STACK_ALL_ZERO as alternative to CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL:

-------------------------------------------------------------------------------------------------------------------------
    <<< OR >>>                                                                             | OK
CONFIG_INIT_STACK_ALL_ZERO              |kconfig|     y      |defconfig | self_protection  | OK
CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL  |kconfig|     y      |   kspp   | self_protection  | None
-------------------------------------------------------------------------------------------------------------------------

Clang will support CONFIG_RANDSTRUCT_FULL starting from version 16:

-------------------------------------------------------------------------------------------------------------------------
    <<< OR >>>                                                                             | FAIL: is not found
CONFIG_RANDSTRUCT_FULL                  |kconfig|     y      |   kspp   | self_protection  | FAIL: is not found
CONFIG_GCC_PLUGIN_RANDSTRUCT            |kconfig|     y      |   kspp   | self_protection  | FAIL: is not found
-------------------------------------------------------------------------------------------------------------------------
    <<< AND >>>                                                                            | FAIL: CONFIG_RANDSTRUCT_FULL is not "y"
CONFIG_RANDSTRUCT_PERFORMANCE           |kconfig| is not set |   kspp   | self_protection  | None
CONFIG_GCC_PLUGIN_RANDSTRUCT_PERFORMANCE|kconfig| is not set |   kspp   | self_protection  | None
    <<< OR >>>                                                                             | FAIL: is not found
CONFIG_RANDSTRUCT_FULL                  |kconfig|     y      |   kspp   | self_protection  | FAIL: is not found
CONFIG_GCC_PLUGIN_RANDSTRUCT            |kconfig|     y      |   kspp   | self_protection  | FAIL: is not found
-------------------------------------------------------------------------------------------------------------------------

The CONFIG_GCC_PLUGIN_LATENT_ENTROPY check gives FAIL: CONFIG_CC_IS_GCC is not "y":

-------------------------------------------------------------------------------------------------------------------------
    <<< AND >>>                                                                            | FAIL: CONFIG_CC_IS_GCC is not "y"
CONFIG_GCC_PLUGIN_LATENT_ENTROPY        |kconfig|     y      |   kspp   | self_protection  | None
CONFIG_CC_IS_GCC                        |kconfig|     y      |    -     |        -         | FAIL: is not found
-------------------------------------------------------------------------------------------------------------------------

The CONFIG_GCC_PLUGIN_STACKLEAK check gives the same:

-------------------------------------------------------------------------------------------------------------------------
    <<< AND >>>                                                                            | FAIL: CONFIG_CC_IS_GCC is not "y"
CONFIG_GCC_PLUGIN_STACKLEAK             |kconfig|     y      |   kspp   | self_protection  | None
CONFIG_CC_IS_GCC                        |kconfig|     y      |    -     |        -         | FAIL: is not found
-------------------------------------------------------------------------------------------------------------------------

I decided not to remove the gcc-specific checks for clang builds and vice-versa. I think users should see the options they miss when they choose a compiler for the kernel. The example with the CONFIG_CFI_CLANG check for the gcc kernel build:

-------------------------------------------------------------------------------------------------------------------------
    <<< AND >>>                                                                            | FAIL: CONFIG_CC_IS_CLANG is not "y"
CONFIG_CFI_CLANG                        |kconfig|     y      |   kspp   | self_protection  | None
CONFIG_CC_IS_CLANG                      |kconfig|     y      |    -     |        -         | FAIL: is not found
-------------------------------------------------------------------------------------------------------------------------
    <<< AND >>>                                                                            | FAIL: CONFIG_CC_IS_CLANG is not "y"
CONFIG_CFI_PERMISSIVE                   |kconfig| is not set |   kspp   | self_protection  | None
CONFIG_CFI_CLANG                        |kconfig|     y      |   kspp   | self_protection  | None
CONFIG_CC_IS_CLANG                      |kconfig|     y      |    -     |        -         | FAIL: is not found
-------------------------------------------------------------------------------------------------------------------------

What do you think?

thestinger commented 7 months ago

@a13xp0p0v Yes, that makes perfect sense. Some features are GCC exclusive and some are Clang exclusive. PaX and grsecurity still exist where features going beyond what Clang provides for CFI exist for GCC but that's not available upstream where Clang has a big advantage until GCC provides kCFI.

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107048

The main thing missing upstream for Clang is STACKLEAK. Latent entropy really doesn't matter on any decent hardware but would still be quite useful in problematic environments.