[PATCH RESEND bpf-next 2/4] security: Generate a header with the count of enabled LSMs
Kees Cook
keescook at chromium.org
Fri Jan 20 04:04:33 UTC 2023
On Fri, Jan 20, 2023 at 01:08:16AM +0100, KP Singh wrote:
> The header defines a MAX_LSM_COUNT constant which is used in a
> subsequent patch to generate the static calls for each LSM hook which
> are named using preprocessor token pasting. Since token pasting does not
> work with arithmetic expressions, generate a simple lsm_count.h header
> which represents the subset of LSMs that can be enabled on a given
> kernel based on the config.
>
> While one can generate static calls for all the possible LSMs that the
> kernel has, this is actually wasteful as most kernels only enable a
> handful of LSMs.
This is a frustrating bit of complexity to deal with it, but it seems
worse to leave each security_... callsite with a huge swath of NOPs.
>
> Signed-off-by: KP Singh <kpsingh at kernel.org>
> ---
> scripts/Makefile | 1 +
> scripts/security/.gitignore | 1 +
> scripts/security/Makefile | 4 +++
> scripts/security/gen_lsm_count.c | 57 ++++++++++++++++++++++++++++++++
> security/Makefile | 11 ++++++
> 5 files changed, 74 insertions(+)
> create mode 100644 scripts/security/.gitignore
> create mode 100644 scripts/security/Makefile
> create mode 100644 scripts/security/gen_lsm_count.c
>
> diff --git a/scripts/Makefile b/scripts/Makefile
> index 1575af84d557..9712249c0fb3 100644
> --- a/scripts/Makefile
> +++ b/scripts/Makefile
> @@ -41,6 +41,7 @@ targets += module.lds
> subdir-$(CONFIG_GCC_PLUGINS) += gcc-plugins
> subdir-$(CONFIG_MODVERSIONS) += genksyms
> subdir-$(CONFIG_SECURITY_SELINUX) += selinux
> +subdir-$(CONFIG_SECURITY) += security
>
> # Let clean descend into subdirs
> subdir- += basic dtc gdb kconfig mod
> diff --git a/scripts/security/.gitignore b/scripts/security/.gitignore
> new file mode 100644
> index 000000000000..684af16735f1
> --- /dev/null
> +++ b/scripts/security/.gitignore
> @@ -0,0 +1 @@
> +gen_lsm_count
> diff --git a/scripts/security/Makefile b/scripts/security/Makefile
> new file mode 100644
> index 000000000000..05f7e4109052
> --- /dev/null
> +++ b/scripts/security/Makefile
> @@ -0,0 +1,4 @@
> +# SPDX-License-Identifier: GPL-2.0
> +hostprogs-always-y += gen_lsm_count
> +HOST_EXTRACFLAGS += \
> + -I$(srctree)/include/uapi -I$(srctree)/include
> diff --git a/scripts/security/gen_lsm_count.c b/scripts/security/gen_lsm_count.c
> new file mode 100644
> index 000000000000..a9a227724d84
> --- /dev/null
> +++ b/scripts/security/gen_lsm_count.c
> @@ -0,0 +1,57 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/* NOTE: we really do want to use the kernel headers here */
> +#define __EXPORTED_HEADERS__
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <errno.h>
> +#include <ctype.h>
> +
> +#include <linux/kconfig.h>
> +
> +#define GEN_MAX_LSM_COUNT ( \
> + /* Capabilities */ \
> + IS_ENABLED(CONFIG_SECURITY) + \
> + IS_ENABLED(CONFIG_SECURITY_SELINUX) + \
> + IS_ENABLED(CONFIG_SECURITY_SMACK) + \
> + IS_ENABLED(CONFIG_SECURITY_TOMOYO) + \
> + IS_ENABLED(CONFIG_SECURITY_APPARMOR) + \
> + IS_ENABLED(CONFIG_SECURITY_YAMA) + \
> + IS_ENABLED(CONFIG_SECURITY_LOADPIN) + \
> + IS_ENABLED(CONFIG_SECURITY_SAFESETID) + \
> + IS_ENABLED(CONFIG_SECURITY_LOCKDOWN_LSM) + \
> + IS_ENABLED(CONFIG_BPF_LSM) + \
> + IS_ENABLED(CONFIG_SECURITY_LANDLOCK))
I'm bothered that we have another place to collect a list of "all" the
LSMs. The stacking design went out of its way to create DEFINE_LSM() so
there didn't need to be this kind of centralized list.
I don't have a better suggestion, though. Casey has a centralized list
too, so it might make sense (as he mentioned) to use something like
that. It can be arranged to provide a MAX_... macro (that could be
BUILD_BUG_ON checked against a similarly named enum). I'm thinking:
enum lsm_list {
LSM_SELINUX,
LSM_SMACK,
...
__LSM_MAX,
};
/*
* We can't use __LSM_MAX directly because we need it for macro
* concatenation, so just check it against __LSM_MAX at build time.
*/
#define LSM_MAX 15
...
BUILD_BUG_ON(LSM_MAX != __LSM_MAX);
> +
> +const char *progname;
> +
> +static void usage(void)
> +{
> + printf("usage: %s lsm_count.h\n", progname);
> + exit(1);
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + FILE *fout;
> +
> + progname = argv[0];
> +
> + if (argc < 2)
> + usage();
> +
> + fout = fopen(argv[1], "w");
> + if (!fout) {
> + fprintf(stderr, "Could not open %s for writing: %s\n",
> + argv[1], strerror(errno));
> + exit(2);
> + }
> +
> + fprintf(fout, "#ifndef _LSM_COUNT_H_\n#define _LSM_COUNT_H_\n\n");
> + fprintf(fout, "\n#define MAX_LSM_COUNT %d\n", GEN_MAX_LSM_COUNT);
> + fprintf(fout, "#endif /* _LSM_COUNT_H_ */\n");
> + exit(0);
> +}
> diff --git a/security/Makefile b/security/Makefile
> index 18121f8f85cd..7a47174831f4 100644
> --- a/security/Makefile
> +++ b/security/Makefile
> @@ -3,6 +3,7 @@
> # Makefile for the kernel security code
> #
>
> +gen := include/generated
> obj-$(CONFIG_KEYS) += keys/
>
> # always enable default capabilities
> @@ -27,3 +28,13 @@ obj-$(CONFIG_SECURITY_LANDLOCK) += landlock/
>
> # Object integrity file lists
> obj-$(CONFIG_INTEGRITY) += integrity/
Or, if the enum/#define doesn't work, it might be possible to just do
this in the Makefile more directly?
${gen}/lsm_count.h: FORCE
(echo "#ifndef _LSM_COUNT_H_"; \
echo "#define _LSM_COUNT_H_"; \
echo -n "#define MAX_LSM_COUNT "; \
echo $(CONFIG_SECURITY_SELINUX) \
$(CONFIG_SECURITY_SMACK) \
...
| wc -w; \
echo "#endif /* _LSM_COUNT_H_") >$@
> +
> +$(addprefix $(obj)/,$(obj-y)): $(gen)/lsm_count.h
> +
> +quiet_cmd_lsm_count = GEN ${gen}/lsm_count.h
> + cmd_lsm_count = scripts/security/gen_lsm_count ${gen}/lsm_count.h
> +
> +targets += lsm_count.h
> +
> +${gen}/lsm_count.h: FORCE
> + $(call if_changed,lsm_count)
> --
> 2.39.0.246.g2a6d74b583-goog
>
--
Kees Cook
More information about the Linux-security-module-archive
mailing list