* Re: [PATCH v4 12/34] lsm: rework the LSM enable/disable setter/getter functions
From: Mimi Zohar @ 2025-09-19 19:04 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: John Johansen, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250916220355.252592-48-paul@paul-moore.com>
On Tue, 2025-09-16 at 18:03 -0400, Paul Moore wrote:
> In addition to style changes, rename set_enabled() to lsm_enabled_set()
> and is_enabled() to lsm_is_enabled() to better fit within the LSM
> initialization code.
>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> Reviewed-by: John Johansen <john.johhansen@canonical.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
> security/lsm_init.c | 62 ++++++++++++++++++++++-----------------------
> 1 file changed, 31 insertions(+), 31 deletions(-)
>
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 87e2147016b3..2cfd72ade6fb 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -10,6 +10,10 @@
>
> #include "lsm.h"
>
> +/* LSM enabled constants. */
> +static __initdata int lsm_enabled_true = 1;
> +static __initdata int lsm_enabled_false = 0;
> +
> /* Pointers to LSM sections defined in include/asm-generic/vmlinux.lds.h */
> extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
> extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
> @@ -75,37 +79,33 @@ static int __init lsm_debug_enable(char *str)
> }
> __setup("lsm.debug", lsm_debug_enable);
>
> -/* Mark an LSM's enabled flag. */
> -static int lsm_enabled_true __initdata = 1;
> -static int lsm_enabled_false __initdata = 0;
> -static void __init set_enabled(struct lsm_info *lsm, bool enabled)
> +/**
> + * lsm_enabled_set - Mark a LSM as enabled
> + * @lsm: LSM definition
> + * @enabled: enabled flag
> + */
> +static void __init lsm_enabled_set(struct lsm_info *lsm, bool enabled)
> {
> /*
> * When an LSM hasn't configured an enable variable, we can use
> * a hard-coded location for storing the default enabled state.
> */
> - if (!lsm->enabled) {
> - if (enabled)
> - lsm->enabled = &lsm_enabled_true;
> - else
> - lsm->enabled = &lsm_enabled_false;
> - } else if (lsm->enabled == &lsm_enabled_true) {
> - if (!enabled)
> - lsm->enabled = &lsm_enabled_false;
> - } else if (lsm->enabled == &lsm_enabled_false) {
> - if (enabled)
> - lsm->enabled = &lsm_enabled_true;
> + if (!lsm->enabled ||
> + lsm->enabled == &lsm_enabled_true ||
> + lsm->enabled == &lsm_enabled_false) {
> + lsm->enabled = enabled ? &lsm_enabled_true : &lsm_enabled_false;
> } else {
> *lsm->enabled = enabled;
> }
> }
>
> -static inline bool is_enabled(struct lsm_info *lsm)
> +/**
> + * lsm_is_enabled - Determine if a LSM is enabled
> + * @lsm: LSM definition
> + */
> +static inline bool lsm_is_enabled(struct lsm_info *lsm)
> {
> - if (!lsm->enabled)
> - return false;
> -
> - return *lsm->enabled;
> + return (lsm->enabled ? *lsm->enabled : false);
> }
>
> /* Is an LSM already listed in the ordered LSMs list? */
> @@ -139,7 +139,7 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
> lsm_idlist[last_lsm++] = lsm->id;
>
> init_debug("%s ordered: %s (%s)\n", from, lsm->id->name,
> - is_enabled(lsm) ? "enabled" : "disabled");
> + lsm_is_enabled(lsm) ? "enabled" : "disabled");
> }
>
> static void __init lsm_set_blob_size(int *need, int *lbs)
> @@ -162,17 +162,17 @@ static void __init lsm_prepare(struct lsm_info *lsm)
> {
> struct lsm_blob_sizes *blobs;
>
> - if (!is_enabled(lsm)) {
> - set_enabled(lsm, false);
> + if (!lsm_is_enabled(lsm)) {
> + lsm_enabled_set(lsm, false);
> return;
> } else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && lsm_exclusive) {
> init_debug("exclusive disabled: %s\n", lsm->id->name);
> - set_enabled(lsm, false);
> + lsm_enabled_set(lsm, false);
> return;
> }
>
> /* Mark the LSM as enabled. */
> - set_enabled(lsm, true);
> + lsm_enabled_set(lsm, true);
> if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !lsm_exclusive) {
> init_debug("exclusive chosen: %s\n", lsm->id->name);
> lsm_exclusive = lsm;
> @@ -206,7 +206,7 @@ static void __init lsm_prepare(struct lsm_info *lsm)
> /* Initialize a given LSM, if it is enabled. */
> static void __init initialize_lsm(struct lsm_info *lsm)
> {
> - if (is_enabled(lsm)) {
> + if (lsm_is_enabled(lsm)) {
> int ret;
>
> init_debug("initializing %s\n", lsm->id->name);
> @@ -240,7 +240,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> lsm_for_each_raw(major) {
> if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
> strcmp(major->id->name, lsm_order_legacy) != 0) {
> - set_enabled(major, false);
> + lsm_enabled_set(major, false);
> init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
> lsm_order_legacy, major->id->name);
> }
> @@ -286,7 +286,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> lsm_for_each_raw(lsm) {
> if (exists_ordered_lsm(lsm))
> continue;
> - set_enabled(lsm, false);
> + lsm_enabled_set(lsm, false);
> init_debug("%s skipped: %s (not in requested order)\n",
> origin, lsm->id->name);
> }
> @@ -319,12 +319,12 @@ static void __init lsm_init_ordered(void)
>
> pr_info("initializing lsm=");
> lsm_early_for_each_raw(early) {
> - if (is_enabled(early))
> + if (lsm_is_enabled(early))
> pr_cont("%s%s",
> first++ == 0 ? "" : ",", early->id->name);
> }
> lsm_order_for_each(lsm) {
> - if (is_enabled(*lsm))
> + if (lsm_is_enabled(*lsm))
> pr_cont("%s%s",
> first++ == 0 ? "" : ",", (*lsm)->id->name);
> }
> @@ -440,7 +440,7 @@ int __init security_init(void)
> */
> lsm_early_for_each_raw(lsm) {
> init_debug(" early started: %s (%s)\n", lsm->id->name,
> - is_enabled(lsm) ? "enabled" : "disabled");
> + lsm_is_enabled(lsm) ? "enabled" : "disabled");
> }
>
> /* Load LSMs in specified order. */
^ permalink raw reply
* Re: [PATCH v4 10/34] lsm: rework lsm_active_cnt and lsm_idlist[]
From: Mimi Zohar @ 2025-09-19 19:02 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: John Johansen, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250916220355.252592-46-paul@paul-moore.com>
On Tue, 2025-09-16 at 18:03 -0400, Paul Moore wrote:
> Move the LSM active count and lsm_id list declarations out of a header
> that is visible across the kernel and into a header that is limited to
> the LSM framework. This not only helps keep the include/linux headers
> smaller and cleaner, it helps prevent misuse of these variables.
>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> Reviewed-by: John Johansen <john.johhansen@canonical.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
> include/linux/security.h | 2 --
> security/lsm.h | 5 +++++
> security/lsm_init.c | 6 ------
> security/lsm_syscalls.c | 2 ++
> security/security.c | 3 +++
> 5 files changed, 10 insertions(+), 8 deletions(-)
>
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 521bcb5b9717..8560c50edd2e 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -167,8 +167,6 @@ struct lsm_prop {
> };
>
> extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1];
> -extern u32 lsm_active_cnt;
> -extern const struct lsm_id *lsm_idlist[];
>
> /* These functions are in security/commoncap.c */
> extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
> diff --git a/security/lsm.h b/security/lsm.h
> index 0e1731bad4a7..dbe755c45e57 100644
> --- a/security/lsm.h
> +++ b/security/lsm.h
> @@ -7,6 +7,11 @@
> #define _LSM_H_
>
> #include <linux/lsm_hooks.h>
> +#include <linux/lsm_count.h>
> +
> +/* List of configured LSMs */
> +extern unsigned int lsm_active_cnt;
> +extern const struct lsm_id *lsm_idlist[];
>
> /* LSM blob configuration */
> extern struct lsm_blob_sizes blob_sizes;
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 2e76cefb1585..9e495a36a332 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -217,12 +217,6 @@ static void __init initialize_lsm(struct lsm_info *lsm)
> }
> }
>
> -/*
> - * Current index to use while initializing the lsm id list.
> - */
> -u32 lsm_active_cnt __ro_after_init;
> -const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
> -
> /* Populate ordered LSMs list from comma-separated LSM name list. */
> static void __init ordered_lsm_parse(const char *order, const char *origin)
> {
> diff --git a/security/lsm_syscalls.c b/security/lsm_syscalls.c
> index 8440948a690c..5648b1f0ce9c 100644
> --- a/security/lsm_syscalls.c
> +++ b/security/lsm_syscalls.c
> @@ -17,6 +17,8 @@
> #include <linux/lsm_hooks.h>
> #include <uapi/linux/lsm.h>
>
> +#include "lsm.h"
> +
> /**
> * lsm_name_to_attr - map an LSM attribute name to its ID
> * @name: name of the attribute
> diff --git a/security/security.c b/security/security.c
> index ff6da6735e2a..add46073af0c 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -73,6 +73,9 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = {
> [LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
> };
>
> +unsigned int lsm_active_cnt __ro_after_init;
> +const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
> +
> struct lsm_blob_sizes blob_sizes;
>
> struct kmem_cache *lsm_file_cache;
^ permalink raw reply
* Re: [PATCH v4 09/34] lsm: rename the lsm order variables for consistency
From: Mimi Zohar @ 2025-09-19 19:02 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: John Johansen, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250916220355.252592-45-paul@paul-moore.com>
On Tue, 2025-09-16 at 18:03 -0400, Paul Moore wrote:
> Rename the builtin_lsm_order variable to lsm_order_builtin,
> chosen_lsm_order to lsm_order_cmdline, chosen_major_lsm to
> lsm_order_legacy, ordered_lsms[] to lsm_order[], and exclusive
> to lsm_exclusive.
>
> This patch also renames the associated kernel command line parsing
> functions and adds some basic function comment blocks. The parsing
> function choose_major_lsm() was renamed to lsm_choose_security(),
> choose_lsm_order() to lsm_choose_lsm(), and enable_debug() to
> lsm_debug_enable().
>
> Reviewed-by: Kees Cook <kees@kernel.org>
> Reviewed-by: John Johansen <john.johansen@canonical.com>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
> security/lsm_init.c | 86 +++++++++++++++++++++++++--------------------
> 1 file changed, 48 insertions(+), 38 deletions(-)
>
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 628f54790360..2e76cefb1585 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -16,14 +16,14 @@ char *lsm_names;
> extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
> extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
>
> -/* Boot-time LSM user choice */
> -static __initconst const char *const builtin_lsm_order = CONFIG_LSM;
> -static __initdata const char *chosen_lsm_order;
> -static __initdata const char *chosen_major_lsm;
> +/* Build and boot-time LSM ordering. */
> +static __initconst const char *const lsm_order_builtin = CONFIG_LSM;
> +static __initdata const char *lsm_order_cmdline;
> +static __initdata const char *lsm_order_legacy;
>
> /* Ordered list of LSMs to initialize. */
> -static __initdata struct lsm_info *ordered_lsms[MAX_LSM_COUNT + 1];
> -static __initdata struct lsm_info *exclusive;
> +static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
> +static __initdata struct lsm_info *lsm_exclusive;
>
> static __initdata bool debug;
> #define init_debug(...) \
> @@ -33,7 +33,7 @@ static __initdata bool debug;
> } while (0)
>
> #define lsm_order_for_each(iter) \
> - for ((iter) = ordered_lsms; *(iter); (iter)++)
> + for ((iter) = lsm_order; *(iter); (iter)++)
> #define lsm_for_each_raw(iter) \
> for ((iter) = __start_lsm_info; \
> (iter) < __end_lsm_info; (iter)++)
> @@ -41,31 +41,41 @@ static __initdata bool debug;
> for ((iter) = __start_early_lsm_info; \
> (iter) < __end_early_lsm_info; (iter)++)
>
> -static int lsm_append(const char *new, char **result);
> -
> -/* Save user chosen LSM */
> -static int __init choose_major_lsm(char *str)
> +/**
> + * lsm_choose_security - Legacy "major" LSM selection
> + * @str: kernel command line parameter
> + */
> +static int __init lsm_choose_security(char *str)
> {
> - chosen_major_lsm = str;
> + lsm_order_legacy = str;
> return 1;
> }
> -__setup("security=", choose_major_lsm);
> +__setup("security=", lsm_choose_security);
>
> -/* Explicitly choose LSM initialization order. */
> -static int __init choose_lsm_order(char *str)
> +/**
> + * lsm_choose_lsm - Modern LSM selection
> + * @str: kernel command line parameter
> + */
> +static int __init lsm_choose_lsm(char *str)
> {
> - chosen_lsm_order = str;
> + lsm_order_cmdline = str;
> return 1;
> }
> -__setup("lsm=", choose_lsm_order);
> +__setup("lsm=", lsm_choose_lsm);
>
> -/* Enable LSM order debugging. */
> -static int __init enable_debug(char *str)
> +/**
> + * lsm_debug_enable - Enable LSM framework debugging
> + * @str: kernel command line parameter
> + *
> + * Currently we only provide debug info during LSM initialization, but we may
> + * want to expand this in the future.
> + */
> +static int __init lsm_debug_enable(char *str)
> {
> debug = true;
> return 1;
> }
> -__setup("lsm.debug", enable_debug);
> +__setup("lsm.debug", lsm_debug_enable);
>
> /* Mark an LSM's enabled flag. */
> static int lsm_enabled_true __initdata = 1;
> @@ -127,7 +137,7 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
> /* Enable this LSM, if it is not already set. */
> if (!lsm->enabled)
> lsm->enabled = &lsm_enabled_true;
> - ordered_lsms[last_lsm] = lsm;
> + lsm_order[last_lsm] = lsm;
> lsm_idlist[last_lsm++] = lsm->id;
>
> init_debug("%s ordered: %s (%s)\n", from, lsm->id->name,
> @@ -157,7 +167,7 @@ static void __init lsm_prepare(struct lsm_info *lsm)
> if (!is_enabled(lsm)) {
> set_enabled(lsm, false);
> return;
> - } else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
> + } else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && lsm_exclusive) {
> init_debug("exclusive disabled: %s\n", lsm->id->name);
> set_enabled(lsm, false);
> return;
> @@ -165,9 +175,9 @@ static void __init lsm_prepare(struct lsm_info *lsm)
>
> /* Mark the LSM as enabled. */
> set_enabled(lsm, true);
> - if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
> + if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !lsm_exclusive) {
> init_debug("exclusive chosen: %s\n", lsm->id->name);
> - exclusive = lsm;
> + lsm_exclusive = lsm;
> }
>
> /* Register the LSM blob sizes. */
> @@ -226,7 +236,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> }
>
> /* Process "security=", if given. */
> - if (chosen_major_lsm) {
> + if (lsm_order_legacy) {
> struct lsm_info *major;
>
> /*
> @@ -237,10 +247,10 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> */
> lsm_for_each_raw(major) {
> if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
> - strcmp(major->id->name, chosen_major_lsm) != 0) {
> + strcmp(major->id->name, lsm_order_legacy) != 0) {
> set_enabled(major, false);
> init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
> - chosen_major_lsm, major->id->name);
> + lsm_order_legacy, major->id->name);
> }
> }
> }
> @@ -265,11 +275,11 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> }
>
> /* Process "security=", if given. */
> - if (chosen_major_lsm) {
> + if (lsm_order_legacy) {
> lsm_for_each_raw(lsm) {
> if (exists_ordered_lsm(lsm))
> continue;
> - if (strcmp(lsm->id->name, chosen_major_lsm) == 0)
> + if (strcmp(lsm->id->name, lsm_order_legacy) == 0)
> append_ordered_lsm(lsm, "security=");
> }
> }
> @@ -301,15 +311,15 @@ static void __init lsm_init_ordered(void)
> struct lsm_info **lsm;
> struct lsm_info *early;
>
> - if (chosen_lsm_order) {
> - if (chosen_major_lsm) {
> + if (lsm_order_cmdline) {
> + if (lsm_order_legacy) {
> pr_warn("security=%s is ignored because it is superseded by lsm=%s\n",
> - chosen_major_lsm, chosen_lsm_order);
> - chosen_major_lsm = NULL;
> + lsm_order_legacy, lsm_order_cmdline);
> + lsm_order_legacy = NULL;
> }
> - ordered_lsm_parse(chosen_lsm_order, "cmdline");
> + ordered_lsm_parse(lsm_order_cmdline, "cmdline");
> } else
> - ordered_lsm_parse(builtin_lsm_order, "builtin");
> + ordered_lsm_parse(lsm_order_builtin, "builtin");
>
> lsm_order_for_each(lsm) {
> lsm_prepare(*lsm);
> @@ -473,9 +483,9 @@ int __init security_init(void)
> {
> struct lsm_info *lsm;
>
> - init_debug("legacy security=%s\n", chosen_major_lsm ? : " *unspecified*");
> - init_debug(" CONFIG_LSM=%s\n", builtin_lsm_order);
> - init_debug("boot arg lsm=%s\n", chosen_lsm_order ? : " *unspecified*");
> + init_debug("legacy security=%s\n", lsm_order_legacy ? : " *unspecified*");
> + init_debug(" CONFIG_LSM=%s\n", lsm_order_builtin);
> + init_debug("boot arg lsm=%s\n", lsm_order_cmdline ? : " *unspecified*");
>
> /*
> * Append the names of the early LSM modules now that kmalloc() is
^ permalink raw reply
* Re: [PATCH v4 08/34] lsm: replace the name field with a pointer to the lsm_id struct
From: Mimi Zohar @ 2025-09-19 19:02 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: John Johansen, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250916220355.252592-44-paul@paul-moore.com>
On Tue, 2025-09-16 at 18:03 -0400, Paul Moore wrote:
> Reduce the duplication between the lsm_id struct and the DEFINE_LSM()
> definition by linking the lsm_id struct directly into the individual
> LSM's DEFINE_LSM() instance.
>
> Linking the lsm_id into the LSM definition also allows us to simplify
> the security_add_hooks() function by removing the code which populates
> the lsm_idlist[] array and moving it into the normal LSM startup code
> where the LSM list is parsed and the individual LSMs are enabled,
> making for a cleaner implementation with less overhead at boot.
>
> Reviewed-by: Kees Cook <kees@kernel.org>
> Reviewed-by: John Johansen <john.johansen@canonical.com>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
> include/linux/lsm_hooks.h | 2 +-
> security/apparmor/lsm.c | 2 +-
> security/bpf/hooks.c | 2 +-
> security/commoncap.c | 2 +-
> security/integrity/evm/evm_main.c | 2 +-
> security/integrity/ima/ima_main.c | 2 +-
> security/ipe/ipe.c | 2 +-
> security/landlock/setup.c | 2 +-
> security/loadpin/loadpin.c | 2 +-
> security/lockdown/lockdown.c | 2 +-
> security/lsm_init.c | 45 +++++++++++++------------------
> security/safesetid/lsm.c | 2 +-
> security/selinux/hooks.c | 2 +-
> security/smack/smack_lsm.c | 2 +-
> security/tomoyo/tomoyo.c | 2 +-
> security/yama/yama_lsm.c | 2 +-
> 16 files changed, 33 insertions(+), 42 deletions(-)
>
> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> index 0112926ed923..7343dd60b1d5 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -152,7 +152,7 @@ enum lsm_order {
> };
>
> struct lsm_info {
> - const char *name; /* Required. */
> + const struct lsm_id *id;
> enum lsm_order order; /* Optional: default is LSM_ORDER_MUTABLE */
> unsigned long flags; /* Optional: flags describing LSM */
> int *enabled; /* Optional: controlled by CONFIG_LSM */
> diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
> index 8e1cc229b41b..45b3a304d525 100644
> --- a/security/apparmor/lsm.c
> +++ b/security/apparmor/lsm.c
> @@ -2552,7 +2552,7 @@ static int __init apparmor_init(void)
> }
>
> DEFINE_LSM(apparmor) = {
> - .name = "apparmor",
> + .id = &apparmor_lsmid,
> .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
> .enabled = &apparmor_enabled,
> .blobs = &apparmor_blob_sizes,
> diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c
> index db759025abe1..40efde233f3a 100644
> --- a/security/bpf/hooks.c
> +++ b/security/bpf/hooks.c
> @@ -33,7 +33,7 @@ struct lsm_blob_sizes bpf_lsm_blob_sizes __ro_after_init = {
> };
>
> DEFINE_LSM(bpf) = {
> - .name = "bpf",
> + .id = &bpf_lsmid,
> .init = bpf_lsm_init,
> .blobs = &bpf_lsm_blob_sizes
> };
> diff --git a/security/commoncap.c b/security/commoncap.c
> index 6bd4adeb4795..b50479bd0286 100644
> --- a/security/commoncap.c
> +++ b/security/commoncap.c
> @@ -1505,7 +1505,7 @@ static int __init capability_init(void)
> }
>
> DEFINE_LSM(capability) = {
> - .name = "capability",
> + .id = &capability_lsmid,
> .order = LSM_ORDER_FIRST,
> .init = capability_init,
> };
> diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
> index 0add782e73ba..db8e324ed4e6 100644
> --- a/security/integrity/evm/evm_main.c
> +++ b/security/integrity/evm/evm_main.c
> @@ -1175,7 +1175,7 @@ struct lsm_blob_sizes evm_blob_sizes __ro_after_init = {
> };
>
> DEFINE_LSM(evm) = {
> - .name = "evm",
> + .id = &evm_lsmid,
> .init = init_evm_lsm,
> .order = LSM_ORDER_LAST,
> .blobs = &evm_blob_sizes,
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index cdd225f65a62..eade8e1e3cb1 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -1279,7 +1279,7 @@ struct lsm_blob_sizes ima_blob_sizes __ro_after_init = {
> };
>
> DEFINE_LSM(ima) = {
> - .name = "ima",
> + .id = &ima_lsmid,
> .init = init_ima_lsm,
> .order = LSM_ORDER_LAST,
> .blobs = &ima_blob_sizes,
> diff --git a/security/ipe/ipe.c b/security/ipe/ipe.c
> index 4317134cb0da..2426441181dc 100644
> --- a/security/ipe/ipe.c
> +++ b/security/ipe/ipe.c
> @@ -92,7 +92,7 @@ static int __init ipe_init(void)
> }
>
> DEFINE_LSM(ipe) = {
> - .name = "ipe",
> + .id = &ipe_lsmid,
> .init = ipe_init,
> .blobs = &ipe_blobs,
> };
> diff --git a/security/landlock/setup.c b/security/landlock/setup.c
> index bd53c7a56ab9..47dac1736f10 100644
> --- a/security/landlock/setup.c
> +++ b/security/landlock/setup.c
> @@ -75,7 +75,7 @@ static int __init landlock_init(void)
> }
>
> DEFINE_LSM(LANDLOCK_NAME) = {
> - .name = LANDLOCK_NAME,
> + .id = &landlock_lsmid,
> .init = landlock_init,
> .blobs = &landlock_blob_sizes,
> };
> diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c
> index 68252452b66c..b9ddf05c5c16 100644
> --- a/security/loadpin/loadpin.c
> +++ b/security/loadpin/loadpin.c
> @@ -271,7 +271,7 @@ static int __init loadpin_init(void)
> }
>
> DEFINE_LSM(loadpin) = {
> - .name = "loadpin",
> + .id = &loadpin_lsmid,
> .init = loadpin_init,
> };
>
> diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c
> index cf83afa1d879..4813f168ff93 100644
> --- a/security/lockdown/lockdown.c
> +++ b/security/lockdown/lockdown.c
> @@ -168,6 +168,6 @@ DEFINE_EARLY_LSM(lockdown) = {
> #else
> DEFINE_LSM(lockdown) = {
> #endif
> - .name = "lockdown",
> + .id = &lockdown_lsmid,
> .init = lockdown_lsm_init,
> };
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 4a108b03c23d..628f54790360 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -127,9 +127,10 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
> /* Enable this LSM, if it is not already set. */
> if (!lsm->enabled)
> lsm->enabled = &lsm_enabled_true;
> - ordered_lsms[last_lsm++] = lsm;
> + ordered_lsms[last_lsm] = lsm;
> + lsm_idlist[last_lsm++] = lsm->id;
>
> - init_debug("%s ordered: %s (%s)\n", from, lsm->name,
> + init_debug("%s ordered: %s (%s)\n", from, lsm->id->name,
> is_enabled(lsm) ? "enabled" : "disabled");
> }
>
> @@ -157,7 +158,7 @@ static void __init lsm_prepare(struct lsm_info *lsm)
> set_enabled(lsm, false);
> return;
> } else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
> - init_debug("exclusive disabled: %s\n", lsm->name);
> + init_debug("exclusive disabled: %s\n", lsm->id->name);
> set_enabled(lsm, false);
> return;
> }
> @@ -165,7 +166,7 @@ static void __init lsm_prepare(struct lsm_info *lsm)
> /* Mark the LSM as enabled. */
> set_enabled(lsm, true);
> if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
> - init_debug("exclusive chosen: %s\n", lsm->name);
> + init_debug("exclusive chosen: %s\n", lsm->id->name);
> exclusive = lsm;
> }
>
> @@ -200,9 +201,9 @@ static void __init initialize_lsm(struct lsm_info *lsm)
> if (is_enabled(lsm)) {
> int ret;
>
> - init_debug("initializing %s\n", lsm->name);
> + init_debug("initializing %s\n", lsm->id->name);
> ret = lsm->init();
> - WARN(ret, "%s failed to initialize: %d\n", lsm->name, ret);
> + WARN(ret, "%s failed to initialize: %d\n", lsm->id->name, ret);
> }
> }
>
> @@ -236,10 +237,10 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> */
> lsm_for_each_raw(major) {
> if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
> - strcmp(major->name, chosen_major_lsm) != 0) {
> + strcmp(major->id->name, chosen_major_lsm) != 0) {
> set_enabled(major, false);
> init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
> - chosen_major_lsm, major->name);
> + chosen_major_lsm, major->id->name);
> }
> }
> }
> @@ -251,7 +252,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> bool found = false;
>
> lsm_for_each_raw(lsm) {
> - if (strcmp(lsm->name, name) == 0) {
> + if (strcmp(lsm->id->name, name) == 0) {
> if (lsm->order == LSM_ORDER_MUTABLE)
> append_ordered_lsm(lsm, origin);
> found = true;
> @@ -268,7 +269,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> lsm_for_each_raw(lsm) {
> if (exists_ordered_lsm(lsm))
> continue;
> - if (strcmp(lsm->name, chosen_major_lsm) == 0)
> + if (strcmp(lsm->id->name, chosen_major_lsm) == 0)
> append_ordered_lsm(lsm, "security=");
> }
> }
> @@ -285,7 +286,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> continue;
> set_enabled(lsm, false);
> init_debug("%s skipped: %s (not in requested order)\n",
> - origin, lsm->name);
> + origin, lsm->id->name);
> }
>
> kfree(sep);
> @@ -317,11 +318,13 @@ static void __init lsm_init_ordered(void)
> pr_info("initializing lsm=");
> lsm_early_for_each_raw(early) {
> if (is_enabled(early))
> - pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
> + pr_cont("%s%s",
> + first++ == 0 ? "" : ",", early->id->name);
> }
> lsm_order_for_each(lsm) {
> if (is_enabled(*lsm))
> - pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
> + pr_cont("%s%s",
> + first++ == 0 ? "" : ",", (*lsm)->id->name);
> }
> pr_cont("\n");
>
> @@ -432,18 +435,6 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
> {
> int i;
>
> - /*
> - * A security module may call security_add_hooks() more
> - * than once during initialization, and LSM initialization
> - * is serialized. Landlock is one such case.
> - * Look at the previous entry, if there is one, for duplication.
> - */
> - if (lsm_active_cnt == 0 || lsm_idlist[lsm_active_cnt - 1] != lsmid) {
> - if (lsm_active_cnt >= MAX_LSM_COUNT)
> - panic("%s Too many LSMs registered.\n", __func__);
> - lsm_idlist[lsm_active_cnt++] = lsmid;
> - }
> -
> for (i = 0; i < count; i++) {
> hooks[i].lsmid = lsmid;
> lsm_static_call_init(&hooks[i]);
> @@ -491,10 +482,10 @@ int __init security_init(void)
> * available
> */
> lsm_early_for_each_raw(lsm) {
> - init_debug(" early started: %s (%s)\n", lsm->name,
> + init_debug(" early started: %s (%s)\n", lsm->id->name,
> is_enabled(lsm) ? "enabled" : "disabled");
> if (lsm->enabled)
> - lsm_append(lsm->name, &lsm_names);
> + lsm_append(lsm->id->name, &lsm_names);
> }
>
> /* Load LSMs in specified order. */
> diff --git a/security/safesetid/lsm.c b/security/safesetid/lsm.c
> index 1ba564f097f5..9a7c68d4e642 100644
> --- a/security/safesetid/lsm.c
> +++ b/security/safesetid/lsm.c
> @@ -287,6 +287,6 @@ static int __init safesetid_security_init(void)
> }
>
> DEFINE_LSM(safesetid_security_init) = {
> + .id = &safesetid_lsmid,
> .init = safesetid_security_init,
> - .name = "safesetid",
> };
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 4da5e792b42e..d94b1ff316ba 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -7630,7 +7630,7 @@ void selinux_complete_init(void)
> /* SELinux requires early initialization in order to label
> all processes and objects when they are created. */
> DEFINE_LSM(selinux) = {
> - .name = "selinux",
> + .id = &selinux_lsmid,
> .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
> .enabled = &selinux_enabled_boot,
> .blobs = &selinux_blob_sizes,
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index fc340a6f0dde..e09490c75f59 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -5275,7 +5275,7 @@ static __init int smack_init(void)
> * all processes and objects when they are created.
> */
> DEFINE_LSM(smack) = {
> - .name = "smack",
> + .id = &smack_lsmid,
> .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
> .blobs = &smack_blob_sizes,
> .init = smack_init,
> diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
> index d6ebcd9db80a..ed0f7b052a85 100644
> --- a/security/tomoyo/tomoyo.c
> +++ b/security/tomoyo/tomoyo.c
> @@ -612,7 +612,7 @@ static int __init tomoyo_init(void)
> }
>
> DEFINE_LSM(tomoyo) = {
> - .name = "tomoyo",
> + .id = &tomoyo_lsmid,
> .enabled = &tomoyo_enabled,
> .flags = LSM_FLAG_LEGACY_MAJOR,
> .blobs = &tomoyo_blob_sizes,
> diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
> index 3d064dd4e03f..38b21ee0c560 100644
> --- a/security/yama/yama_lsm.c
> +++ b/security/yama/yama_lsm.c
> @@ -476,6 +476,6 @@ static int __init yama_init(void)
> }
>
> DEFINE_LSM(yama) = {
> - .name = "yama",
> + .id = &yama_lsmid,
> .init = yama_init,
> };
^ permalink raw reply
* Re: [PATCH v3 00/35] Compiler-Based Capability- and Locking-Analysis
From: Bart Van Assche @ 2025-09-19 17:20 UTC (permalink / raw)
To: Christoph Hellwig, Nathan Chancellor
Cc: Marco Elver, Peter Zijlstra, Boqun Feng, Ingo Molnar, Will Deacon,
David S. Miller, Luc Van Oostenryck, Paul E. McKenney,
Alexander Potapenko, Arnd Bergmann, Bill Wendling, Dmitry Vyukov,
Eric Dumazet, Frederic Weisbecker, Greg Kroah-Hartman, Herbert Xu,
Ian Rogers, Jann Horn, Joel Fernandes, Jonathan Corbet,
Josh Triplett, Justin Stitt, Kees Cook, Kentaro Takeda,
Lukas Bulwahn, Mark Rutland, Mathieu Desnoyers, Miguel Ojeda,
Neeraj Upadhyay, Nick Desaulniers, Steven Rostedt, Tetsuo Handa,
Thomas Gleixner, Thomas Graf, Uladzislau Rezki, Waiman Long,
kasan-dev, linux-crypto, linux-doc, linux-kbuild, linux-kernel,
linux-mm, linux-security-module, linux-sparse, llvm, rcu
In-Reply-To: <20250919140803.GA23745@lst.de>
On 9/19/25 7:08 AM, Christoph Hellwig wrote:
> 3) Wrappers that take multiple locks conditionally
>
> We have helpers that take different locks in the same object based on the
> arguments like xfs_ilock() or those that take the same lock and a variable
> number of objects like xfs_dqlockn based on input and sorting. The
> first are just historic and we might want to kill them, but the
> sorting of objects to acquire locks in order thing is a pattern in
> various places including the VFS, so we'll need some way to annotate it.
Hi Christoph,
As you probably remember some time ago I took a look myself at adding
locking annotations to kernel code. I ended up annotating multiple XFS
functions with NO_THREAD_SAFETY_ANALYSIS. Maybe the locking patterns in
XFS are too complex for compile-time analysis? See also the XFS changes
in
https://lore.kernel.org/lkml/20250206175114.1974171-33-bvanassche@acm.org/.
Thanks,
Bart.
^ permalink raw reply
* Re: [RFC PATCH 1/6] landlock: Add a place for flags to layer rules
From: Mickaël Salaün @ 2025-09-19 16:02 UTC (permalink / raw)
To: Tingmao Wang; +Cc: Günther Noack, Jan Kara, linux-security-module
In-Reply-To: <841550c5d7bbc7ffcd74f85ee659caf1e29cff67.1757376311.git.m@maowtm.org>
On Tue, Sep 09, 2025 at 01:06:35AM +0100, Tingmao Wang wrote:
> To avoid unnecessarily increasing the size of struct landlock_layer, we
> make the layer level a u8 and use the space to store the flags struct.
>
> Signed-off-by: Tingmao Wang <m@maowtm.org>
> ---
> security/landlock/fs.c | 75 ++++++++++++++++++++++++-------------
> security/landlock/net.c | 3 +-
> security/landlock/ruleset.c | 9 ++++-
> security/landlock/ruleset.h | 27 ++++++++++++-
> 4 files changed, 83 insertions(+), 31 deletions(-)
>
> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
> index c04f8879ad03..e7eaf55093e9 100644
> --- a/security/landlock/fs.c
> +++ b/security/landlock/fs.c
> @@ -756,10 +756,12 @@ static bool is_access_to_paths_allowed(
> const struct path *const path,
> const access_mask_t access_request_parent1,
> layer_mask_t (*const layer_masks_parent1)[LANDLOCK_NUM_ACCESS_FS],
> + struct collected_rule_flags *const rule_flags_parent1,
> struct landlock_request *const log_request_parent1,
> struct dentry *const dentry_child1,
> const access_mask_t access_request_parent2,
> layer_mask_t (*const layer_masks_parent2)[LANDLOCK_NUM_ACCESS_FS],
> + struct collected_rule_flags *const rule_flags_parent2,
> struct landlock_request *const log_request_parent2,
> struct dentry *const dentry_child2)
> {
> @@ -810,22 +812,30 @@ static bool is_access_to_paths_allowed(
> }
>
> if (unlikely(dentry_child1)) {
> + /*
> + * The rule_flags for child1 should have been included in
> + * rule_flags_masks_parent1 already. We do not bother about it
> + * for domain check.
> + */
> landlock_unmask_layers(
> find_rule(domain, dentry_child1),
> landlock_init_layer_masks(
> domain, LANDLOCK_MASK_ACCESS_FS,
> &_layer_masks_child1, LANDLOCK_KEY_INODE),
> - &_layer_masks_child1, ARRAY_SIZE(_layer_masks_child1));
> + &_layer_masks_child1, ARRAY_SIZE(_layer_masks_child1),
> + NULL);
> layer_masks_child1 = &_layer_masks_child1;
> child1_is_directory = d_is_dir(dentry_child1);
> }
> if (unlikely(dentry_child2)) {
> + /* See above comment for why NULL is passed as rule_flags_masks */
> landlock_unmask_layers(
> find_rule(domain, dentry_child2),
> landlock_init_layer_masks(
> domain, LANDLOCK_MASK_ACCESS_FS,
> &_layer_masks_child2, LANDLOCK_KEY_INODE),
> - &_layer_masks_child2, ARRAY_SIZE(_layer_masks_child2));
> + &_layer_masks_child2, ARRAY_SIZE(_layer_masks_child2),
> + NULL);
> layer_masks_child2 = &_layer_masks_child2;
> child2_is_directory = d_is_dir(dentry_child2);
> }
> @@ -881,16 +891,18 @@ static bool is_access_to_paths_allowed(
> }
>
> rule = find_rule(domain, walker_path.dentry);
> - allowed_parent1 = allowed_parent1 ||
> - landlock_unmask_layers(
> - rule, access_masked_parent1,
> - layer_masks_parent1,
> - ARRAY_SIZE(*layer_masks_parent1));
> - allowed_parent2 = allowed_parent2 ||
> - landlock_unmask_layers(
> - rule, access_masked_parent2,
> - layer_masks_parent2,
> - ARRAY_SIZE(*layer_masks_parent2));
> + allowed_parent1 =
> + allowed_parent1 ||
> + landlock_unmask_layers(rule, access_masked_parent1,
> + layer_masks_parent1,
> + ARRAY_SIZE(*layer_masks_parent1),
> + rule_flags_parent1);
> + allowed_parent2 =
> + allowed_parent2 ||
> + landlock_unmask_layers(rule, access_masked_parent2,
> + layer_masks_parent2,
> + ARRAY_SIZE(*layer_masks_parent2),
> + rule_flags_parent2);
>
> /* Stops when a rule from each layer grants access. */
> if (allowed_parent1 && allowed_parent2)
> @@ -958,6 +970,7 @@ static int current_check_access_path(const struct path *const path,
> const struct landlock_cred_security *const subject =
> landlock_get_applicable_subject(current_cred(), masks, NULL);
> layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {};
> + struct collected_rule_flags rule_flags = {};
> struct landlock_request request = {};
>
> if (!subject)
> @@ -967,8 +980,8 @@ static int current_check_access_path(const struct path *const path,
> access_request, &layer_masks,
> LANDLOCK_KEY_INODE);
> if (is_access_to_paths_allowed(subject->domain, path, access_request,
> - &layer_masks, &request, NULL, 0, NULL,
> - NULL, NULL))
> + &layer_masks, &rule_flags, &request,
> + NULL, 0, NULL, NULL, NULL, NULL))
> return 0;
>
> landlock_log_denial(subject, &request);
> @@ -1032,7 +1045,8 @@ static access_mask_t maybe_remove(const struct dentry *const dentry)
> static bool collect_domain_accesses(
> const struct landlock_ruleset *const domain,
> const struct dentry *const mnt_root, struct dentry *dir,
> - layer_mask_t (*const layer_masks_dom)[LANDLOCK_NUM_ACCESS_FS])
> + layer_mask_t (*const layer_masks_dom)[LANDLOCK_NUM_ACCESS_FS],
> + struct collected_rule_flags *const rule_flags)
> {
> unsigned long access_dom;
> bool ret = false;
> @@ -1051,9 +1065,9 @@ static bool collect_domain_accesses(
> struct dentry *parent_dentry;
>
> /* Gets all layers allowing all domain accesses. */
> - if (landlock_unmask_layers(find_rule(domain, dir), access_dom,
> - layer_masks_dom,
> - ARRAY_SIZE(*layer_masks_dom))) {
> + if (landlock_unmask_layers(
> + find_rule(domain, dir), access_dom, layer_masks_dom,
> + ARRAY_SIZE(*layer_masks_dom), rule_flags)) {
> /*
> * Stops when all handled accesses are allowed by at
> * least one rule in each layer.
> @@ -1140,6 +1154,8 @@ static int current_check_refer_path(struct dentry *const old_dentry,
> struct dentry *old_parent;
> layer_mask_t layer_masks_parent1[LANDLOCK_NUM_ACCESS_FS] = {},
> layer_masks_parent2[LANDLOCK_NUM_ACCESS_FS] = {};
> + struct collected_rule_flags rule_flags_parent1 = {},
> + rule_flags_parent2 = {};
> struct landlock_request request1 = {}, request2 = {};
>
> if (!subject)
> @@ -1172,10 +1188,10 @@ static int current_check_refer_path(struct dentry *const old_dentry,
> subject->domain,
> access_request_parent1 | access_request_parent2,
> &layer_masks_parent1, LANDLOCK_KEY_INODE);
> - if (is_access_to_paths_allowed(subject->domain, new_dir,
> - access_request_parent1,
> - &layer_masks_parent1, &request1,
> - NULL, 0, NULL, NULL, NULL))
> + if (is_access_to_paths_allowed(
> + subject->domain, new_dir, access_request_parent1,
> + &layer_masks_parent1, &rule_flags_parent1,
> + &request1, NULL, 0, NULL, NULL, NULL, NULL))
> return 0;
>
> landlock_log_denial(subject, &request1);
> @@ -1201,10 +1217,12 @@ static int current_check_refer_path(struct dentry *const old_dentry,
> /* new_dir->dentry is equal to new_dentry->d_parent */
> allow_parent1 = collect_domain_accesses(subject->domain, mnt_dir.dentry,
> old_parent,
> - &layer_masks_parent1);
> + &layer_masks_parent1,
> + &rule_flags_parent1);
> allow_parent2 = collect_domain_accesses(subject->domain, mnt_dir.dentry,
> new_dir->dentry,
> - &layer_masks_parent2);
> + &layer_masks_parent2,
> + &rule_flags_parent2);
>
> if (allow_parent1 && allow_parent2)
> return 0;
> @@ -1217,8 +1235,9 @@ static int current_check_refer_path(struct dentry *const old_dentry,
> */
> if (is_access_to_paths_allowed(
> subject->domain, &mnt_dir, access_request_parent1,
> - &layer_masks_parent1, &request1, old_dentry,
> - access_request_parent2, &layer_masks_parent2, &request2,
> + &layer_masks_parent1, &rule_flags_parent1, &request1,
> + old_dentry, access_request_parent2, &layer_masks_parent2,
> + &rule_flags_parent2, &request2,
> exchange ? new_dentry : NULL))
> return 0;
>
> @@ -1616,6 +1635,7 @@ static bool is_device(const struct file *const file)
> static int hook_file_open(struct file *const file)
> {
> layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {};
> + struct collected_rule_flags rule_flags = {};
> access_mask_t open_access_request, full_access_request, allowed_access,
> optional_access;
> const struct landlock_cred_security *const subject =
> @@ -1647,7 +1667,8 @@ static int hook_file_open(struct file *const file)
> landlock_init_layer_masks(subject->domain,
> full_access_request, &layer_masks,
> LANDLOCK_KEY_INODE),
> - &layer_masks, &request, NULL, 0, NULL, NULL, NULL)) {
> + &layer_masks, &rule_flags, &request, NULL, 0, NULL, NULL,
> + NULL, NULL)) {
> allowed_access = full_access_request;
> } else {
> unsigned long access_bit;
> diff --git a/security/landlock/net.c b/security/landlock/net.c
> index 1f3915a90a80..fc6369dffa51 100644
> --- a/security/landlock/net.c
> +++ b/security/landlock/net.c
> @@ -48,6 +48,7 @@ static int current_check_access_socket(struct socket *const sock,
> {
> __be16 port;
> layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_NET] = {};
> + struct collected_rule_flags rule_flags = {};
> const struct landlock_rule *rule;
> struct landlock_id id = {
> .type = LANDLOCK_KEY_NET_PORT,
> @@ -179,7 +180,7 @@ static int current_check_access_socket(struct socket *const sock,
> access_request, &layer_masks,
> LANDLOCK_KEY_NET_PORT);
> if (landlock_unmask_layers(rule, access_request, &layer_masks,
> - ARRAY_SIZE(layer_masks)))
> + ARRAY_SIZE(layer_masks), &rule_flags))
> return 0;
>
> audit_net.family = address->sa_family;
> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
> index ce7940efea51..3aa4e33ac95b 100644
> --- a/security/landlock/ruleset.c
> +++ b/security/landlock/ruleset.c
> @@ -616,7 +616,8 @@ landlock_find_rule(const struct landlock_ruleset *const ruleset,
> bool landlock_unmask_layers(const struct landlock_rule *const rule,
> const access_mask_t access_request,
> layer_mask_t (*const layer_masks)[],
> - const size_t masks_array_size)
> + const size_t masks_array_size,
> + struct collected_rule_flags *const rule_flags)
> {
> size_t layer_level;
>
> @@ -643,6 +644,12 @@ bool landlock_unmask_layers(const struct landlock_rule *const rule,
> unsigned long access_bit;
> bool is_empty;
>
> + if (rule_flags) {
> + /* Collect rule flags for each layer */
> + if (layer->flags.quiet)
> + rule_flags->quiet_masks |= layer_bit;
This patch makes quiet flags related to on object, but not tied to the
rule access rights (as explained in the next patch's doc). To tie it to
rule access rights would require to duplicate the access bits for each
rule (because multiple rules can be tied to the same object for the same
layer/ruleset).
So, the question is, what do we really need to mute?
I think the current approach is enough. We could still add a new flag in
the future, or maybe even a new field to each rule type. However, we
should rename the flag to make it clear that the it's related to the
rule's object which is muted instead of the whole rule. Maybe something
like LANDLOCK_ADD_RULE_QUIET_OBJECT?
If we want to have a more fine-grained control, a complementary patch
could add a bitfield for each access right type to quiet a denied access
right iff the object is also quiet (where rules are possible). That
could be a follow up to complete this quiet feature, but this patch
series is good on its own.
> + }
> +
> /*
> * Records in @layer_masks which layer grants access to each
> * requested access.
> diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
> index 5da9a64f5af7..d4b70b6af137 100644
> --- a/security/landlock/ruleset.h
> +++ b/security/landlock/ruleset.h
> @@ -29,7 +29,18 @@ struct landlock_layer {
> /**
> * @level: Position of this layer in the layer stack.
> */
> - u16 level;
> + u8 level;
> + /**
> + * @flags: Bitfield for special flags attached to this rule.
> + */
> + struct {
> + /**
> + * @quiet: Suppresses denial audit logs for the object covered by
> + * this rule in this domain. For fs rules, this inherits down the
Please use filesystem instead of fs.
> + * file hierarchy.
> + */
> + bool quiet:1;
> + } flags;
> /**
> * @access: Bitfield of allowed actions on the kernel object. They are
> * relative to the object type (e.g. %LANDLOCK_ACTION_FS_READ).
> @@ -37,6 +48,17 @@ struct landlock_layer {
> access_mask_t access;
> };
>
> +
Extra new line.
> +/**
> + * struct collected_rule_flags - Hold accumulated flags for each layer
> + */
> +struct collected_rule_flags {
> + /**
> + * @quiet_masks: Layers for which the quiet flag is effective.
> + */
> + layer_mask_t quiet_masks;
> +};
> +
> /**
> * union landlock_key - Key of a ruleset's red-black tree
> */
> @@ -304,7 +326,8 @@ landlock_get_scope_mask(const struct landlock_ruleset *const ruleset,
> bool landlock_unmask_layers(const struct landlock_rule *const rule,
> const access_mask_t access_request,
> layer_mask_t (*const layer_masks)[],
> - const size_t masks_array_size);
> + const size_t masks_array_size,
> + struct collected_rule_flags *const rule_flags);
>
> access_mask_t
> landlock_init_layer_masks(const struct landlock_ruleset *const domain,
> --
> 2.51.0
>
>
^ permalink raw reply
* Re: [RFC PATCH 0/6] Implement LANDLOCK_ADD_RULE_QUIET
From: Mickaël Salaün @ 2025-09-19 16:01 UTC (permalink / raw)
To: Tingmao Wang; +Cc: Günther Noack, Jan Kara, linux-security-module
In-Reply-To: <cover.1757376311.git.m@maowtm.org>
Hi Tingmao,
I have a few comments but overall this series looks very good. Thanks!
On Tue, Sep 09, 2025 at 01:06:34AM +0100, Tingmao Wang wrote:
> Hi Mickaël,
>
> This RFC patch series implements a first pass patch of the "quiet flag"
> feature as proposed in [1]. I've evolved the design beyond the original
> discussion to come up with what I believe would be most useful. For this
> implementation:
>
> - The user can set the quiet flag for a layer on any part of the fs
> hierarchy, and the flag inherits down (no support for "cancelling" the
> inheritance of the flag in specific subdirectories).
>
> - The youngest layer that denies a request gets to decide whether the
> denial is audited or not. This means that a compromised binary, for
> example, cannot "turn off" Landlock auditing when it tries to access
> files, unless it denies access to the files itself. There is some
> debate to be had on whether, if a parent layer sets the quiet flag, but
> the request is denied by a deeper layer, whether Landlock should still
> audit anyway (since the rule author of the child layer likely did not
> expect the denial, so it would be good diagnostic)
>
> This series does not add any tests yet (and also no support for
> suppressing optional access denial audit yet due to complexity). If
> you're happy with this design I can write some tests (and add the missing
> support).
Yes, please.
> Here is a sandboxer demo:
>
> # LL_FS_RO=/ LL_FS_RW= LL_FORCE_LOG=1 LL_FS_QUIET=/tmp linux/samples/landlock/sandboxer /bin/bash
> Executing the sandboxed command...
> [ 135.126499][ T60] audit: type=1423 audit(1757374868.281:942): domain=1a435130e blockers=fs.write_file path="/dev/tty" dev="devtmpfs" ino=11
> [ 135.133298][ T60] audit: type=1424 audit(1757374868.281:942): domain=1a435130e status=allocated mode=enforcing pid=959 uid=0 exe="/linux/samples/landlock/sandboxer" comm="sandboxer"
> [ 135.141869][ T60] audit: type=1300 audit(1757374868.281:942): arch=c000003e syscall=257 success=no exit=-13 a0=ffffffffffffff9c a1=557a9cda83d1 a2=802 a3=0 items=0 ppid=958 pid=959 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="bash" exe="/usr/bin/bash" key=(null)
> [ 135.156620][ T60] audit: type=1327 audit(1757374868.281:942): proctitle="/bin/bash"
> bash: cannot set terminal process group (958): Inappropriate ioctl for device
> bash: no job control in this shell
>
> # echo quiet > /tmp/aa
> bash: /tmp/aa: Permission denied
>
> # echo not quiet > /usr/aa
> [ 165.358804][ T60] audit: type=1423 audit(1757374898.513:943): domain=1a435130e blockers=fs.make_reg path="/usr" dev="virtiofs" ino=840
> [ 165.363746][ T60] audit: type=1300 audit(1757374898.513:943): arch=c000003e syscall=257 success=no exit=-13 a0=ffffffffffffff9c a1=557a9ce447c0 a2=241 a3=1b6 items=0 ppid=958 pid=959 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="bash" exe="/usr/bin/bash" key=(null)
> [ 165.375594][ T60] audit: type=1327 audit(1757374898.513:943): proctitle="/bin/bash"
> bash: /usr/aa: Permission denied
>
> ## (still in sandboxer)
> # LL_FS_RO= LL_FS_RW=/ LL_FS_QUIET=/ linux/samples/landlock/sandboxer /bin/bash
> Executing the sandboxed command...
> [ 203.490417][ T60] audit: type=1423 audit(1757374936.645:944): domain=1a435130e blockers=fs.write_file path="/dev/tty" dev="devtmpfs" ino=11
> ...
> # echo "child can't suppress audit logs" > /usr/a
> [ 219.948543][ T60] audit: type=1423 audit(1757374953.101:945): domain=1a435130e blockers=fs.make_reg path="/usr" dev="virtiofs" ino=840
> [ 219.953918][ T60] audit: type=1300 audit(1757374953.101:945): arch=c000003e syscall=257 success=no exit=-13 a0=ffffffffffffff9c a1=5651ea7875c0 a2=241 a3=1b6 items=0 ppid=959 pid=960 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="bash" exe="/usr/bin/bash" key=(null)
> [ 219.969167][ T60] audit: type=1327 audit(1757374953.101:945): proctitle="/bin/bash"
> bash: /usr/a: Permission denied
> # echo "/tmp is still quiet" > /tmp/a
> bash: /tmp/a: Permission denied
> # exit
>
> (still in first layer sandboxer)
> # LL_FS_RO=/ LL_FS_RW= LL_FS_QUIET= LL_FORCE_LOG=1 linux/samples/landlock/sandboxer /bin/bash
> Executing the sandboxed command...
> ...
> root@fced6595bd01:/# echo "not quiet now" > /tmp/a
> [ 492.130486][ T60] audit: type=1423 audit(1757375225.285:949): domain=1a435132a blockers=fs.make_reg path="/tmp" dev="tmpfs" ino=1
> [ 492.136729][ T60] audit: type=1300 audit(1757375225.285:949): arch=c000003e syscall=257 success=no exit=-13 a0=ffffffffffffff9c a1=55fc4c168450 a2=241 a3=1b6 items=0 ppid=959 pid=964 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="bash" exe="/usr/bin/bash" key=(null)
> [ 492.151727][ T60] audit: type=1327 audit(1757375225.285:949): proctitle="/bin/bash"
> bash: /tmp/a: Permission denied
>
> All existing kselftests pass.
>
> [1]: https://github.com/landlock-lsm/linux/issues/44#issuecomment-2876500918
>
> Kind regards,
> Tingmao
>
> Tingmao Wang (6):
> landlock: Add a place for flags to layer rules
> landlock: Add API support for the quiet flag
> landlock/audit: Check for quiet flag in landlock_log_denial
> landlock/audit: Fix wrong type usage
> landlock/access: Improve explanation on the deny_masks_t
> samples/landlock: Add FS quiet flag support to sandboxer
>
> include/uapi/linux/landlock.h | 25 +++++
> samples/landlock/sandboxer.c | 20 +++-
> security/landlock/access.h | 6 +-
> security/landlock/audit.c | 18 +++-
> security/landlock/audit.h | 3 +-
> security/landlock/fs.c | 99 ++++++++++++--------
> security/landlock/fs.h | 2 +-
> security/landlock/net.c | 11 ++-
> security/landlock/net.h | 3 +-
> security/landlock/ruleset.c | 17 +++-
> security/landlock/ruleset.h | 29 +++++-
> security/landlock/syscalls.c | 28 +++---
> security/landlock/task.c | 12 +--
> tools/testing/selftests/landlock/base_test.c | 2 +-
> 14 files changed, 199 insertions(+), 76 deletions(-)
>
>
> base-commit: b320789d6883cc00ac78ce83bccbfe7ed58afcf0
> --
> 2.51.0
>
>
^ permalink raw reply
* Re: [RFC PATCH 5/6] landlock/access: Improve explanation on the deny_masks_t
From: Mickaël Salaün @ 2025-09-19 16:04 UTC (permalink / raw)
To: Tingmao Wang; +Cc: Günther Noack, Jan Kara, linux-security-module
In-Reply-To: <9253127a0386f53f84897f62a2beaa5aa5959360.1757376311.git.m@maowtm.org>
Looks good, I'll take it.
On Tue, Sep 09, 2025 at 01:06:39AM +0100, Tingmao Wang wrote:
> Not really related to this series, but just something which took me a
> while to realize, and would probably be helpful as a comment.
Please just describe the change in the main commit message and move this
kind of explanation bellow a "---", just after your SoB. This is useful
for review and avoid unrelated information when picking a patch out of
this context.
>
> Signed-off-by: Tingmao Wang <m@maowtm.org>
> ---
> security/landlock/access.h | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/security/landlock/access.h b/security/landlock/access.h
> index 7961c6630a2d..5e2285575479 100644
> --- a/security/landlock/access.h
> +++ b/security/landlock/access.h
> @@ -67,8 +67,10 @@ typedef u16 layer_mask_t;
> static_assert(BITS_PER_TYPE(layer_mask_t) >= LANDLOCK_MAX_NUM_LAYERS);
>
> /*
> - * Tracks domains responsible of a denied access. This is required to avoid
> - * storing in each object the full layer_masks[] required by update_request().
> + * Tracks domains responsible of a denied access, stored in the form of
> + * two 4-bit layer numbers packed into a byte (one for each optional
> + * access). This is required to avoid storing in each object the full
> + * layer_masks[] required by update_request().
> */
> typedef u8 deny_masks_t;
>
> --
> 2.51.0
>
>
^ permalink raw reply
* Re: [RFC PATCH 4/6] landlock/audit: Fix wrong type usage
From: Mickaël Salaün @ 2025-09-19 16:03 UTC (permalink / raw)
To: Tingmao Wang; +Cc: Günther Noack, Jan Kara, linux-security-module
In-Reply-To: <ad6c155f38dda6ed31be1f1cbc6def6cdbd9769c.1757376311.git.m@maowtm.org>
On Tue, Sep 09, 2025 at 01:06:38AM +0100, Tingmao Wang wrote:
> I think, based on my best understanding, that this type is likely a typo
> (even though in the end both are u16)
>
> Signed-off-by: Tingmao Wang <m@maowtm.org>
Indeed, good catch!
You can add:
Fixes: 2fc80c69df82 ("landlock: Log file-related denials")
> ---
> security/landlock/audit.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/security/landlock/audit.c b/security/landlock/audit.c
> index 2b3edd1ab374..a67155c7f0c3 100644
> --- a/security/landlock/audit.c
> +++ b/security/landlock/audit.c
> @@ -191,7 +191,7 @@ static size_t get_denied_layer(const struct landlock_ruleset *const domain,
> long youngest_layer = -1;
>
> for_each_set_bit(access_bit, &access_req, layer_masks_size) {
> - const access_mask_t mask = (*layer_masks)[access_bit];
> + const layer_mask_t mask = (*layer_masks)[access_bit];
> long layer;
>
> if (!mask)
> --
> 2.51.0
>
>
^ permalink raw reply
* Re: [RFC PATCH 3/6] landlock/audit: Check for quiet flag in landlock_log_denial
From: Mickaël Salaün @ 2025-09-19 16:02 UTC (permalink / raw)
To: Tingmao Wang; +Cc: Günther Noack, Jan Kara, linux-security-module
In-Reply-To: <366f215b1687eb3d530bfde11626ec0256d51180.1757376311.git.m@maowtm.org>
On Tue, Sep 09, 2025 at 01:06:37AM +0100, Tingmao Wang wrote:
> Suppresses logging if the flag is effective on the youngest layer.
>
> This does not handle optional access logging yet - to do that correctly we will
> need to expand deny_masks to support representing "don't log anything"
>
> Signed-off-by: Tingmao Wang <m@maowtm.org>
> ---
> security/landlock/audit.c | 16 +++++++++++++++-
> security/landlock/audit.h | 3 ++-
> security/landlock/fs.c | 20 +++++++++++---------
> security/landlock/net.c | 3 ++-
> security/landlock/task.c | 12 ++++++------
> 5 files changed, 36 insertions(+), 18 deletions(-)
>
> diff --git a/security/landlock/audit.c b/security/landlock/audit.c
> index c52d079cdb77..2b3edd1ab374 100644
> --- a/security/landlock/audit.c
> +++ b/security/landlock/audit.c
> @@ -386,9 +386,12 @@ static bool is_valid_request(const struct landlock_request *const request)
> *
> * @subject: The Landlock subject's credential denying an action.
> * @request: Detail of the user space request.
> + * @rule_flags: The flags for the matched rule, or NULL if this is a
> + * scope request (no particular object involved).
> */
> void landlock_log_denial(const struct landlock_cred_security *const subject,
> - const struct landlock_request *const request)
> + const struct landlock_request *const request,
> + const struct collected_rule_flags *const rule_flags)
No need for a pointer for this small struct. For scope requests,
rule_flags can just be 0, which should also simplify the following
check.
I think that's the only place where we could replace a pointer with the
(small) raw struct, but if there are other in the code, this rule should
also be applied.
> {
> struct audit_buffer *ab;
> struct landlock_hierarchy *youngest_denied;
> @@ -436,6 +439,17 @@ void landlock_log_denial(const struct landlock_cred_security *const subject,
> if (!audit_enabled)
> return;
>
> + /*
> + * Check if the object is marked quiet by the layer that denied the
For consistency: "Checks"
> + * request. (If it's a different layer that marked it as quiet, but
> + * that layer is not the one that denied the request, we should still
> + * audit log the denial)
No need for parenthesis.
> + */
> + if (rule_flags &&
> + rule_flags->quiet_masks & BIT(youngest_layer)) {
> + return;
> + }
> +
> /* Checks if the current exec was restricting itself. */
> if (subject->domain_exec & BIT(youngest_layer)) {
> /* Ignores denials for the same execution. */
> diff --git a/security/landlock/audit.h b/security/landlock/audit.h
> index 92428b7fc4d8..e6f76d417c2f 100644
> --- a/security/landlock/audit.h
> +++ b/security/landlock/audit.h
> @@ -56,7 +56,8 @@ struct landlock_request {
> void landlock_log_drop_domain(const struct landlock_hierarchy *const hierarchy);
>
> void landlock_log_denial(const struct landlock_cred_security *const subject,
> - const struct landlock_request *const request);
> + const struct landlock_request *const request,
> + const struct collected_rule_flags *const rule_flags);
>
> #else /* CONFIG_AUDIT */
>
> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
> index b566ae498df5..ba93b0de384c 100644
> --- a/security/landlock/fs.c
> +++ b/security/landlock/fs.c
> @@ -984,7 +984,7 @@ static int current_check_access_path(const struct path *const path,
> NULL, 0, NULL, NULL, NULL, NULL))
> return 0;
>
> - landlock_log_denial(subject, &request);
> + landlock_log_denial(subject, &request, &rule_flags);
> return -EACCES;
> }
>
> @@ -1194,7 +1194,7 @@ static int current_check_refer_path(struct dentry *const old_dentry,
> &request1, NULL, 0, NULL, NULL, NULL, NULL))
> return 0;
>
> - landlock_log_denial(subject, &request1);
> + landlock_log_denial(subject, &request1, &rule_flags_parent1);
> return -EACCES;
> }
>
> @@ -1243,11 +1243,13 @@ static int current_check_refer_path(struct dentry *const old_dentry,
>
> if (request1.access) {
> request1.audit.u.path.dentry = old_parent;
> - landlock_log_denial(subject, &request1);
> + landlock_log_denial(subject, &request1,
> + &rule_flags_parent1);
> }
> if (request2.access) {
> request2.audit.u.path.dentry = new_dir->dentry;
> - landlock_log_denial(subject, &request2);
> + landlock_log_denial(subject, &request2,
> + &rule_flags_parent2);
> }
>
> /*
> @@ -1403,7 +1405,7 @@ log_fs_change_topology_path(const struct landlock_cred_security *const subject,
> .u.path = *path,
> },
> .layer_plus_one = handle_layer + 1,
> - });
> + }, NULL);
> }
>
> static void log_fs_change_topology_dentry(
> @@ -1417,7 +1419,7 @@ static void log_fs_change_topology_dentry(
> .u.dentry = dentry,
> },
> .layer_plus_one = handle_layer + 1,
> - });
> + }, NULL);
> }
>
> /*
> @@ -1705,7 +1707,7 @@ static int hook_file_open(struct file *const file)
>
> /* Sets access to reflect the actual request. */
> request.access = open_access_request;
> - landlock_log_denial(subject, &request);
> + landlock_log_denial(subject, &request, &rule_flags);
> return -EACCES;
> }
>
> @@ -1735,7 +1737,7 @@ static int hook_file_truncate(struct file *const file)
> #ifdef CONFIG_AUDIT
> .deny_masks = landlock_file(file)->deny_masks,
> #endif /* CONFIG_AUDIT */
> - });
> + }, NULL);
> return -EACCES;
> }
>
> @@ -1774,7 +1776,7 @@ static int hook_file_ioctl_common(const struct file *const file,
> #ifdef CONFIG_AUDIT
> .deny_masks = landlock_file(file)->deny_masks,
> #endif /* CONFIG_AUDIT */
> - });
> + }, NULL);
> return -EACCES;
> }
>
> diff --git a/security/landlock/net.c b/security/landlock/net.c
> index bddbe93d69fd..d242bb9fa5b4 100644
> --- a/security/landlock/net.c
> +++ b/security/landlock/net.c
> @@ -193,7 +193,8 @@ static int current_check_access_socket(struct socket *const sock,
> .access = access_request,
> .layer_masks = &layer_masks,
> .layer_masks_size = ARRAY_SIZE(layer_masks),
> - });
> + },
> + &rule_flags);
> return -EACCES;
> }
>
> diff --git a/security/landlock/task.c b/security/landlock/task.c
> index 2385017418ca..dfea227ce1d7 100644
> --- a/security/landlock/task.c
> +++ b/security/landlock/task.c
> @@ -115,7 +115,7 @@ static int hook_ptrace_access_check(struct task_struct *const child,
> .u.tsk = child,
> },
> .layer_plus_one = parent_subject->domain->num_layers,
> - });
> + }, NULL);
>
> return err;
> }
> @@ -161,7 +161,7 @@ static int hook_ptrace_traceme(struct task_struct *const parent)
> .u.tsk = current,
> },
> .layer_plus_one = parent_subject->domain->num_layers,
> - });
> + }, NULL);
> return err;
> }
>
> @@ -290,7 +290,7 @@ static int hook_unix_stream_connect(struct sock *const sock,
> },
> },
> .layer_plus_one = handle_layer + 1,
> - });
> + }, NULL);
> return -EPERM;
> }
>
> @@ -327,7 +327,7 @@ static int hook_unix_may_send(struct socket *const sock,
> },
> },
> .layer_plus_one = handle_layer + 1,
> - });
> + }, NULL);
> return -EPERM;
> }
>
> @@ -383,7 +383,7 @@ static int hook_task_kill(struct task_struct *const p,
> .u.tsk = p,
> },
> .layer_plus_one = handle_layer + 1,
> - });
> + }, NULL);
> return -EPERM;
> }
>
> @@ -426,7 +426,7 @@ static int hook_file_send_sigiotask(struct task_struct *tsk,
> #ifdef CONFIG_AUDIT
> .layer_plus_one = landlock_file(fown->file)->fown_layer + 1,
> #endif /* CONFIG_AUDIT */
> - });
> + }, NULL);
> return -EPERM;
> }
>
> --
> 2.51.0
>
>
^ permalink raw reply
* Re: [RFC PATCH 2/6] landlock: Add API support for the quiet flag
From: Mickaël Salaün @ 2025-09-19 16:02 UTC (permalink / raw)
To: Tingmao Wang; +Cc: Günther Noack, Jan Kara, linux-security-module
In-Reply-To: <e9462ee16376d706188d48d8f4b4fd50760432e5.1757376311.git.m@maowtm.org>
On Tue, Sep 09, 2025 at 01:06:36AM +0100, Tingmao Wang wrote:
> Also added documentation.
>
> As for kselftests, for now we just change add_rule_checks_ordering to use
> a different invalid flag. I will add tests for the quiet flag in a later
> version.
>
> Signed-off-by: Tingmao Wang <m@maowtm.org>
> ---
> include/uapi/linux/landlock.h | 25 +++++++++++++++++
> security/landlock/fs.c | 4 +--
> security/landlock/fs.h | 2 +-
> security/landlock/net.c | 5 ++--
> security/landlock/net.h | 3 ++-
> security/landlock/ruleset.c | 8 +++++-
> security/landlock/ruleset.h | 2 +-
> security/landlock/syscalls.c | 28 ++++++++++++--------
> tools/testing/selftests/landlock/base_test.c | 2 +-
> 9 files changed, 59 insertions(+), 20 deletions(-)
>
> diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h
> index f030adc462ee..3e5b2ce0b18b 100644
> --- a/include/uapi/linux/landlock.h
> +++ b/include/uapi/linux/landlock.h
> @@ -69,6 +69,31 @@ struct landlock_ruleset_attr {
> #define LANDLOCK_CREATE_RULESET_ERRATA (1U << 1)
> /* clang-format on */
>
> +/**
> + * DOC: landlock_add_rule_flags
> + *
> + * **Flags**
> + *
> + * %LANDLOCK_ADD_RULE_QUIET
> + * This flag controls whether Landlock will log audit messages when
> + * access to the objects covered by this rule is denied by this layer.
> + *
> + * When Landlock denies an access, if audit logging is enabled,
> + * Landlock will check if the youngest layer that denied the access
> + * has marked the object in question as "quiet". If so, no audit log
> + * will be generated. Note that logging is only suppressed if the
> + * layer that denied the access is this layer. This means that a
> + * sandboxed program cannot use this flag to "hide" access denials,
> + * unless it denies itself the access.
> + *
> + * When this flag is present, the caller is allowed to pass in a rule
> + * with empty allowed_access.
> + */
> +
> +/* clang-format off */
> +#define LANDLOCK_ADD_RULE_QUIET (1U << 0)
> +/* clang-format on */
> +
> /**
> * DOC: landlock_restrict_self_flags
> *
> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
> index e7eaf55093e9..b566ae498df5 100644
> --- a/security/landlock/fs.c
> +++ b/security/landlock/fs.c
> @@ -322,7 +322,7 @@ static struct landlock_object *get_inode_object(struct inode *const inode)
> */
> int landlock_append_fs_rule(struct landlock_ruleset *const ruleset,
> const struct path *const path,
> - access_mask_t access_rights)
> + access_mask_t access_rights, const int flags)
> {
> int err;
> struct landlock_id id = {
> @@ -343,7 +343,7 @@ int landlock_append_fs_rule(struct landlock_ruleset *const ruleset,
> if (IS_ERR(id.key.object))
> return PTR_ERR(id.key.object);
> mutex_lock(&ruleset->lock);
> - err = landlock_insert_rule(ruleset, id, access_rights);
> + err = landlock_insert_rule(ruleset, id, access_rights, flags);
> mutex_unlock(&ruleset->lock);
> /*
> * No need to check for an error because landlock_insert_rule()
> diff --git a/security/landlock/fs.h b/security/landlock/fs.h
> index bf9948941f2f..cb7e654933ac 100644
> --- a/security/landlock/fs.h
> +++ b/security/landlock/fs.h
> @@ -126,6 +126,6 @@ __init void landlock_add_fs_hooks(void);
>
> int landlock_append_fs_rule(struct landlock_ruleset *const ruleset,
> const struct path *const path,
> - access_mask_t access_hierarchy);
> + access_mask_t access_hierarchy, const int flags);
>
> #endif /* _SECURITY_LANDLOCK_FS_H */
> diff --git a/security/landlock/net.c b/security/landlock/net.c
> index fc6369dffa51..bddbe93d69fd 100644
> --- a/security/landlock/net.c
> +++ b/security/landlock/net.c
> @@ -20,7 +20,8 @@
> #include "ruleset.h"
>
> int landlock_append_net_rule(struct landlock_ruleset *const ruleset,
> - const u16 port, access_mask_t access_rights)
> + const u16 port, access_mask_t access_rights,
> + const int flags)
> {
> int err;
> const struct landlock_id id = {
> @@ -35,7 +36,7 @@ int landlock_append_net_rule(struct landlock_ruleset *const ruleset,
> ~landlock_get_net_access_mask(ruleset, 0);
>
> mutex_lock(&ruleset->lock);
> - err = landlock_insert_rule(ruleset, id, access_rights);
> + err = landlock_insert_rule(ruleset, id, access_rights, flags);
> mutex_unlock(&ruleset->lock);
>
> return err;
> diff --git a/security/landlock/net.h b/security/landlock/net.h
> index 09960c237a13..799cedd5d0b7 100644
> --- a/security/landlock/net.h
> +++ b/security/landlock/net.h
> @@ -16,7 +16,8 @@
> __init void landlock_add_net_hooks(void);
>
> int landlock_append_net_rule(struct landlock_ruleset *const ruleset,
> - const u16 port, access_mask_t access_rights);
> + const u16 port, access_mask_t access_rights,
> + const int flags);
> #else /* IS_ENABLED(CONFIG_INET) */
> static inline void landlock_add_net_hooks(void)
> {
> diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
> index 3aa4e33ac95b..990aa1a2c120 100644
> --- a/security/landlock/ruleset.c
> +++ b/security/landlock/ruleset.c
> @@ -21,6 +21,7 @@
> #include <linux/slab.h>
> #include <linux/spinlock.h>
> #include <linux/workqueue.h>
> +#include <uapi/linux/landlock.h>
>
> #include "access.h"
> #include "audit.h"
> @@ -251,6 +252,7 @@ static int insert_rule(struct landlock_ruleset *const ruleset,
> if (WARN_ON_ONCE(this->layers[0].level != 0))
> return -EINVAL;
> this->layers[0].access |= (*layers)[0].access;
> + this->layers[0].flags.quiet |= (*layers)[0].flags.quiet;
> return 0;
> }
>
> @@ -297,12 +299,15 @@ static void build_check_layer(void)
> /* @ruleset must be locked by the caller. */
> int landlock_insert_rule(struct landlock_ruleset *const ruleset,
> const struct landlock_id id,
> - const access_mask_t access)
> + const access_mask_t access, const int flags)
> {
> struct landlock_layer layers[] = { {
> .access = access,
> /* When @level is zero, insert_rule() extends @ruleset. */
> .level = 0,
> + .flags = {
> + .quiet = flags & LANDLOCK_ADD_RULE_QUIET ? 1 : 0,
This looks better to me (no hardcoded values):
.quiet = !!(flags & LANDLOCK_ADD_RULE_QUIET,
> + }
> } };
>
> build_check_layer();
> @@ -343,6 +348,7 @@ static int merge_tree(struct landlock_ruleset *const dst,
> return -EINVAL;
>
> layers[0].access = walker_rule->layers[0].access;
> + layers[0].flags = walker_rule->layers[0].flags;
>
> err = insert_rule(dst, id, &layers, ARRAY_SIZE(layers));
> if (err)
> diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
> index d4b70b6af137..4f184d2da382 100644
> --- a/security/landlock/ruleset.h
> +++ b/security/landlock/ruleset.h
> @@ -224,7 +224,7 @@ DEFINE_FREE(landlock_put_ruleset, struct landlock_ruleset *,
>
> int landlock_insert_rule(struct landlock_ruleset *const ruleset,
> const struct landlock_id id,
> - const access_mask_t access);
> + const access_mask_t access, const int flags);
>
> struct landlock_ruleset *
> landlock_merge_ruleset(struct landlock_ruleset *const parent,
> diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
> index 0116e9f93ffe..e46164246fdb 100644
> --- a/security/landlock/syscalls.c
> +++ b/security/landlock/syscalls.c
> @@ -312,7 +312,7 @@ static int get_path_from_fd(const s32 fd, struct path *const path)
> }
>
> static int add_rule_path_beneath(struct landlock_ruleset *const ruleset,
> - const void __user *const rule_attr)
> + const void __user *const rule_attr, int flags)
> {
> struct landlock_path_beneath_attr path_beneath_attr;
> struct path path;
> @@ -328,8 +328,10 @@ static int add_rule_path_beneath(struct landlock_ruleset *const ruleset,
> /*
> * Informs about useless rule: empty allowed_access (i.e. deny rules)
> * are ignored in path walks.
> + * (However, the rule is not useless if it is there to hold a quiet
> + * flag)
There is no need for parenthesis, please just append to the previous
sentence.
> */
> - if (!path_beneath_attr.allowed_access)
> + if (!flags && !path_beneath_attr.allowed_access)
> return -ENOMSG;
>
> /* Checks that allowed_access matches the @ruleset constraints. */
> @@ -344,13 +346,13 @@ static int add_rule_path_beneath(struct landlock_ruleset *const ruleset,
>
> /* Imports the new rule. */
> err = landlock_append_fs_rule(ruleset, &path,
> - path_beneath_attr.allowed_access);
> + path_beneath_attr.allowed_access, flags);
> path_put(&path);
> return err;
> }
>
> static int add_rule_net_port(struct landlock_ruleset *ruleset,
> - const void __user *const rule_attr)
> + const void __user *const rule_attr, int flags)
> {
> struct landlock_net_port_attr net_port_attr;
> int res;
> @@ -364,8 +366,10 @@ static int add_rule_net_port(struct landlock_ruleset *ruleset,
> /*
> * Informs about useless rule: empty allowed_access (i.e. deny rules)
> * are ignored by network actions.
> + * (However, the rule is not useless if it is there to hold a quiet
> + * flag)
ditto
> */
> - if (!net_port_attr.allowed_access)
> + if (!flags && !net_port_attr.allowed_access)
> return -ENOMSG;
>
> /* Checks that allowed_access matches the @ruleset constraints. */
> @@ -379,7 +383,7 @@ static int add_rule_net_port(struct landlock_ruleset *ruleset,
>
> /* Imports the new rule. */
> return landlock_append_net_rule(ruleset, net_port_attr.port,
> - net_port_attr.allowed_access);
> + net_port_attr.allowed_access, flags);
> }
>
> /**
> @@ -390,7 +394,7 @@ static int add_rule_net_port(struct landlock_ruleset *ruleset,
> * @rule_type: Identify the structure type pointed to by @rule_attr:
> * %LANDLOCK_RULE_PATH_BENEATH or %LANDLOCK_RULE_NET_PORT.
> * @rule_attr: Pointer to a rule (matching the @rule_type).
> - * @flags: Must be 0.
> + * @flags: Must be 0 or %LANDLOCK_ADD_RULE_QUIET.
> *
> * This system call enables to define a new rule and add it to an existing
> * ruleset.
> @@ -414,6 +418,9 @@ static int add_rule_net_port(struct landlock_ruleset *ruleset,
> * @rule_attr is not the expected file descriptor type;
> * - %EPERM: @ruleset_fd has no write access to the underlying ruleset;
> * - %EFAULT: @rule_attr was not a valid address.
> + *
> + * .. kernel-doc:: include/uapi/linux/landlock.h
> + * :identifiers: landlock_add_rule_flags
> */
> SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
> const enum landlock_rule_type, rule_type,
> @@ -424,8 +431,7 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
> if (!is_initialized())
> return -EOPNOTSUPP;
>
> - /* No flag for now. */
> - if (flags)
> + if (flags && flags != LANDLOCK_ADD_RULE_QUIET)
> return -EINVAL;
>
> /* Gets and checks the ruleset. */
> @@ -435,9 +441,9 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
>
> switch (rule_type) {
> case LANDLOCK_RULE_PATH_BENEATH:
> - return add_rule_path_beneath(ruleset, rule_attr);
> + return add_rule_path_beneath(ruleset, rule_attr, flags);
> case LANDLOCK_RULE_NET_PORT:
> - return add_rule_net_port(ruleset, rule_attr);
> + return add_rule_net_port(ruleset, rule_attr, flags);
> default:
> return -EINVAL;
> }
> diff --git a/tools/testing/selftests/landlock/base_test.c b/tools/testing/selftests/landlock/base_test.c
> index 7b69002239d7..d07a0bf6927c 100644
> --- a/tools/testing/selftests/landlock/base_test.c
> +++ b/tools/testing/selftests/landlock/base_test.c
> @@ -201,7 +201,7 @@ TEST(add_rule_checks_ordering)
> ASSERT_LE(0, ruleset_fd);
>
> /* Checks invalid flags. */
> - ASSERT_EQ(-1, landlock_add_rule(-1, 0, NULL, 1));
> + ASSERT_EQ(-1, landlock_add_rule(-1, 0, NULL, 100));
> ASSERT_EQ(EINVAL, errno);
>
> /* Checks invalid ruleset FD. */
> --
> 2.51.0
>
>
^ permalink raw reply
* Re: [PATCH v7] tpm: Make TPM buffer allocations more robust
From: Jarkko Sakkinen @ 2025-09-19 15:32 UTC (permalink / raw)
To: Stefano Garzarella
Cc: linux-integrity, Stefan Berger, Jarkko Sakkinen, Peter Huewe,
Jason Gunthorpe, James Bottomley, Mimi Zohar, David Howells,
Paul Moore, James Morris, Serge E. Hallyn, open list,
open list:KEYS-TRUSTED, open list:SECURITY SUBSYSTEM
In-Reply-To: <hwsx2t2tkbos3g7k2syemxbvc6sfrsbviwm64ubcdl6ms7ljvo@toetomkhheht>
On Fri, Sep 19, 2025 at 03:35:43PM +0200, Stefano Garzarella wrote:
> On Fri, Sep 19, 2025 at 02:24:47PM +0300, Jarkko Sakkinen wrote:
> > From: Jarkko Sakkinen <jarkko.sakkinen@opinsys.com>
> >
> > Drop 'tpm_buf_init', 'tpm_buf_init_sized' and 'tpm_buf_free'. Refine
> > 'struct tpm_buf' to hold capacity in order to enable stack allocation and
> > sizes other than page size.
> >
> > The updated 'struct tpm_buf' can be allocated either from stack or heap.
> >
> > The contract is the following:
> >
> > 1. 'tpm_buf_reset' and 'tpm_buf_reset_size' expect that on the first run
> > the passed buffer is zeroed by the caller (e.g. via memset or kzalloc).
> > 2. The same buffer can be reused. On the second and subsequent resets the
> > aforementioned functions verify that 'buf_size' has the same value, and
> > emits warning if not.
> >
> > As a consequence 'struct tpm_buf' instance can be easily wrapped into
> > managed allocation:
> >
> > struct tpm_buf *buf __free(kfree) buf = kzalloc(PAGE_SIZE,
> > GFP_KERNEL);
> >
> > Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> > Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@opinsys.com>
> > ---
> > v7:
> > - Additional function comments and invariant was unfortunately left to
> > my staging area so here's the addition (does not affect functionality).
> > v6:
> > - Removed two empty lines as requested by Stefan:
> > https://lore.kernel.org/linux-integrity/be1c5bef-7c97-4173-b417-986dc90d779c@linux.ibm.com/
> > - Add 'capacity' field as this makes easy to stretch tpm_buf into stack
> > allocation.
> > v5:
> > - I tested this version also with TPM 1.2 by booting up and checking
> > that sysfs attributes work.
> > - Fixed the length check against capacity (James) with TPM_BUF_CAPACITY.
> > - Fixed declaration style: do it at the site (Jason).
> > - Improved commit message (Stefan).
> > - Removed "out" label from tpm2_pcr_read() (Stefan).
> > - Removed spurious "return rc;" from tpm2_get_pcr_allocation() (Stefan).
> > v4:
> > - Wrote a more a descriptive short summary and improved description.
> > - Fixed the error in documentation: there is 4090 bytes of space left
> > for the payload - not 4088 bytes.
> > - Turned tpm_buf_alloc() into inline function.
> > v3:
> > - Removed the cleanup class and moved on using __free(kfree) instead.
> > - Removed `buf_size` (James).
> > - I'm open for the idea of splitting still (Jason) but I'll hold
> > at least this revision just to check that my core idea here
> > is correct.
> > v2:
> > - Implement also memory allocation using the cleanup class.
> > - Rewrote the commit message.
> > - Implemented CLASS_TPM_BUF() helper macro.
> > ---
> > drivers/char/tpm/tpm-buf.c | 68 ++----
> > drivers/char/tpm/tpm-sysfs.c | 19 +-
> > drivers/char/tpm/tpm1-cmd.c | 143 ++++++------
> > drivers/char/tpm/tpm2-cmd.c | 270 ++++++++++------------
> > drivers/char/tpm/tpm2-sessions.c | 118 +++++-----
> > drivers/char/tpm/tpm2-space.c | 42 ++--
> > drivers/char/tpm/tpm_vtpm_proxy.c | 29 +--
> > include/linux/tpm.h | 17 +-
> > security/keys/trusted-keys/trusted_tpm1.c | 40 ++--
> > security/keys/trusted-keys/trusted_tpm2.c | 153 ++++++------
> > 10 files changed, 390 insertions(+), 509 deletions(-)
> >
> > diff --git a/drivers/char/tpm/tpm-buf.c b/drivers/char/tpm/tpm-buf.c
> > index dc882fc9fa9e..19774bc5786f 100644
> > --- a/drivers/char/tpm/tpm-buf.c
> > +++ b/drivers/char/tpm/tpm-buf.c
> > @@ -7,83 +7,57 @@
> > #include <linux/module.h>
> > #include <linux/tpm.h>
> >
> > -/**
> > - * tpm_buf_init() - Allocate and initialize a TPM command
> > - * @buf: A &tpm_buf
> > - * @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS
> > - * @ordinal: A command ordinal
> > - *
> > - * Return: 0 or -ENOMEM
> > - */
> > -int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
> > -{
> > - buf->data = (u8 *)__get_free_page(GFP_KERNEL);
> > - if (!buf->data)
> > - return -ENOMEM;
> > -
> > - tpm_buf_reset(buf, tag, ordinal);
> > - return 0;
> > -}
> > -EXPORT_SYMBOL_GPL(tpm_buf_init);
> > -
> > /**
> > * tpm_buf_reset() - Initialize a TPM command
> > * @buf: A &tpm_buf
> > + * @buf_size: Size of the buffer.
> > * @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS
> > * @ordinal: A command ordinal
> > + *
> > + * 1. Expects that on the first run the passed buffer is zeroed by the caller.
> > + * 2. Old buffer can be reused. On the second and subsequent resets @buf_size is
> > + * verified to be equal to the previous value.
> > */
> > -void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
> > +void tpm_buf_reset(struct tpm_buf *buf, u16 buf_size, u16 tag, u32 ordinal)
> > {
> > struct tpm_header *head = (struct tpm_header *)buf->data;
> >
> > + WARN_ON(buf->capacity != 0 && buf_size != (buf->capacity + sizeof(*buf)));
> > WARN_ON(tag != TPM_TAG_RQU_COMMAND && tag != TPM2_ST_NO_SESSIONS &&
> > tag != TPM2_ST_SESSIONS && tag != 0);
> >
> > buf->flags = 0;
> > buf->length = sizeof(*head);
> > + buf->capacity = buf_size - sizeof(*buf);
> > + buf->handles = 0;
> > head->tag = cpu_to_be16(tag);
> > head->length = cpu_to_be32(sizeof(*head));
> > head->ordinal = cpu_to_be32(ordinal);
> > - buf->handles = 0;
> > }
> > EXPORT_SYMBOL_GPL(tpm_buf_reset);
> >
> > -/**
> > - * tpm_buf_init_sized() - Allocate and initialize a sized (TPM2B) buffer
> > - * @buf: A @tpm_buf
> > - *
> > - * Return: 0 or -ENOMEM
> > - */
> > -int tpm_buf_init_sized(struct tpm_buf *buf)
> > -{
> > - buf->data = (u8 *)__get_free_page(GFP_KERNEL);
> > - if (!buf->data)
> > - return -ENOMEM;
> > -
> > - tpm_buf_reset_sized(buf);
> > - return 0;
> > -}
> > -EXPORT_SYMBOL_GPL(tpm_buf_init_sized);
> > -
> > /**
> > * tpm_buf_reset_sized() - Initialize a sized buffer
> > * @buf: A &tpm_buf
> > + * @buf_size: Size of the buffer.
> > + *
> > + * 1. Expects that on the first run the passed buffer is zeroed by the caller.
> > + * 2. Old buffer can be reused. On the second and subsequent resets @buf_size is
> > + * verified to be equal to the previous value.
> > */
> > -void tpm_buf_reset_sized(struct tpm_buf *buf)
> > +void tpm_buf_reset_sized(struct tpm_buf *buf, u16 buf_size)
> > {
> > + WARN_ON(buf->capacity != 0 && buf_size != (buf->capacity + sizeof(*buf)));
> > +
> > buf->flags = TPM_BUF_TPM2B;
> > buf->length = 2;
> > + buf->capacity = buf_size - sizeof(*buf);
> > + buf->handles = 0;
> > buf->data[0] = 0;
> > buf->data[1] = 0;
> > }
> > EXPORT_SYMBOL_GPL(tpm_buf_reset_sized);
> >
> > -void tpm_buf_destroy(struct tpm_buf *buf)
> > -{
> > - free_page((unsigned long)buf->data);
> > -}
> > -EXPORT_SYMBOL_GPL(tpm_buf_destroy);
> > -
> > /**
> > * tpm_buf_length() - Return the number of bytes consumed by the data
> > * @buf: A &tpm_buf
> *
> * Return: The number of bytes consumed by the buffer
> */
> u32 tpm_buf_length(struct tpm_buf *buf)
> {
> return buf->length;
> }
> EXPORT_SYMBOL_GPL(tpm_buf_length);
>
> Should we update the return type (u16) on this function?
Yes we should. Thanks for catching this.
>
> > @@ -108,7 +82,7 @@ void tpm_buf_append(struct tpm_buf *buf, const u8 *new_data, u16 new_length)
> > if (buf->flags & TPM_BUF_OVERFLOW)
> > return;
> >
> > - if ((buf->length + new_length) > PAGE_SIZE) {
> > + if ((buf->length + new_length) > buf->capacity) {
>
> IIUC all of these are u16, so there could be an overflow when we do
> `buf->length + new_length` ?
>
> Should we cast to u32 or just change the expression in something like
> `new_length > (buf->capacity - buf->length)`
Thanks, these really appropriate comments.
I think best measure here would have hard constant cap of PAGE_SIZE
for buf_size. That's how the specs limit anyhow. I'll extend the
invariant.
>
> Thanks,
> Stefano
>
> > WARN(1, "tpm_buf: write overflow\n");
> > buf->flags |= TPM_BUF_OVERFLOW;
> > return;
> > @@ -242,5 +216,3 @@ u32 tpm_buf_read_u32(struct tpm_buf *buf, off_t *offset)
> > return be32_to_cpu(value);
> > }
> > EXPORT_SYMBOL_GPL(tpm_buf_read_u32);
> > -
> > -
> > diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
> > index 94231f052ea7..68328ca6367d 100644
> > --- a/drivers/char/tpm/tpm-sysfs.c
> > +++ b/drivers/char/tpm/tpm-sysfs.c
> > @@ -32,28 +32,29 @@ struct tpm_readpubek_out {
> > static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
> > char *buf)
> > {
> > - struct tpm_buf tpm_buf;
> > struct tpm_readpubek_out *out;
> > int i;
> > char *str = buf;
> > struct tpm_chip *chip = to_tpm_chip(dev);
> > char anti_replay[20];
> >
> > + struct tpm_buf *tpm_buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!tpm_buf)
> > + return -ENOMEM;
> > +
> > memset(&anti_replay, 0, sizeof(anti_replay));
> >
> > if (tpm_try_get_ops(chip))
> > return 0;
> >
> > - if (tpm_buf_init(&tpm_buf, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK))
> > - goto out_ops;
> > -
> > - tpm_buf_append(&tpm_buf, anti_replay, sizeof(anti_replay));
> > + tpm_buf_reset(tpm_buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK);
> > + tpm_buf_append(tpm_buf, anti_replay, sizeof(anti_replay));
> >
> > - if (tpm_transmit_cmd(chip, &tpm_buf, READ_PUBEK_RESULT_MIN_BODY_SIZE,
> > + if (tpm_transmit_cmd(chip, tpm_buf, READ_PUBEK_RESULT_MIN_BODY_SIZE,
> > "attempting to read the PUBEK"))
> > - goto out_buf;
> > + goto out_ops;
> >
> > - out = (struct tpm_readpubek_out *)&tpm_buf.data[10];
> > + out = (struct tpm_readpubek_out *)&tpm_buf->data[10];
> > str +=
> > sprintf(str,
> > "Algorithm: %4ph\n"
> > @@ -71,8 +72,6 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
> > for (i = 0; i < 256; i += 16)
> > str += sprintf(str, "%16ph\n", &out->modulus[i]);
> >
> > -out_buf:
> > - tpm_buf_destroy(&tpm_buf);
> > out_ops:
> > tpm_put_ops(chip);
> > return str - buf;
> > diff --git a/drivers/char/tpm/tpm1-cmd.c b/drivers/char/tpm/tpm1-cmd.c
> > index cf64c7385105..e7dc01c68a92 100644
> > --- a/drivers/char/tpm/tpm1-cmd.c
> > +++ b/drivers/char/tpm/tpm1-cmd.c
> > @@ -323,19 +323,18 @@ unsigned long tpm1_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
> > */
> > static int tpm1_startup(struct tpm_chip *chip)
> > {
> > - struct tpm_buf buf;
> > int rc;
> >
> > - dev_info(&chip->dev, "starting up the TPM manually\n");
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> >
> > - rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_STARTUP);
> > - if (rc < 0)
> > - return rc;
> > + dev_info(&chip->dev, "starting up the TPM manually\n");
> >
> > - tpm_buf_append_u16(&buf, TPM_ST_CLEAR);
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_STARTUP);
> > + tpm_buf_append_u16(buf, TPM_ST_CLEAR);
> >
> > - rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM");
> > - tpm_buf_destroy(&buf);
> > + rc = tpm_transmit_cmd(chip, buf, 0, "attempting to start the TPM");
> > return rc;
> > }
> >
> > @@ -463,18 +462,17 @@ int tpm1_get_timeouts(struct tpm_chip *chip)
> > int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash,
> > const char *log_msg)
> > {
> > - struct tpm_buf buf;
> > int rc;
> >
> > - rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_EXTEND);
> > - if (rc)
> > - return rc;
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> >
> > - tpm_buf_append_u32(&buf, pcr_idx);
> > - tpm_buf_append(&buf, hash, TPM_DIGEST_SIZE);
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_EXTEND);
> > + tpm_buf_append_u32(buf, pcr_idx);
> > + tpm_buf_append(buf, hash, TPM_DIGEST_SIZE);
> >
> > - rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE, log_msg);
> > - tpm_buf_destroy(&buf);
> > + rc = tpm_transmit_cmd(chip, buf, TPM_DIGEST_SIZE, log_msg);
> > return rc;
> > }
> >
> > @@ -482,31 +480,31 @@ int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash,
> > ssize_t tpm1_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
> > const char *desc, size_t min_cap_length)
> > {
> > - struct tpm_buf buf;
> > int rc;
> >
> > - rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_CAP);
> > - if (rc)
> > - return rc;
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> > +
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_CAP);
> >
> > if (subcap_id == TPM_CAP_VERSION_1_1 ||
> > subcap_id == TPM_CAP_VERSION_1_2) {
> > - tpm_buf_append_u32(&buf, subcap_id);
> > - tpm_buf_append_u32(&buf, 0);
> > + tpm_buf_append_u32(buf, subcap_id);
> > + tpm_buf_append_u32(buf, 0);
> > } else {
> > if (subcap_id == TPM_CAP_FLAG_PERM ||
> > subcap_id == TPM_CAP_FLAG_VOL)
> > - tpm_buf_append_u32(&buf, TPM_CAP_FLAG);
> > + tpm_buf_append_u32(buf, TPM_CAP_FLAG);
> > else
> > - tpm_buf_append_u32(&buf, TPM_CAP_PROP);
> > + tpm_buf_append_u32(buf, TPM_CAP_PROP);
> >
> > - tpm_buf_append_u32(&buf, 4);
> > - tpm_buf_append_u32(&buf, subcap_id);
> > + tpm_buf_append_u32(buf, 4);
> > + tpm_buf_append_u32(buf, subcap_id);
> > }
> > - rc = tpm_transmit_cmd(chip, &buf, min_cap_length, desc);
> > + rc = tpm_transmit_cmd(chip, buf, min_cap_length, desc);
> > if (!rc)
> > - *cap = *(cap_t *)&buf.data[TPM_HEADER_SIZE + 4];
> > - tpm_buf_destroy(&buf);
> > + *cap = *(cap_t *)&buf->data[TPM_HEADER_SIZE + 4];
> > return rc;
> > }
> > EXPORT_SYMBOL_GPL(tpm1_getcap);
> > @@ -531,81 +529,72 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
> > {
> > struct tpm1_get_random_out *out;
> > u32 num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA);
> > - struct tpm_buf buf;
> > u32 total = 0;
> > int retries = 5;
> > u32 recd;
> > int rc;
> >
> > - rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
> > - if (rc)
> > - return rc;
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> > +
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
> >
> > do {
> > - tpm_buf_append_u32(&buf, num_bytes);
> > + tpm_buf_append_u32(buf, num_bytes);
> >
> > - rc = tpm_transmit_cmd(chip, &buf, sizeof(out->rng_data_len),
> > + rc = tpm_transmit_cmd(chip, buf, sizeof(out->rng_data_len),
> > "attempting get random");
> > if (rc) {
> > if (rc > 0)
> > rc = -EIO;
> > - goto out;
> > + return rc;
> > }
> >
> > - out = (struct tpm1_get_random_out *)&buf.data[TPM_HEADER_SIZE];
> > + out = (struct tpm1_get_random_out *)&buf->data[TPM_HEADER_SIZE];
> >
> > recd = be32_to_cpu(out->rng_data_len);
> > - if (recd > num_bytes) {
> > - rc = -EFAULT;
> > - goto out;
> > - }
> > + if (recd > num_bytes)
> > + return -EFAULT;
> > +
> > + if (buf->length < TPM_HEADER_SIZE +
> > + sizeof(out->rng_data_len) + recd)
> > + return -EFAULT;
> >
> > - if (tpm_buf_length(&buf) < TPM_HEADER_SIZE +
> > - sizeof(out->rng_data_len) + recd) {
> > - rc = -EFAULT;
> > - goto out;
> > - }
> > memcpy(dest, out->rng_data, recd);
> >
> > dest += recd;
> > total += recd;
> > num_bytes -= recd;
> >
> > - tpm_buf_reset(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
> > } while (retries-- && total < max);
> >
> > rc = total ? (int)total : -EIO;
> > -out:
> > - tpm_buf_destroy(&buf);
> > return rc;
> > }
> >
> > #define TPM_ORD_PCRREAD 21
> > int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
> > {
> > - struct tpm_buf buf;
> > int rc;
> >
> > - rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCRREAD);
> > - if (rc)
> > - return rc;
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> >
> > - tpm_buf_append_u32(&buf, pcr_idx);
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_PCRREAD);
> > + tpm_buf_append_u32(buf, pcr_idx);
> >
> > - rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE,
> > + rc = tpm_transmit_cmd(chip, buf, TPM_DIGEST_SIZE,
> > "attempting to read a pcr value");
> > if (rc)
> > - goto out;
> > -
> > - if (tpm_buf_length(&buf) < TPM_DIGEST_SIZE) {
> > - rc = -EFAULT;
> > - goto out;
> > - }
> > + return rc;
> >
> > - memcpy(res_buf, &buf.data[TPM_HEADER_SIZE], TPM_DIGEST_SIZE);
> > + if (buf->length < TPM_DIGEST_SIZE)
> > + return -EFAULT;
> >
> > -out:
> > - tpm_buf_destroy(&buf);
> > + memcpy(res_buf, &buf->data[TPM_HEADER_SIZE], TPM_DIGEST_SIZE);
> > return rc;
> > }
> >
> > @@ -619,15 +608,14 @@ int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
> > */
> > static int tpm1_continue_selftest(struct tpm_chip *chip)
> > {
> > - struct tpm_buf buf;
> > int rc;
> >
> > - rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_CONTINUE_SELFTEST);
> > - if (rc)
> > - return rc;
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> >
> > - rc = tpm_transmit_cmd(chip, &buf, 0, "continue selftest");
> > - tpm_buf_destroy(&buf);
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_CONTINUE_SELFTEST);
> > + rc = tpm_transmit_cmd(chip, buf, 0, "continue selftest");
> > return rc;
> > }
> >
> > @@ -742,22 +730,23 @@ int tpm1_auto_startup(struct tpm_chip *chip)
> > int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
> > {
> > u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 };
> > - struct tpm_buf buf;
> > unsigned int try;
> > int rc;
> >
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> >
> > /* for buggy tpm, flush pcrs with extend to selected dummy */
> > if (tpm_suspend_pcr)
> > rc = tpm1_pcr_extend(chip, tpm_suspend_pcr, dummy_hash,
> > "extending dummy pcr before suspend");
> >
> > - rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
> > - if (rc)
> > - return rc;
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
> > +
> > /* now do the actual savestate */
> > for (try = 0; try < TPM_RETRY; try++) {
> > - rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
> > + rc = tpm_transmit_cmd(chip, buf, 0, NULL);
> > /*
> > * If the TPM indicates that it is too busy to respond to
> > * this command then retry before giving up. It can take
> > @@ -772,7 +761,7 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
> > break;
> > tpm_msleep(TPM_TIMEOUT_RETRY);
> >
> > - tpm_buf_reset(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
> > }
> >
> > if (rc)
> > @@ -782,8 +771,6 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
> > dev_warn(&chip->dev, "TPM savestate took %dms\n",
> > try * TPM_TIMEOUT_RETRY);
> >
> > - tpm_buf_destroy(&buf);
> > -
> > return rc;
> > }
> >
> > diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
> > index 524d802ede26..56d8bc496cd6 100644
> > --- a/drivers/char/tpm/tpm2-cmd.c
> > +++ b/drivers/char/tpm/tpm2-cmd.c
> > @@ -167,12 +167,15 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
> > {
> > int i;
> > int rc;
> > - struct tpm_buf buf;
> > struct tpm2_pcr_read_out *out;
> > u8 pcr_select[TPM2_PCR_SELECT_MIN] = {0};
> > u16 digest_size;
> > u16 expected_digest_size = 0;
> >
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> > +
> > if (pcr_idx >= TPM2_PLATFORM_PCR)
> > return -EINVAL;
> >
> > @@ -187,36 +190,30 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
> > expected_digest_size = chip->allocated_banks[i].digest_size;
> > }
> >
> > - rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ);
> > - if (rc)
> > - return rc;
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ);
> >
> > pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
> >
> > - tpm_buf_append_u32(&buf, 1);
> > - tpm_buf_append_u16(&buf, digest->alg_id);
> > - tpm_buf_append_u8(&buf, TPM2_PCR_SELECT_MIN);
> > - tpm_buf_append(&buf, (const unsigned char *)pcr_select,
> > + tpm_buf_append_u32(buf, 1);
> > + tpm_buf_append_u16(buf, digest->alg_id);
> > + tpm_buf_append_u8(buf, TPM2_PCR_SELECT_MIN);
> > + tpm_buf_append(buf, (const unsigned char *)pcr_select,
> > sizeof(pcr_select));
> >
> > - rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to read a pcr value");
> > + rc = tpm_transmit_cmd(chip, buf, 0, "attempting to read a pcr value");
> > if (rc)
> > - goto out;
> > + return rc;
> >
> > - out = (struct tpm2_pcr_read_out *)&buf.data[TPM_HEADER_SIZE];
> > + out = (struct tpm2_pcr_read_out *)&buf->data[TPM_HEADER_SIZE];
> > digest_size = be16_to_cpu(out->digest_size);
> > if (digest_size > sizeof(digest->digest) ||
> > - (!digest_size_ptr && digest_size != expected_digest_size)) {
> > - rc = -EINVAL;
> > - goto out;
> > - }
> > + (!digest_size_ptr && digest_size != expected_digest_size))
> > + return rc;
> >
> > if (digest_size_ptr)
> > *digest_size_ptr = digest_size;
> >
> > memcpy(digest->digest, out->digest, digest_size);
> > -out:
> > - tpm_buf_destroy(&buf);
> > return rc;
> > }
> >
> > @@ -232,46 +229,42 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
> > int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
> > struct tpm_digest *digests)
> > {
> > - struct tpm_buf buf;
> > int rc;
> > int i;
> >
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> > +
> > if (!disable_pcr_integrity) {
> > rc = tpm2_start_auth_session(chip);
> > if (rc)
> > return rc;
> > }
> >
> > - rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
> > - if (rc) {
> > - if (!disable_pcr_integrity)
> > - tpm2_end_auth_session(chip);
> > - return rc;
> > - }
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
> >
> > if (!disable_pcr_integrity) {
> > - tpm_buf_append_name(chip, &buf, pcr_idx, NULL);
> > - tpm_buf_append_hmac_session(chip, &buf, 0, NULL, 0);
> > + tpm_buf_append_name(chip, buf, pcr_idx, NULL);
> > + tpm_buf_append_hmac_session(chip, buf, 0, NULL, 0);
> > } else {
> > - tpm_buf_append_handle(chip, &buf, pcr_idx);
> > - tpm_buf_append_auth(chip, &buf, 0, NULL, 0);
> > + tpm_buf_append_handle(chip, buf, pcr_idx);
> > + tpm_buf_append_auth(chip, buf, 0, NULL, 0);
> > }
> >
> > - tpm_buf_append_u32(&buf, chip->nr_allocated_banks);
> > + tpm_buf_append_u32(buf, chip->nr_allocated_banks);
> >
> > for (i = 0; i < chip->nr_allocated_banks; i++) {
> > - tpm_buf_append_u16(&buf, digests[i].alg_id);
> > - tpm_buf_append(&buf, (const unsigned char *)&digests[i].digest,
> > + tpm_buf_append_u16(buf, digests[i].alg_id);
> > + tpm_buf_append(buf, (const unsigned char *)&digests[i].digest,
> > chip->allocated_banks[i].digest_size);
> > }
> >
> > if (!disable_pcr_integrity)
> > - tpm_buf_fill_hmac_session(chip, &buf);
> > - rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value");
> > + tpm_buf_fill_hmac_session(chip, buf);
> > + rc = tpm_transmit_cmd(chip, buf, 0, "attempting extend a PCR value");
> > if (!disable_pcr_integrity)
> > - rc = tpm_buf_check_hmac_response(chip, &buf, rc);
> > -
> > - tpm_buf_destroy(&buf);
> > + rc = tpm_buf_check_hmac_response(chip, buf, rc);
> >
> > return rc;
> > }
> > @@ -296,7 +289,6 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
> > {
> > struct tpm2_get_random_out *out;
> > struct tpm_header *head;
> > - struct tpm_buf buf;
> > u32 recd;
> > u32 num_bytes = max;
> > int err;
> > @@ -308,43 +300,41 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
> > if (!num_bytes || max > TPM_MAX_RNG_DATA)
> > return -EINVAL;
> >
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> > +
> > err = tpm2_start_auth_session(chip);
> > if (err)
> > return err;
> >
> > - err = tpm_buf_init(&buf, 0, 0);
> > - if (err) {
> > - tpm2_end_auth_session(chip);
> > - return err;
> > - }
> > -
> > do {
> > - tpm_buf_reset(&buf, TPM2_ST_SESSIONS, TPM2_CC_GET_RANDOM);
> > - tpm_buf_append_hmac_session_opt(chip, &buf, TPM2_SA_ENCRYPT
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_GET_RANDOM);
> > + tpm_buf_append_hmac_session_opt(chip, buf, TPM2_SA_ENCRYPT
> > | TPM2_SA_CONTINUE_SESSION,
> > NULL, 0);
> > - tpm_buf_append_u16(&buf, num_bytes);
> > - tpm_buf_fill_hmac_session(chip, &buf);
> > - err = tpm_transmit_cmd(chip, &buf,
> > + tpm_buf_append_u16(buf, num_bytes);
> > + tpm_buf_fill_hmac_session(chip, buf);
> > + err = tpm_transmit_cmd(chip, buf,
> > offsetof(struct tpm2_get_random_out,
> > buffer),
> > "attempting get random");
> > - err = tpm_buf_check_hmac_response(chip, &buf, err);
> > + err = tpm_buf_check_hmac_response(chip, buf, err);
> > if (err) {
> > if (err > 0)
> > err = -EIO;
> > goto out;
> > }
> >
> > - head = (struct tpm_header *)buf.data;
> > + head = (struct tpm_header *)buf->data;
> > offset = TPM_HEADER_SIZE;
> > /* Skip the parameter size field: */
> > if (be16_to_cpu(head->tag) == TPM2_ST_SESSIONS)
> > offset += 4;
> >
> > - out = (struct tpm2_get_random_out *)&buf.data[offset];
> > + out = (struct tpm2_get_random_out *)&buf->data[offset];
> > recd = min_t(u32, be16_to_cpu(out->size), num_bytes);
> > - if (tpm_buf_length(&buf) <
> > + if (tpm_buf_length(buf) <
> > TPM_HEADER_SIZE +
> > offsetof(struct tpm2_get_random_out, buffer) +
> > recd) {
> > @@ -358,11 +348,9 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
> > num_bytes -= recd;
> > } while (retries-- && total < max);
> >
> > - tpm_buf_destroy(&buf);
> > -
> > return total ? total : -EIO;
> > +
> > out:
> > - tpm_buf_destroy(&buf);
> > tpm2_end_auth_session(chip);
> > return err;
> > }
> > @@ -374,20 +362,17 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
> > */
> > void tpm2_flush_context(struct tpm_chip *chip, u32 handle)
> > {
> > - struct tpm_buf buf;
> > - int rc;
> > -
> > - rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
> > - if (rc) {
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf) {
> > dev_warn(&chip->dev, "0x%08x was not flushed, out of memory\n",
> > handle);
> > return;
> > }
> >
> > - tpm_buf_append_u32(&buf, handle);
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
> > + tpm_buf_append_u32(buf, handle);
> >
> > - tpm_transmit_cmd(chip, &buf, 0, "flushing context");
> > - tpm_buf_destroy(&buf);
> > + tpm_transmit_cmd(chip, buf, 0, "flushing context");
> > }
> > EXPORT_SYMBOL_GPL(tpm2_flush_context);
> >
> > @@ -414,19 +399,20 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
> > const char *desc)
> > {
> > struct tpm2_get_cap_out *out;
> > - struct tpm_buf buf;
> > int rc;
> >
> > - rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
> > - if (rc)
> > - return rc;
> > - tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
> > - tpm_buf_append_u32(&buf, property_id);
> > - tpm_buf_append_u32(&buf, 1);
> > - rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> > +
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
> > + tpm_buf_append_u32(buf, TPM2_CAP_TPM_PROPERTIES);
> > + tpm_buf_append_u32(buf, property_id);
> > + tpm_buf_append_u32(buf, 1);
> > + rc = tpm_transmit_cmd(chip, buf, 0, NULL);
> > if (!rc) {
> > out = (struct tpm2_get_cap_out *)
> > - &buf.data[TPM_HEADER_SIZE];
> > + &buf->data[TPM_HEADER_SIZE];
> > /*
> > * To prevent failing boot up of some systems, Infineon TPM2.0
> > * returns SUCCESS on TPM2_Startup in field upgrade mode. Also
> > @@ -438,7 +424,6 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
> > else
> > rc = -ENODATA;
> > }
> > - tpm_buf_destroy(&buf);
> > return rc;
> > }
> > EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);
> > @@ -455,15 +440,13 @@ EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);
> > */
> > void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
> > {
> > - struct tpm_buf buf;
> > - int rc;
> > -
> > - rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SHUTDOWN);
> > - if (rc)
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > return;
> > - tpm_buf_append_u16(&buf, shutdown_type);
> > - tpm_transmit_cmd(chip, &buf, 0, "stopping the TPM");
> > - tpm_buf_destroy(&buf);
> > +
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_SHUTDOWN);
> > + tpm_buf_append_u16(buf, shutdown_type);
> > + tpm_transmit_cmd(chip, buf, 0, "stopping the TPM");
> > }
> >
> > /**
> > @@ -481,19 +464,18 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
> > */
> > static int tpm2_do_selftest(struct tpm_chip *chip)
> > {
> > - struct tpm_buf buf;
> > int full;
> > int rc;
> >
> > - for (full = 0; full < 2; full++) {
> > - rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SELF_TEST);
> > - if (rc)
> > - return rc;
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> >
> > - tpm_buf_append_u8(&buf, full);
> > - rc = tpm_transmit_cmd(chip, &buf, 0,
> > + for (full = 0; full < 2; full++) {
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_SELF_TEST);
> > + tpm_buf_append_u8(buf, full);
> > + rc = tpm_transmit_cmd(chip, buf, 0,
> > "attempting the self test");
> > - tpm_buf_destroy(&buf);
> >
> > if (rc == TPM2_RC_TESTING)
> > rc = TPM2_RC_SUCCESS;
> > @@ -519,23 +501,23 @@ static int tpm2_do_selftest(struct tpm_chip *chip)
> > int tpm2_probe(struct tpm_chip *chip)
> > {
> > struct tpm_header *out;
> > - struct tpm_buf buf;
> > int rc;
> >
> > - rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
> > - if (rc)
> > - return rc;
> > - tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
> > - tpm_buf_append_u32(&buf, TPM_PT_TOTAL_COMMANDS);
> > - tpm_buf_append_u32(&buf, 1);
> > - rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> > +
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
> > + tpm_buf_append_u32(buf, TPM2_CAP_TPM_PROPERTIES);
> > + tpm_buf_append_u32(buf, TPM_PT_TOTAL_COMMANDS);
> > + tpm_buf_append_u32(buf, 1);
> > + rc = tpm_transmit_cmd(chip, buf, 0, NULL);
> > /* We ignore TPM return codes on purpose. */
> > if (rc >= 0) {
> > - out = (struct tpm_header *)buf.data;
> > + out = (struct tpm_header *)buf->data;
> > if (be16_to_cpu(out->tag) == TPM2_ST_NO_SESSIONS)
> > chip->flags |= TPM_CHIP_FLAG_TPM2;
> > }
> > - tpm_buf_destroy(&buf);
> > return 0;
> > }
> > EXPORT_SYMBOL_GPL(tpm2_probe);
> > @@ -575,7 +557,6 @@ struct tpm2_pcr_selection {
> > ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
> > {
> > struct tpm2_pcr_selection pcr_selection;
> > - struct tpm_buf buf;
> > void *marker;
> > void *end;
> > void *pcr_select_offset;
> > @@ -587,41 +568,38 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
> > int rc;
> > int i = 0;
> >
> > - rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
> > - if (rc)
> > - return rc;
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> >
> > - tpm_buf_append_u32(&buf, TPM2_CAP_PCRS);
> > - tpm_buf_append_u32(&buf, 0);
> > - tpm_buf_append_u32(&buf, 1);
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
> > + tpm_buf_append_u32(buf, TPM2_CAP_PCRS);
> > + tpm_buf_append_u32(buf, 0);
> > + tpm_buf_append_u32(buf, 1);
> >
> > - rc = tpm_transmit_cmd(chip, &buf, 9, "get tpm pcr allocation");
> > + rc = tpm_transmit_cmd(chip, buf, 9, "get tpm pcr allocation");
> > if (rc)
> > - goto out;
> > + return rc;
> >
> > nr_possible_banks = be32_to_cpup(
> > - (__be32 *)&buf.data[TPM_HEADER_SIZE + 5]);
> > + (__be32 *)&buf->data[TPM_HEADER_SIZE + 5]);
> >
> > chip->allocated_banks = kcalloc(nr_possible_banks,
> > sizeof(*chip->allocated_banks),
> > GFP_KERNEL);
> > - if (!chip->allocated_banks) {
> > - rc = -ENOMEM;
> > - goto out;
> > - }
> > + if (!chip->allocated_banks)
> > + return -ENOMEM;
> >
> > - marker = &buf.data[TPM_HEADER_SIZE + 9];
> > + marker = &buf->data[TPM_HEADER_SIZE + 9];
> >
> > - rsp_len = be32_to_cpup((__be32 *)&buf.data[2]);
> > - end = &buf.data[rsp_len];
> > + rsp_len = be32_to_cpup((__be32 *)&buf->data[2]);
> > + end = &buf->data[rsp_len];
> >
> > for (i = 0; i < nr_possible_banks; i++) {
> > pcr_select_offset = marker +
> > offsetof(struct tpm2_pcr_selection, size_of_select);
> > - if (pcr_select_offset >= end) {
> > - rc = -EFAULT;
> > - break;
> > - }
> > + if (pcr_select_offset >= end)
> > + return -EFAULT;
> >
> > memcpy(&pcr_selection, marker, sizeof(pcr_selection));
> > hash_alg = be16_to_cpu(pcr_selection.hash_alg);
> > @@ -633,7 +611,7 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
> >
> > rc = tpm2_init_bank_info(chip, nr_alloc_banks);
> > if (rc < 0)
> > - break;
> > + return rc;
> >
> > nr_alloc_banks++;
> > }
> > @@ -645,21 +623,21 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
> > }
> >
> > chip->nr_allocated_banks = nr_alloc_banks;
> > -out:
> > - tpm_buf_destroy(&buf);
> > -
> > - return rc;
> > + return 0;
> > }
> >
> > int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
> > {
> > - struct tpm_buf buf;
> > u32 nr_commands;
> > __be32 *attrs;
> > u32 cc;
> > int i;
> > int rc;
> >
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> > +
> > rc = tpm2_get_tpm_pt(chip, TPM_PT_TOTAL_COMMANDS, &nr_commands, NULL);
> > if (rc)
> > goto out;
> > @@ -676,30 +654,24 @@ int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
> > goto out;
> > }
> >
> > - rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
> > - if (rc)
> > - goto out;
> > -
> > - tpm_buf_append_u32(&buf, TPM2_CAP_COMMANDS);
> > - tpm_buf_append_u32(&buf, TPM2_CC_FIRST);
> > - tpm_buf_append_u32(&buf, nr_commands);
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
> > + tpm_buf_append_u32(buf, TPM2_CAP_COMMANDS);
> > + tpm_buf_append_u32(buf, TPM2_CC_FIRST);
> > + tpm_buf_append_u32(buf, nr_commands);
> >
> > - rc = tpm_transmit_cmd(chip, &buf, 9 + 4 * nr_commands, NULL);
> > - if (rc) {
> > - tpm_buf_destroy(&buf);
> > + rc = tpm_transmit_cmd(chip, buf, 9 + 4 * nr_commands, NULL);
> > + if (rc)
> > goto out;
> > - }
> >
> > if (nr_commands !=
> > - be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE + 5])) {
> > + be32_to_cpup((__be32 *)&buf->data[TPM_HEADER_SIZE + 5])) {
> > rc = -EFAULT;
> > - tpm_buf_destroy(&buf);
> > goto out;
> > }
> >
> > chip->nr_commands = nr_commands;
> >
> > - attrs = (__be32 *)&buf.data[TPM_HEADER_SIZE + 9];
> > + attrs = (__be32 *)&buf->data[TPM_HEADER_SIZE + 9];
> > for (i = 0; i < nr_commands; i++, attrs++) {
> > chip->cc_attrs_tbl[i] = be32_to_cpup(attrs);
> > cc = chip->cc_attrs_tbl[i] & 0xFFFF;
> > @@ -711,8 +683,6 @@ int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
> > }
> > }
> >
> > - tpm_buf_destroy(&buf);
> > -
> > out:
> > if (rc > 0)
> > rc = -ENODEV;
> > @@ -733,20 +703,16 @@ EXPORT_SYMBOL_GPL(tpm2_get_cc_attrs_tbl);
> >
> > static int tpm2_startup(struct tpm_chip *chip)
> > {
> > - struct tpm_buf buf;
> > - int rc;
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> >
> > dev_info(&chip->dev, "starting up the TPM manually\n");
> >
> > - rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP);
> > - if (rc < 0)
> > - return rc;
> > -
> > - tpm_buf_append_u16(&buf, TPM2_SU_CLEAR);
> > - rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM");
> > - tpm_buf_destroy(&buf);
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP);
> > + tpm_buf_append_u16(buf, TPM2_SU_CLEAR);
> >
> > - return rc;
> > + return tpm_transmit_cmd(chip, buf, 0, "attempting to start the TPM");
> > }
> >
> > /**
> > diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c
> > index 6d03c224e6b2..b2c0c2143adc 100644
> > --- a/drivers/char/tpm/tpm2-sessions.c
> > +++ b/drivers/char/tpm/tpm2-sessions.c
> > @@ -182,19 +182,17 @@ static int tpm2_parse_read_public(char *name, struct tpm_buf *buf)
> >
> > static int tpm2_read_public(struct tpm_chip *chip, u32 handle, char *name)
> > {
> > - struct tpm_buf buf;
> > int rc;
> >
> > - rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_READ_PUBLIC);
> > - if (rc)
> > - return rc;
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> >
> > - tpm_buf_append_u32(&buf, handle);
> > - rc = tpm_transmit_cmd(chip, &buf, 0, "read public");
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_READ_PUBLIC);
> > + tpm_buf_append_u32(buf, handle);
> > + rc = tpm_transmit_cmd(chip, buf, 0, "read public");
> > if (rc == TPM2_RC_SUCCESS)
> > - rc = tpm2_parse_read_public(name, &buf);
> > -
> > - tpm_buf_destroy(&buf);
> > + rc = tpm2_parse_read_public(name, buf);
> >
> > return rc;
> > }
> > @@ -925,7 +923,6 @@ static int tpm2_load_null(struct tpm_chip *chip, u32 *null_key)
> > int tpm2_start_auth_session(struct tpm_chip *chip)
> > {
> > struct tpm2_auth *auth;
> > - struct tpm_buf buf;
> > u32 null_key;
> > int rc;
> >
> > @@ -934,6 +931,10 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
> > return 0;
> > }
> >
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> > +
> > auth = kzalloc(sizeof(*auth), GFP_KERNEL);
> > if (!auth)
> > return -ENOMEM;
> > @@ -944,41 +945,36 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
> >
> > auth->session = TPM_HEADER_SIZE;
> >
> > - rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_START_AUTH_SESS);
> > - if (rc)
> > - goto out;
> > -
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_START_AUTH_SESS);
> > /* salt key handle */
> > - tpm_buf_append_u32(&buf, null_key);
> > + tpm_buf_append_u32(buf, null_key);
> > /* bind key handle */
> > - tpm_buf_append_u32(&buf, TPM2_RH_NULL);
> > + tpm_buf_append_u32(buf, TPM2_RH_NULL);
> > /* nonce caller */
> > get_random_bytes(auth->our_nonce, sizeof(auth->our_nonce));
> > - tpm_buf_append_u16(&buf, sizeof(auth->our_nonce));
> > - tpm_buf_append(&buf, auth->our_nonce, sizeof(auth->our_nonce));
> > + tpm_buf_append_u16(buf, sizeof(auth->our_nonce));
> > + tpm_buf_append(buf, auth->our_nonce, sizeof(auth->our_nonce));
> >
> > /* append encrypted salt and squirrel away unencrypted in auth */
> > - tpm_buf_append_salt(&buf, chip, auth);
> > + tpm_buf_append_salt(buf, chip, auth);
> > /* session type (HMAC, audit or policy) */
> > - tpm_buf_append_u8(&buf, TPM2_SE_HMAC);
> > + tpm_buf_append_u8(buf, TPM2_SE_HMAC);
> >
> > /* symmetric encryption parameters */
> > /* symmetric algorithm */
> > - tpm_buf_append_u16(&buf, TPM_ALG_AES);
> > + tpm_buf_append_u16(buf, TPM_ALG_AES);
> > /* bits for symmetric algorithm */
> > - tpm_buf_append_u16(&buf, AES_KEY_BITS);
> > + tpm_buf_append_u16(buf, AES_KEY_BITS);
> > /* symmetric algorithm mode (must be CFB) */
> > - tpm_buf_append_u16(&buf, TPM_ALG_CFB);
> > + tpm_buf_append_u16(buf, TPM_ALG_CFB);
> > /* hash algorithm for session */
> > - tpm_buf_append_u16(&buf, TPM_ALG_SHA256);
> > + tpm_buf_append_u16(buf, TPM_ALG_SHA256);
> >
> > - rc = tpm_ret_to_err(tpm_transmit_cmd(chip, &buf, 0, "StartAuthSession"));
> > + rc = tpm_ret_to_err(tpm_transmit_cmd(chip, buf, 0, "StartAuthSession"));
> > tpm2_flush_context(chip, null_key);
> >
> > if (rc == TPM2_RC_SUCCESS)
> > - rc = tpm2_parse_start_auth_session(auth, &buf);
> > -
> > - tpm_buf_destroy(&buf);
> > + rc = tpm2_parse_start_auth_session(auth, buf);
> >
> > if (rc == TPM2_RC_SUCCESS) {
> > chip->auth = auth;
> > @@ -1200,18 +1196,17 @@ static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
> > u32 *handle, u8 *name)
> > {
> > int rc;
> > - struct tpm_buf buf;
> > - struct tpm_buf template;
> >
> > - rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE_PRIMARY);
> > - if (rc)
> > - return rc;
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> >
> > - rc = tpm_buf_init_sized(&template);
> > - if (rc) {
> > - tpm_buf_destroy(&buf);
> > - return rc;
> > - }
> > + struct tpm_buf *template __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!template)
> > + return -ENOMEM;
> > +
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_CREATE_PRIMARY);
> > + tpm_buf_reset_sized(template, PAGE_SIZE);
> >
> > /*
> > * create the template. Note: in order for userspace to
> > @@ -1223,75 +1218,72 @@ static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
> > */
> >
> > /* key type */
> > - tpm_buf_append_u16(&template, TPM_ALG_ECC);
> > + tpm_buf_append_u16(template, TPM_ALG_ECC);
> >
> > /* name algorithm */
> > - tpm_buf_append_u16(&template, TPM_ALG_SHA256);
> > + tpm_buf_append_u16(template, TPM_ALG_SHA256);
> >
> > /* object properties */
> > - tpm_buf_append_u32(&template, TPM2_OA_NULL_KEY);
> > + tpm_buf_append_u32(template, TPM2_OA_NULL_KEY);
> >
> > /* sauth policy (empty) */
> > - tpm_buf_append_u16(&template, 0);
> > + tpm_buf_append_u16(template, 0);
> >
> > /* BEGIN parameters: key specific; for ECC*/
> >
> > /* symmetric algorithm */
> > - tpm_buf_append_u16(&template, TPM_ALG_AES);
> > + tpm_buf_append_u16(template, TPM_ALG_AES);
> >
> > /* bits for symmetric algorithm */
> > - tpm_buf_append_u16(&template, AES_KEY_BITS);
> > + tpm_buf_append_u16(template, AES_KEY_BITS);
> >
> > /* algorithm mode (must be CFB) */
> > - tpm_buf_append_u16(&template, TPM_ALG_CFB);
> > + tpm_buf_append_u16(template, TPM_ALG_CFB);
> >
> > /* scheme (NULL means any scheme) */
> > - tpm_buf_append_u16(&template, TPM_ALG_NULL);
> > + tpm_buf_append_u16(template, TPM_ALG_NULL);
> >
> > /* ECC Curve ID */
> > - tpm_buf_append_u16(&template, TPM2_ECC_NIST_P256);
> > + tpm_buf_append_u16(template, TPM2_ECC_NIST_P256);
> >
> > /* KDF Scheme */
> > - tpm_buf_append_u16(&template, TPM_ALG_NULL);
> > + tpm_buf_append_u16(template, TPM_ALG_NULL);
> >
> > /* unique: key specific; for ECC it is two zero size points */
> > - tpm_buf_append_u16(&template, 0);
> > - tpm_buf_append_u16(&template, 0);
> > + tpm_buf_append_u16(template, 0);
> > + tpm_buf_append_u16(template, 0);
> >
> > /* END parameters */
> >
> > /* primary handle */
> > - tpm_buf_append_u32(&buf, hierarchy);
> > - tpm_buf_append_empty_auth(&buf, TPM2_RS_PW);
> > + tpm_buf_append_u32(buf, hierarchy);
> > + tpm_buf_append_empty_auth(buf, TPM2_RS_PW);
> >
> > /* sensitive create size is 4 for two empty buffers */
> > - tpm_buf_append_u16(&buf, 4);
> > + tpm_buf_append_u16(buf, 4);
> >
> > /* sensitive create auth data (empty) */
> > - tpm_buf_append_u16(&buf, 0);
> > + tpm_buf_append_u16(buf, 0);
> >
> > /* sensitive create sensitive data (empty) */
> > - tpm_buf_append_u16(&buf, 0);
> > + tpm_buf_append_u16(buf, 0);
> >
> > /* the public template */
> > - tpm_buf_append(&buf, template.data, template.length);
> > - tpm_buf_destroy(&template);
> > + tpm_buf_append(buf, template->data, template->length);
> >
> > /* outside info (empty) */
> > - tpm_buf_append_u16(&buf, 0);
> > + tpm_buf_append_u16(buf, 0);
> >
> > /* creation PCR (none) */
> > - tpm_buf_append_u32(&buf, 0);
> > + tpm_buf_append_u32(buf, 0);
> >
> > - rc = tpm_transmit_cmd(chip, &buf, 0,
> > + rc = tpm_transmit_cmd(chip, buf, 0,
> > "attempting to create NULL primary");
> >
> > if (rc == TPM2_RC_SUCCESS)
> > - rc = tpm2_parse_create_primary(chip, &buf, handle, hierarchy,
> > + rc = tpm2_parse_create_primary(chip, buf, handle, hierarchy,
> > name);
> >
> > - tpm_buf_destroy(&buf);
> > -
> > return rc;
> > }
> >
> > diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c
> > index 60354cd53b5c..c7409c4c78d0 100644
> > --- a/drivers/char/tpm/tpm2-space.c
> > +++ b/drivers/char/tpm/tpm2-space.c
> > @@ -71,24 +71,24 @@ void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space)
> > int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
> > unsigned int *offset, u32 *handle)
> > {
> > - struct tpm_buf tbuf;
> > struct tpm2_context *ctx;
> > unsigned int body_size;
> > int rc;
> >
> > - rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
> > - if (rc)
> > - return rc;
> > + struct tpm_buf *tbuf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!tbuf)
> > + return -ENOMEM;
> > +
> > + tpm_buf_reset(tbuf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
> >
> > ctx = (struct tpm2_context *)&buf[*offset];
> > body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size);
> > - tpm_buf_append(&tbuf, &buf[*offset], body_size);
> > + tpm_buf_append(tbuf, &buf[*offset], body_size);
> >
> > - rc = tpm_transmit_cmd(chip, &tbuf, 4, NULL);
> > + rc = tpm_transmit_cmd(chip, tbuf, 4, NULL);
> > if (rc < 0) {
> > dev_warn(&chip->dev, "%s: failed with a system error %d\n",
> > __func__, rc);
> > - tpm_buf_destroy(&tbuf);
> > return -EFAULT;
> > } else if (tpm2_rc_value(rc) == TPM2_RC_HANDLE ||
> > rc == TPM2_RC_REFERENCE_H0) {
> > @@ -103,64 +103,54 @@ int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
> > * flushed outside the space
> > */
> > *handle = 0;
> > - tpm_buf_destroy(&tbuf);
> > return -ENOENT;
> > } else if (tpm2_rc_value(rc) == TPM2_RC_INTEGRITY) {
> > - tpm_buf_destroy(&tbuf);
> > return -EINVAL;
> > } else if (rc > 0) {
> > dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
> > __func__, rc);
> > - tpm_buf_destroy(&tbuf);
> > return -EFAULT;
> > }
> >
> > - *handle = be32_to_cpup((__be32 *)&tbuf.data[TPM_HEADER_SIZE]);
> > + *handle = be32_to_cpup((__be32 *)&tbuf->data[TPM_HEADER_SIZE]);
> > *offset += body_size;
> > -
> > - tpm_buf_destroy(&tbuf);
> > return 0;
> > }
> >
> > int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
> > unsigned int buf_size, unsigned int *offset)
> > {
> > - struct tpm_buf tbuf;
> > unsigned int body_size;
> > int rc;
> >
> > - rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE);
> > - if (rc)
> > - return rc;
> > + struct tpm_buf *tbuf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!tbuf)
> > + return -ENOMEM;
> >
> > - tpm_buf_append_u32(&tbuf, handle);
> > + tpm_buf_reset(tbuf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE);
> > + tpm_buf_append_u32(tbuf, handle);
> >
> > - rc = tpm_transmit_cmd(chip, &tbuf, 0, NULL);
> > + rc = tpm_transmit_cmd(chip, tbuf, 0, NULL);
> > if (rc < 0) {
> > dev_warn(&chip->dev, "%s: failed with a system error %d\n",
> > __func__, rc);
> > - tpm_buf_destroy(&tbuf);
> > return -EFAULT;
> > } else if (tpm2_rc_value(rc) == TPM2_RC_REFERENCE_H0) {
> > - tpm_buf_destroy(&tbuf);
> > return -ENOENT;
> > } else if (rc) {
> > dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
> > __func__, rc);
> > - tpm_buf_destroy(&tbuf);
> > return -EFAULT;
> > }
> >
> > - body_size = tpm_buf_length(&tbuf) - TPM_HEADER_SIZE;
> > + body_size = tpm_buf_length(tbuf) - TPM_HEADER_SIZE;
> > if ((*offset + body_size) > buf_size) {
> > dev_warn(&chip->dev, "%s: out of backing storage\n", __func__);
> > - tpm_buf_destroy(&tbuf);
> > return -ENOMEM;
> > }
> >
> > - memcpy(&buf[*offset], &tbuf.data[TPM_HEADER_SIZE], body_size);
> > + memcpy(&buf[*offset], &tbuf->data[TPM_HEADER_SIZE], body_size);
> > *offset += body_size;
> > - tpm_buf_destroy(&tbuf);
> > return 0;
> > }
> >
> > diff --git a/drivers/char/tpm/tpm_vtpm_proxy.c b/drivers/char/tpm/tpm_vtpm_proxy.c
> > index 0818bb517805..7ebe55825215 100644
> > --- a/drivers/char/tpm/tpm_vtpm_proxy.c
> > +++ b/drivers/char/tpm/tpm_vtpm_proxy.c
> > @@ -395,40 +395,35 @@ static bool vtpm_proxy_tpm_req_canceled(struct tpm_chip *chip, u8 status)
> >
> > static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality)
> > {
> > - struct tpm_buf buf;
> > int rc;
> > const struct tpm_header *header;
> > struct proxy_dev *proxy_dev = dev_get_drvdata(&chip->dev);
> >
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> > +
> > if (chip->flags & TPM_CHIP_FLAG_TPM2)
> > - rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS,
> > - TPM2_CC_SET_LOCALITY);
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_SET_LOCALITY);
> > else
> > - rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND,
> > - TPM_ORD_SET_LOCALITY);
> > - if (rc)
> > - return rc;
> > - tpm_buf_append_u8(&buf, locality);
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_SET_LOCALITY);
> > +
> > + tpm_buf_append_u8(buf, locality);
> >
> > proxy_dev->state |= STATE_DRIVER_COMMAND;
> >
> > - rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to set locality");
> > + rc = tpm_transmit_cmd(chip, buf, 0, "attempting to set locality");
> >
> > proxy_dev->state &= ~STATE_DRIVER_COMMAND;
> >
> > - if (rc < 0) {
> > - locality = rc;
> > - goto out;
> > - }
> > + if (rc < 0)
> > + return rc;
> >
> > - header = (const struct tpm_header *)buf.data;
> > + header = (const struct tpm_header *)buf->data;
> > rc = be32_to_cpu(header->return_code);
> > if (rc)
> > locality = -1;
> >
> > -out:
> > - tpm_buf_destroy(&buf);
> > -
> > return locality;
> > }
> >
> > diff --git a/include/linux/tpm.h b/include/linux/tpm.h
> > index b0e9eb5ef022..1d8b016dd6bc 100644
> > --- a/include/linux/tpm.h
> > +++ b/include/linux/tpm.h
> > @@ -375,13 +375,15 @@ enum tpm_buf_flags {
> > };
> >
> > /*
> > - * A string buffer type for constructing TPM commands.
> > + * A buffer for constructing and parsing TPM commands, responses and sized
> > + * (TPM2B) buffers.
> > */
> > struct tpm_buf {
> > - u32 flags;
> > - u32 length;
> > - u8 *data;
> > + u8 flags;
> > u8 handles;
> > + u16 length;
> > + u16 capacity;
> > + u8 data[];
> > };
> >
> > enum tpm2_object_attributes {
> > @@ -412,11 +414,8 @@ struct tpm2_hash {
> > unsigned int tpm_id;
> > };
> >
> > -int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal);
> > -void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal);
> > -int tpm_buf_init_sized(struct tpm_buf *buf);
> > -void tpm_buf_reset_sized(struct tpm_buf *buf);
> > -void tpm_buf_destroy(struct tpm_buf *buf);
> > +void tpm_buf_reset(struct tpm_buf *buf, u16 buf_size, u16 tag, u32 ordinal);
> > +void tpm_buf_reset_sized(struct tpm_buf *buf, u16 buf_size);
> > u32 tpm_buf_length(struct tpm_buf *buf);
> > void tpm_buf_append(struct tpm_buf *buf, const u8 *new_data, u16 new_length);
> > void tpm_buf_append_u8(struct tpm_buf *buf, const u8 value);
> > diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c
> > index 636acb66a4f6..3b710daff084 100644
> > --- a/security/keys/trusted-keys/trusted_tpm1.c
> > +++ b/security/keys/trusted-keys/trusted_tpm1.c
> > @@ -312,21 +312,23 @@ static int TSS_checkhmac2(unsigned char *buffer,
> > */
> > static int trusted_tpm_send(unsigned char *cmd, size_t buflen)
> > {
> > - struct tpm_buf buf;
> > int rc;
> >
> > if (!chip)
> > return -ENODEV;
> >
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> > +
> > rc = tpm_try_get_ops(chip);
> > if (rc)
> > return rc;
> >
> > - buf.flags = 0;
> > - buf.length = buflen;
> > - buf.data = cmd;
> > + tpm_buf_append(buf, cmd, buflen);
> > +
> > dump_tpm_buf(cmd);
> > - rc = tpm_transmit_cmd(chip, &buf, 4, "sending data");
> > + rc = tpm_transmit_cmd(chip, buf, 4, "sending data");
> > dump_tpm_buf(cmd);
> >
> > if (rc > 0)
> > @@ -368,7 +370,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
> > if (ret != TPM_NONCE_SIZE)
> > return -EIO;
> >
> > - tpm_buf_reset(tb, TPM_TAG_RQU_COMMAND, TPM_ORD_OSAP);
> > + tpm_buf_reset(tb, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_OSAP);
> > tpm_buf_append_u16(tb, type);
> > tpm_buf_append_u32(tb, handle);
> > tpm_buf_append(tb, ononce, TPM_NONCE_SIZE);
> > @@ -396,7 +398,7 @@ static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce)
> > if (!chip)
> > return -ENODEV;
> >
> > - tpm_buf_reset(tb, TPM_TAG_RQU_COMMAND, TPM_ORD_OIAP);
> > + tpm_buf_reset(tb, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_OIAP);
> > ret = trusted_tpm_send(tb->data, tb->length);
> > if (ret < 0)
> > return ret;
> > @@ -494,7 +496,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
> > goto out;
> >
> > /* build and send the TPM request packet */
> > - tpm_buf_reset(tb, TPM_TAG_RQU_AUTH1_COMMAND, TPM_ORD_SEAL);
> > + tpm_buf_reset(tb, PAGE_SIZE, TPM_TAG_RQU_AUTH1_COMMAND, TPM_ORD_SEAL);
> > tpm_buf_append_u32(tb, keyhandle);
> > tpm_buf_append(tb, td->encauth, SHA1_DIGEST_SIZE);
> > tpm_buf_append_u32(tb, pcrinfosize);
> > @@ -585,7 +587,7 @@ static int tpm_unseal(struct tpm_buf *tb,
> > return ret;
> >
> > /* build and send TPM request packet */
> > - tpm_buf_reset(tb, TPM_TAG_RQU_AUTH2_COMMAND, TPM_ORD_UNSEAL);
> > + tpm_buf_reset(tb, PAGE_SIZE, TPM_TAG_RQU_AUTH2_COMMAND, TPM_ORD_UNSEAL);
> > tpm_buf_append_u32(tb, keyhandle);
> > tpm_buf_append(tb, blob, bloblen);
> > tpm_buf_append_u32(tb, authhandle1);
> > @@ -624,23 +626,21 @@ static int tpm_unseal(struct tpm_buf *tb,
> > static int key_seal(struct trusted_key_payload *p,
> > struct trusted_key_options *o)
> > {
> > - struct tpm_buf tb;
> > int ret;
> >
> > - ret = tpm_buf_init(&tb, 0, 0);
> > - if (ret)
> > - return ret;
> > + struct tpm_buf *tb __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!tb)
> > + return -ENOMEM;
> >
> > /* include migratable flag at end of sealed key */
> > p->key[p->key_len] = p->migratable;
> >
> > - ret = tpm_seal(&tb, o->keytype, o->keyhandle, o->keyauth,
> > + ret = tpm_seal(tb, o->keytype, o->keyhandle, o->keyauth,
> > p->key, p->key_len + 1, p->blob, &p->blob_len,
> > o->blobauth, o->pcrinfo, o->pcrinfo_len);
> > if (ret < 0)
> > pr_info("srkseal failed (%d)\n", ret);
> >
> > - tpm_buf_destroy(&tb);
> > return ret;
> > }
> >
> > @@ -650,14 +650,13 @@ static int key_seal(struct trusted_key_payload *p,
> > static int key_unseal(struct trusted_key_payload *p,
> > struct trusted_key_options *o)
> > {
> > - struct tpm_buf tb;
> > int ret;
> >
> > - ret = tpm_buf_init(&tb, 0, 0);
> > - if (ret)
> > - return ret;
> > + struct tpm_buf *tb __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!tb)
> > + return -ENOMEM;
> >
> > - ret = tpm_unseal(&tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
> > + ret = tpm_unseal(tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
> > o->blobauth, p->key, &p->key_len);
> > if (ret < 0)
> > pr_info("srkunseal failed (%d)\n", ret);
> > @@ -665,7 +664,6 @@ static int key_unseal(struct trusted_key_payload *p,
> > /* pull migratable flag out of sealed key */
> > p->migratable = p->key[--p->key_len];
> >
> > - tpm_buf_destroy(&tb);
> > return ret;
> > }
> >
> > diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
> > index 024be262702f..472344c788ec 100644
> > --- a/security/keys/trusted-keys/trusted_tpm2.c
> > +++ b/security/keys/trusted-keys/trusted_tpm2.c
> > @@ -242,13 +242,20 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> > struct trusted_key_options *options)
> > {
> > off_t offset = TPM_HEADER_SIZE;
> > - struct tpm_buf buf, sized;
> > int blob_len = 0;
> > u32 hash;
> > u32 flags;
> > int i;
> > int rc;
> >
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> > +
> > + struct tpm_buf *sized __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!sized)
> > + return -ENOMEM;
> > +
> > for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
> > if (options->hash == tpm2_hash_map[i].crypto_id) {
> > hash = tpm2_hash_map[i].tpm_id;
> > @@ -270,89 +277,76 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> > if (rc)
> > goto out_put;
> >
> > - rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
> > - if (rc) {
> > - tpm2_end_auth_session(chip);
> > - goto out_put;
> > - }
> > -
> > - rc = tpm_buf_init_sized(&sized);
> > - if (rc) {
> > - tpm_buf_destroy(&buf);
> > - tpm2_end_auth_session(chip);
> > - goto out_put;
> > - }
> > -
> > - tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);
> > - tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_DECRYPT,
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
> > + tpm_buf_reset_sized(sized, PAGE_SIZE);
> > + tpm_buf_append_name(chip, buf, options->keyhandle, NULL);
> > + tpm_buf_append_hmac_session(chip, buf, TPM2_SA_DECRYPT,
> > options->keyauth, TPM_DIGEST_SIZE);
> >
> > /* sensitive */
> > - tpm_buf_append_u16(&sized, options->blobauth_len);
> > + tpm_buf_append_u16(sized, options->blobauth_len);
> >
> > if (options->blobauth_len)
> > - tpm_buf_append(&sized, options->blobauth, options->blobauth_len);
> > + tpm_buf_append(sized, options->blobauth, options->blobauth_len);
> >
> > - tpm_buf_append_u16(&sized, payload->key_len);
> > - tpm_buf_append(&sized, payload->key, payload->key_len);
> > - tpm_buf_append(&buf, sized.data, sized.length);
> > + tpm_buf_append_u16(sized, payload->key_len);
> > + tpm_buf_append(sized, payload->key, payload->key_len);
> > + tpm_buf_append(buf, sized->data, sized->length);
> >
> > /* public */
> > - tpm_buf_reset_sized(&sized);
> > - tpm_buf_append_u16(&sized, TPM_ALG_KEYEDHASH);
> > - tpm_buf_append_u16(&sized, hash);
> > + tpm_buf_reset_sized(sized, PAGE_SIZE);
> > + tpm_buf_append_u16(sized, TPM_ALG_KEYEDHASH);
> > + tpm_buf_append_u16(sized, hash);
> >
> > /* key properties */
> > flags = 0;
> > flags |= options->policydigest_len ? 0 : TPM2_OA_USER_WITH_AUTH;
> > flags |= payload->migratable ? 0 : (TPM2_OA_FIXED_TPM | TPM2_OA_FIXED_PARENT);
> > - tpm_buf_append_u32(&sized, flags);
> > + tpm_buf_append_u32(sized, flags);
> >
> > /* policy */
> > - tpm_buf_append_u16(&sized, options->policydigest_len);
> > + tpm_buf_append_u16(sized, options->policydigest_len);
> > if (options->policydigest_len)
> > - tpm_buf_append(&sized, options->policydigest, options->policydigest_len);
> > + tpm_buf_append(sized, options->policydigest, options->policydigest_len);
> >
> > /* public parameters */
> > - tpm_buf_append_u16(&sized, TPM_ALG_NULL);
> > - tpm_buf_append_u16(&sized, 0);
> > + tpm_buf_append_u16(sized, TPM_ALG_NULL);
> > + tpm_buf_append_u16(sized, 0);
> >
> > - tpm_buf_append(&buf, sized.data, sized.length);
> > + tpm_buf_append(buf, sized->data, sized->length);
> >
> > /* outside info */
> > - tpm_buf_append_u16(&buf, 0);
> > + tpm_buf_append_u16(buf, 0);
> >
> > /* creation PCR */
> > - tpm_buf_append_u32(&buf, 0);
> > + tpm_buf_append_u32(buf, 0);
> >
> > - if (buf.flags & TPM_BUF_OVERFLOW) {
> > + if (buf->flags & TPM_BUF_OVERFLOW) {
> > rc = -E2BIG;
> > tpm2_end_auth_session(chip);
> > goto out;
> > }
> >
> > - tpm_buf_fill_hmac_session(chip, &buf);
> > - rc = tpm_transmit_cmd(chip, &buf, 4, "sealing data");
> > - rc = tpm_buf_check_hmac_response(chip, &buf, rc);
> > + tpm_buf_fill_hmac_session(chip, buf);
> > + rc = tpm_transmit_cmd(chip, buf, 4, "sealing data");
> > + rc = tpm_buf_check_hmac_response(chip, buf, rc);
> > if (rc)
> > goto out;
> >
> > - blob_len = tpm_buf_read_u32(&buf, &offset);
> > - if (blob_len > MAX_BLOB_SIZE || buf.flags & TPM_BUF_BOUNDARY_ERROR) {
> > + blob_len = tpm_buf_read_u32(buf, &offset);
> > + if (blob_len > MAX_BLOB_SIZE || buf->flags & TPM_BUF_BOUNDARY_ERROR) {
> > rc = -E2BIG;
> > goto out;
> > }
> > - if (buf.length - offset < blob_len) {
> > + if (buf->length - offset < blob_len) {
> > rc = -EFAULT;
> > goto out;
> > }
> >
> > - blob_len = tpm2_key_encode(payload, options, &buf.data[offset], blob_len);
> > + blob_len = tpm2_key_encode(payload, options, &buf->data[offset],
> > + blob_len);
> >
> > out:
> > - tpm_buf_destroy(&sized);
> > - tpm_buf_destroy(&buf);
> > -
> > if (rc > 0) {
> > if (tpm2_rc_value(rc) == TPM2_RC_HASH)
> > rc = -EINVAL;
> > @@ -387,7 +381,6 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
> > struct trusted_key_options *options,
> > u32 *blob_handle)
> > {
> > - struct tpm_buf buf;
> > unsigned int private_len;
> > unsigned int public_len;
> > unsigned int blob_len;
> > @@ -395,6 +388,10 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
> > int rc;
> > u32 attrs;
> >
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> > +
> > rc = tpm2_key_decode(payload, options, &blob);
> > if (rc) {
> > /* old form */
> > @@ -438,35 +435,29 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
> > if (rc)
> > return rc;
> >
> > - rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
> > - if (rc) {
> > - tpm2_end_auth_session(chip);
> > - return rc;
> > - }
> > -
> > - tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);
> > - tpm_buf_append_hmac_session(chip, &buf, 0, options->keyauth,
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
> > + tpm_buf_append_name(chip, buf, options->keyhandle, NULL);
> > + tpm_buf_append_hmac_session(chip, buf, 0, options->keyauth,
> > TPM_DIGEST_SIZE);
> >
> > - tpm_buf_append(&buf, blob, blob_len);
> > + tpm_buf_append(buf, blob, blob_len);
> >
> > - if (buf.flags & TPM_BUF_OVERFLOW) {
> > + if (buf->flags & TPM_BUF_OVERFLOW) {
> > rc = -E2BIG;
> > tpm2_end_auth_session(chip);
> > goto out;
> > }
> >
> > - tpm_buf_fill_hmac_session(chip, &buf);
> > - rc = tpm_transmit_cmd(chip, &buf, 4, "loading blob");
> > - rc = tpm_buf_check_hmac_response(chip, &buf, rc);
> > + tpm_buf_fill_hmac_session(chip, buf);
> > + rc = tpm_transmit_cmd(chip, buf, 4, "loading blob");
> > + rc = tpm_buf_check_hmac_response(chip, buf, rc);
> > if (!rc)
> > *blob_handle = be32_to_cpup(
> > - (__be32 *) &buf.data[TPM_HEADER_SIZE]);
> > + (__be32 *)&buf->data[TPM_HEADER_SIZE]);
> >
> > out:
> > if (blob != payload->blob)
> > kfree(blob);
> > - tpm_buf_destroy(&buf);
> >
> > if (rc > 0)
> > rc = -EPERM;
> > @@ -491,25 +482,23 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
> > struct trusted_key_options *options,
> > u32 blob_handle)
> > {
> > - struct tpm_buf buf;
> > u16 data_len;
> > u8 *data;
> > int rc;
> >
> > + struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> > +
> > rc = tpm2_start_auth_session(chip);
> > if (rc)
> > return rc;
> >
> > - rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
> > - if (rc) {
> > - tpm2_end_auth_session(chip);
> > - return rc;
> > - }
> > -
> > - tpm_buf_append_name(chip, &buf, blob_handle, NULL);
> > + tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
> > + tpm_buf_append_name(chip, buf, blob_handle, NULL);
> >
> > if (!options->policyhandle) {
> > - tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_ENCRYPT,
> > + tpm_buf_append_hmac_session(chip, buf, TPM2_SA_ENCRYPT,
> > options->blobauth,
> > options->blobauth_len);
> > } else {
> > @@ -524,32 +513,28 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
> > * could repeat our actions with the exfiltrated
> > * password.
> > */
> > - tpm2_buf_append_auth(&buf, options->policyhandle,
> > + tpm2_buf_append_auth(buf, options->policyhandle,
> > NULL /* nonce */, 0, 0,
> > options->blobauth, options->blobauth_len);
> > - tpm_buf_append_hmac_session_opt(chip, &buf, TPM2_SA_ENCRYPT,
> > + tpm_buf_append_hmac_session_opt(chip, buf, TPM2_SA_ENCRYPT,
> > NULL, 0);
> > }
> >
> > - tpm_buf_fill_hmac_session(chip, &buf);
> > - rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing");
> > - rc = tpm_buf_check_hmac_response(chip, &buf, rc);
> > + tpm_buf_fill_hmac_session(chip, buf);
> > + rc = tpm_transmit_cmd(chip, buf, 6, "unsealing");
> > + rc = tpm_buf_check_hmac_response(chip, buf, rc);
> > if (rc > 0)
> > rc = -EPERM;
> >
> > if (!rc) {
> > data_len = be16_to_cpup(
> > - (__be16 *) &buf.data[TPM_HEADER_SIZE + 4]);
> > - if (data_len < MIN_KEY_SIZE || data_len > MAX_KEY_SIZE) {
> > - rc = -EFAULT;
> > - goto out;
> > - }
> > + (__be16 *)&buf->data[TPM_HEADER_SIZE + 4]);
> > + if (data_len < MIN_KEY_SIZE || data_len > MAX_KEY_SIZE)
> > + return -EFAULT;
> >
> > - if (tpm_buf_length(&buf) < TPM_HEADER_SIZE + 6 + data_len) {
> > - rc = -EFAULT;
> > - goto out;
> > - }
> > - data = &buf.data[TPM_HEADER_SIZE + 6];
> > + if (tpm_buf_length(buf) < TPM_HEADER_SIZE + 6 + data_len)
> > + return -EFAULT;
> > + data = &buf->data[TPM_HEADER_SIZE + 6];
> >
> > if (payload->old_format) {
> > /* migratable flag is at the end of the key */
> > @@ -566,8 +551,6 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
> > }
> > }
> >
> > -out:
> > - tpm_buf_destroy(&buf);
> > return rc;
> > }
> >
> > --
> > 2.39.5
> >
> >
BR, Jarkko
>
^ permalink raw reply
* Re: [PATCH v2] tpm: use a map for tpm2_calc_ordinal_duration()
From: Serge E. Hallyn @ 2025-09-19 14:47 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: Serge E. Hallyn, linux-integrity, Frédéric Jouen,
Peter Huewe, Jason Gunthorpe, James Bottomley, Mimi Zohar,
David Howells, Paul Moore, James Morris, open list,
open list:KEYS-TRUSTED, open list:SECURITY SUBSYSTEM
In-Reply-To: <aM0A1hceUC-RJdo8@kernel.org>
On Fri, Sep 19, 2025 at 10:05:58AM +0300, Jarkko Sakkinen wrote:
> On Thu, Sep 18, 2025 at 10:49:28PM -0500, Serge E. Hallyn wrote:
> > On Thu, Sep 18, 2025 at 10:30:18PM +0300, Jarkko Sakkinen wrote:
> > > The current shenanigans for duration calculation introduce too much
> > > complexity for a trivial problem, and further the code is hard to patch and
> > > maintain.
> > >
> > > Address these issues with a flat look-up table, which is easy to understand
> > > and patch. If leaf driver specific patching is required in future, it is
> > > easy enough to make a copy of this table during driver initialization and
> > > add the chip parameter back.
> > >
> > > 'chip->duration' is retained for TPM 1.x.
> > >
> > > As the first entry for this new behavior address TCG spec update mentioned
> > > in this issue:
> > >
> > > https://github.com/raspberrypi/linux/issues/7054
> > >
> > > Therefore, for TPM_SelfTest the duration is set to 3000 ms.
D'oh! It *was* in the commit message all along, sorry.
> > > This does not categorize a as bug, given that this is introduced to the
> > > spec after the feature was originally made.
> > >
> > > Cc: Frédéric Jouen <fjouen@sealsq.com>
> > > Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
Looks good, thank you.
Reviewed-by: Serge Hallyn <serge@hallyn.com>
> > fwiw (which shouldn't be much) looks good to me, but two questions,
> > one here and one below.
> >
> > First, it looks like in the existing code it is possible for a tpm2
> > chip to set its own timeouts and then set the TPM_CHIP_FLAG_HAVE_TIMEOUTS
> > flag to avoid using the defaults, but I don't see anything using that
> > in-tree. Is it possible that there are out of tree drivers that will be
> > sabotaged here? Or am I misunderstanding that completely?
>
> Good questions, and I can brief a bit about the context of the
> pre-existing art and this change.
>
> This complexity was formed in 2014 when I originally developed TPM2
> support and the only available testing plaform was early Intel PTT with
> a flakky version of TPM2 support (e.g., no localities).
>
> Since then we haven't had per leaf-driver divergence.
>
> Further, I think that this type of layout is actually a better fit if
> we ever need to quirks for command durations for a particular device, as
> then we can migrate to "copy and patch" semantics i.e., have a copy of
> this map in the chip structure.
>
> As per out-of-tree drivers, it's unfortunate reality of out-of-tree
> drivers :-) However, this will definitely add some extra work, when
> backporting fixes (not overwhelmingly much).
>
> BR, Jarkko
^ permalink raw reply
* Re: [PATCH v3 00/35] Compiler-Based Capability- and Locking-Analysis
From: Christoph Hellwig @ 2025-09-19 14:09 UTC (permalink / raw)
To: Nathan Chancellor
Cc: Christoph Hellwig, Marco Elver, Peter Zijlstra, Boqun Feng,
Ingo Molnar, Will Deacon, David S. Miller, Luc Van Oostenryck,
Paul E. McKenney, Alexander Potapenko, Arnd Bergmann,
Bart Van Assche, Bill Wendling, Dmitry Vyukov, Eric Dumazet,
Frederic Weisbecker, Greg Kroah-Hartman, Herbert Xu, Ian Rogers,
Jann Horn, Joel Fernandes, Jonathan Corbet, Josh Triplett,
Justin Stitt, Kees Cook, Kentaro Takeda, Lukas Bulwahn,
Mark Rutland, Mathieu Desnoyers, Miguel Ojeda, Neeraj Upadhyay,
Nick Desaulniers, Steven Rostedt, Tetsuo Handa, Thomas Gleixner,
Thomas Graf, Uladzislau Rezki, Waiman Long, kasan-dev,
linux-crypto, linux-doc, linux-kbuild, linux-kernel, linux-mm,
linux-security-module, linux-sparse, llvm, rcu
In-Reply-To: <20250919140803.GA23745@lst.de>
On Fri, Sep 19, 2025 at 04:08:03PM +0200, Christoph Hellwig wrote:
> I started to play around with that. For the nvme code adding the
> annotations was very simply, and I also started adding trivial
> __guarded_by which instantly found issues.
>
> For XFS it was a lot more work and I still see tons of compiler
> warnings, which I'm not entirely sure how to address. Right now I
> see three major classes:
And in case anyone cares, here are my patches for that:
https://git.infradead.org/?p=users/hch/misc.git;a=shortlog;h=refs/heads/cap-analysis
git://git.infradead.org/users/hch/misc.git cap-analysis
^ permalink raw reply
* Re: [PATCH v3 00/35] Compiler-Based Capability- and Locking-Analysis
From: Christoph Hellwig @ 2025-09-19 14:08 UTC (permalink / raw)
To: Nathan Chancellor
Cc: Christoph Hellwig, Marco Elver, Peter Zijlstra, Boqun Feng,
Ingo Molnar, Will Deacon, David S. Miller, Luc Van Oostenryck,
Paul E. McKenney, Alexander Potapenko, Arnd Bergmann,
Bart Van Assche, Bill Wendling, Dmitry Vyukov, Eric Dumazet,
Frederic Weisbecker, Greg Kroah-Hartman, Herbert Xu, Ian Rogers,
Jann Horn, Joel Fernandes, Jonathan Corbet, Josh Triplett,
Justin Stitt, Kees Cook, Kentaro Takeda, Lukas Bulwahn,
Mark Rutland, Mathieu Desnoyers, Miguel Ojeda, Neeraj Upadhyay,
Nick Desaulniers, Steven Rostedt, Tetsuo Handa, Thomas Gleixner,
Thomas Graf, Uladzislau Rezki, Waiman Long, kasan-dev,
linux-crypto, linux-doc, linux-kbuild, linux-kernel, linux-mm,
linux-security-module, linux-sparse, llvm, rcu
In-Reply-To: <20250918174555.GA3366400@ax162>
On Thu, Sep 18, 2025 at 10:45:55AM -0700, Nathan Chancellor wrote:
> On Thu, Sep 18, 2025 at 04:15:11PM +0200, Christoph Hellwig wrote:
> > On Thu, Sep 18, 2025 at 03:59:11PM +0200, Marco Elver wrote:
> > > A Clang version that supports `-Wthread-safety-pointer` and the new
> > > alias-analysis of capability pointers is required (from this version
> > > onwards):
> > >
> > > https://github.com/llvm/llvm-project/commit/b4c98fcbe1504841203e610c351a3227f36c92a4 [3]
> >
> > There's no chance to make say x86 pre-built binaries for that available?
>
> I can use my existing kernel.org LLVM [1] build infrastructure to
> generate prebuilt x86 binaries. Just give me a bit to build and upload
> them. You may not be the only developer or maintainer who may want to
> play with this.
That did work, thanks.
I started to play around with that. For the nvme code adding the
annotations was very simply, and I also started adding trivial
__guarded_by which instantly found issues.
For XFS it was a lot more work and I still see tons of compiler
warnings, which I'm not entirely sure how to address. Right now I
see three major classes:
1) locks held over loop iterations like:
fs/xfs/xfs_extent_busy.c:573:26: warning: expecting spinlock 'xfs_group_hold(busyp->group)..xg_busy_extents->eb_lock' to be held at start of each loop [-Wthread-safety-analysis]
573 | struct xfs_group *xg = xfs_group_hold(busyp->group);
| ^
fs/xfs/xfs_extent_busy.c:577:3: note: spinlock acquired here
577 | spin_lock(&eb->eb_lock);
| ^
This is perfectly find code and needs some annotations, but I can't find
any good example.
2) Locks on returned objects, which can be NULL. I.e., something
like crossover of __acquire_ret and __cond_acquires
3) Wrappers that take multiple locks conditionally
We have helpers that take different locks in the same object based on the
arguments like xfs_ilock() or those that take the same lock and a variable
number of objects like xfs_dqlockn based on input and sorting. The
first are just historic and we might want to kill them, but the
sorting of objects to acquire locks in order thing is a pattern in
various places including the VFS, so we'll need some way to annotate it.
^ permalink raw reply
* Re: [PATCH v7] tpm: Make TPM buffer allocations more robust
From: Stefano Garzarella @ 2025-09-19 13:35 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: linux-integrity, Stefan Berger, Jarkko Sakkinen, Peter Huewe,
Jason Gunthorpe, James Bottomley, Mimi Zohar, David Howells,
Paul Moore, James Morris, Serge E. Hallyn, open list,
open list:KEYS-TRUSTED, open list:SECURITY SUBSYSTEM
In-Reply-To: <20250919112448.2543343-1-jarkko@kernel.org>
On Fri, Sep 19, 2025 at 02:24:47PM +0300, Jarkko Sakkinen wrote:
>From: Jarkko Sakkinen <jarkko.sakkinen@opinsys.com>
>
>Drop 'tpm_buf_init', 'tpm_buf_init_sized' and 'tpm_buf_free'. Refine
>'struct tpm_buf' to hold capacity in order to enable stack allocation and
>sizes other than page size.
>
>The updated 'struct tpm_buf' can be allocated either from stack or heap.
>
>The contract is the following:
>
>1. 'tpm_buf_reset' and 'tpm_buf_reset_size' expect that on the first run
> the passed buffer is zeroed by the caller (e.g. via memset or kzalloc).
>2. The same buffer can be reused. On the second and subsequent resets the
> aforementioned functions verify that 'buf_size' has the same value, and
> emits warning if not.
>
>As a consequence 'struct tpm_buf' instance can be easily wrapped into
>managed allocation:
>
> struct tpm_buf *buf __free(kfree) buf = kzalloc(PAGE_SIZE,
> GFP_KERNEL);
>
>Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
>Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@opinsys.com>
>---
>v7:
>- Additional function comments and invariant was unfortunately left to
> my staging area so here's the addition (does not affect functionality).
>v6:
>- Removed two empty lines as requested by Stefan:
> https://lore.kernel.org/linux-integrity/be1c5bef-7c97-4173-b417-986dc90d779c@linux.ibm.com/
>- Add 'capacity' field as this makes easy to stretch tpm_buf into stack
> allocation.
>v5:
>- I tested this version also with TPM 1.2 by booting up and checking
> that sysfs attributes work.
>- Fixed the length check against capacity (James) with TPM_BUF_CAPACITY.
>- Fixed declaration style: do it at the site (Jason).
>- Improved commit message (Stefan).
>- Removed "out" label from tpm2_pcr_read() (Stefan).
>- Removed spurious "return rc;" from tpm2_get_pcr_allocation() (Stefan).
>v4:
>- Wrote a more a descriptive short summary and improved description.
>- Fixed the error in documentation: there is 4090 bytes of space left
> for the payload - not 4088 bytes.
>- Turned tpm_buf_alloc() into inline function.
>v3:
>- Removed the cleanup class and moved on using __free(kfree) instead.
>- Removed `buf_size` (James).
>- I'm open for the idea of splitting still (Jason) but I'll hold
> at least this revision just to check that my core idea here
> is correct.
>v2:
>- Implement also memory allocation using the cleanup class.
>- Rewrote the commit message.
>- Implemented CLASS_TPM_BUF() helper macro.
>---
> drivers/char/tpm/tpm-buf.c | 68 ++----
> drivers/char/tpm/tpm-sysfs.c | 19 +-
> drivers/char/tpm/tpm1-cmd.c | 143 ++++++------
> drivers/char/tpm/tpm2-cmd.c | 270 ++++++++++------------
> drivers/char/tpm/tpm2-sessions.c | 118 +++++-----
> drivers/char/tpm/tpm2-space.c | 42 ++--
> drivers/char/tpm/tpm_vtpm_proxy.c | 29 +--
> include/linux/tpm.h | 17 +-
> security/keys/trusted-keys/trusted_tpm1.c | 40 ++--
> security/keys/trusted-keys/trusted_tpm2.c | 153 ++++++------
> 10 files changed, 390 insertions(+), 509 deletions(-)
>
>diff --git a/drivers/char/tpm/tpm-buf.c b/drivers/char/tpm/tpm-buf.c
>index dc882fc9fa9e..19774bc5786f 100644
>--- a/drivers/char/tpm/tpm-buf.c
>+++ b/drivers/char/tpm/tpm-buf.c
>@@ -7,83 +7,57 @@
> #include <linux/module.h>
> #include <linux/tpm.h>
>
>-/**
>- * tpm_buf_init() - Allocate and initialize a TPM command
>- * @buf: A &tpm_buf
>- * @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS
>- * @ordinal: A command ordinal
>- *
>- * Return: 0 or -ENOMEM
>- */
>-int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
>-{
>- buf->data = (u8 *)__get_free_page(GFP_KERNEL);
>- if (!buf->data)
>- return -ENOMEM;
>-
>- tpm_buf_reset(buf, tag, ordinal);
>- return 0;
>-}
>-EXPORT_SYMBOL_GPL(tpm_buf_init);
>-
> /**
> * tpm_buf_reset() - Initialize a TPM command
> * @buf: A &tpm_buf
>+ * @buf_size: Size of the buffer.
> * @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS
> * @ordinal: A command ordinal
>+ *
>+ * 1. Expects that on the first run the passed buffer is zeroed by the caller.
>+ * 2. Old buffer can be reused. On the second and subsequent resets @buf_size is
>+ * verified to be equal to the previous value.
> */
>-void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
>+void tpm_buf_reset(struct tpm_buf *buf, u16 buf_size, u16 tag, u32 ordinal)
> {
> struct tpm_header *head = (struct tpm_header *)buf->data;
>
>+ WARN_ON(buf->capacity != 0 && buf_size != (buf->capacity + sizeof(*buf)));
> WARN_ON(tag != TPM_TAG_RQU_COMMAND && tag != TPM2_ST_NO_SESSIONS &&
> tag != TPM2_ST_SESSIONS && tag != 0);
>
> buf->flags = 0;
> buf->length = sizeof(*head);
>+ buf->capacity = buf_size - sizeof(*buf);
>+ buf->handles = 0;
> head->tag = cpu_to_be16(tag);
> head->length = cpu_to_be32(sizeof(*head));
> head->ordinal = cpu_to_be32(ordinal);
>- buf->handles = 0;
> }
> EXPORT_SYMBOL_GPL(tpm_buf_reset);
>
>-/**
>- * tpm_buf_init_sized() - Allocate and initialize a sized (TPM2B) buffer
>- * @buf: A @tpm_buf
>- *
>- * Return: 0 or -ENOMEM
>- */
>-int tpm_buf_init_sized(struct tpm_buf *buf)
>-{
>- buf->data = (u8 *)__get_free_page(GFP_KERNEL);
>- if (!buf->data)
>- return -ENOMEM;
>-
>- tpm_buf_reset_sized(buf);
>- return 0;
>-}
>-EXPORT_SYMBOL_GPL(tpm_buf_init_sized);
>-
> /**
> * tpm_buf_reset_sized() - Initialize a sized buffer
> * @buf: A &tpm_buf
>+ * @buf_size: Size of the buffer.
>+ *
>+ * 1. Expects that on the first run the passed buffer is zeroed by the caller.
>+ * 2. Old buffer can be reused. On the second and subsequent resets @buf_size is
>+ * verified to be equal to the previous value.
> */
>-void tpm_buf_reset_sized(struct tpm_buf *buf)
>+void tpm_buf_reset_sized(struct tpm_buf *buf, u16 buf_size)
> {
>+ WARN_ON(buf->capacity != 0 && buf_size != (buf->capacity + sizeof(*buf)));
>+
> buf->flags = TPM_BUF_TPM2B;
> buf->length = 2;
>+ buf->capacity = buf_size - sizeof(*buf);
>+ buf->handles = 0;
> buf->data[0] = 0;
> buf->data[1] = 0;
> }
> EXPORT_SYMBOL_GPL(tpm_buf_reset_sized);
>
>-void tpm_buf_destroy(struct tpm_buf *buf)
>-{
>- free_page((unsigned long)buf->data);
>-}
>-EXPORT_SYMBOL_GPL(tpm_buf_destroy);
>-
> /**
> * tpm_buf_length() - Return the number of bytes consumed by the data
> * @buf: A &tpm_buf
*
* Return: The number of bytes consumed by the buffer
*/
u32 tpm_buf_length(struct tpm_buf *buf)
{
return buf->length;
}
EXPORT_SYMBOL_GPL(tpm_buf_length);
Should we update the return type (u16) on this function?
>@@ -108,7 +82,7 @@ void tpm_buf_append(struct tpm_buf *buf, const u8 *new_data, u16 new_length)
> if (buf->flags & TPM_BUF_OVERFLOW)
> return;
>
>- if ((buf->length + new_length) > PAGE_SIZE) {
>+ if ((buf->length + new_length) > buf->capacity) {
IIUC all of these are u16, so there could be an overflow when we do
`buf->length + new_length` ?
Should we cast to u32 or just change the expression in something like
`new_length > (buf->capacity - buf->length)`
Thanks,
Stefano
> WARN(1, "tpm_buf: write overflow\n");
> buf->flags |= TPM_BUF_OVERFLOW;
> return;
>@@ -242,5 +216,3 @@ u32 tpm_buf_read_u32(struct tpm_buf *buf, off_t *offset)
> return be32_to_cpu(value);
> }
> EXPORT_SYMBOL_GPL(tpm_buf_read_u32);
>-
>-
>diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
>index 94231f052ea7..68328ca6367d 100644
>--- a/drivers/char/tpm/tpm-sysfs.c
>+++ b/drivers/char/tpm/tpm-sysfs.c
>@@ -32,28 +32,29 @@ struct tpm_readpubek_out {
> static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
> char *buf)
> {
>- struct tpm_buf tpm_buf;
> struct tpm_readpubek_out *out;
> int i;
> char *str = buf;
> struct tpm_chip *chip = to_tpm_chip(dev);
> char anti_replay[20];
>
>+ struct tpm_buf *tpm_buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!tpm_buf)
>+ return -ENOMEM;
>+
> memset(&anti_replay, 0, sizeof(anti_replay));
>
> if (tpm_try_get_ops(chip))
> return 0;
>
>- if (tpm_buf_init(&tpm_buf, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK))
>- goto out_ops;
>-
>- tpm_buf_append(&tpm_buf, anti_replay, sizeof(anti_replay));
>+ tpm_buf_reset(tpm_buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK);
>+ tpm_buf_append(tpm_buf, anti_replay, sizeof(anti_replay));
>
>- if (tpm_transmit_cmd(chip, &tpm_buf, READ_PUBEK_RESULT_MIN_BODY_SIZE,
>+ if (tpm_transmit_cmd(chip, tpm_buf, READ_PUBEK_RESULT_MIN_BODY_SIZE,
> "attempting to read the PUBEK"))
>- goto out_buf;
>+ goto out_ops;
>
>- out = (struct tpm_readpubek_out *)&tpm_buf.data[10];
>+ out = (struct tpm_readpubek_out *)&tpm_buf->data[10];
> str +=
> sprintf(str,
> "Algorithm: %4ph\n"
>@@ -71,8 +72,6 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
> for (i = 0; i < 256; i += 16)
> str += sprintf(str, "%16ph\n", &out->modulus[i]);
>
>-out_buf:
>- tpm_buf_destroy(&tpm_buf);
> out_ops:
> tpm_put_ops(chip);
> return str - buf;
>diff --git a/drivers/char/tpm/tpm1-cmd.c b/drivers/char/tpm/tpm1-cmd.c
>index cf64c7385105..e7dc01c68a92 100644
>--- a/drivers/char/tpm/tpm1-cmd.c
>+++ b/drivers/char/tpm/tpm1-cmd.c
>@@ -323,19 +323,18 @@ unsigned long tpm1_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
> */
> static int tpm1_startup(struct tpm_chip *chip)
> {
>- struct tpm_buf buf;
> int rc;
>
>- dev_info(&chip->dev, "starting up the TPM manually\n");
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>
>- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_STARTUP);
>- if (rc < 0)
>- return rc;
>+ dev_info(&chip->dev, "starting up the TPM manually\n");
>
>- tpm_buf_append_u16(&buf, TPM_ST_CLEAR);
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_STARTUP);
>+ tpm_buf_append_u16(buf, TPM_ST_CLEAR);
>
>- rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM");
>- tpm_buf_destroy(&buf);
>+ rc = tpm_transmit_cmd(chip, buf, 0, "attempting to start the TPM");
> return rc;
> }
>
>@@ -463,18 +462,17 @@ int tpm1_get_timeouts(struct tpm_chip *chip)
> int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash,
> const char *log_msg)
> {
>- struct tpm_buf buf;
> int rc;
>
>- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_EXTEND);
>- if (rc)
>- return rc;
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>
>- tpm_buf_append_u32(&buf, pcr_idx);
>- tpm_buf_append(&buf, hash, TPM_DIGEST_SIZE);
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_EXTEND);
>+ tpm_buf_append_u32(buf, pcr_idx);
>+ tpm_buf_append(buf, hash, TPM_DIGEST_SIZE);
>
>- rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE, log_msg);
>- tpm_buf_destroy(&buf);
>+ rc = tpm_transmit_cmd(chip, buf, TPM_DIGEST_SIZE, log_msg);
> return rc;
> }
>
>@@ -482,31 +480,31 @@ int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash,
> ssize_t tpm1_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
> const char *desc, size_t min_cap_length)
> {
>- struct tpm_buf buf;
> int rc;
>
>- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_CAP);
>- if (rc)
>- return rc;
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_CAP);
>
> if (subcap_id == TPM_CAP_VERSION_1_1 ||
> subcap_id == TPM_CAP_VERSION_1_2) {
>- tpm_buf_append_u32(&buf, subcap_id);
>- tpm_buf_append_u32(&buf, 0);
>+ tpm_buf_append_u32(buf, subcap_id);
>+ tpm_buf_append_u32(buf, 0);
> } else {
> if (subcap_id == TPM_CAP_FLAG_PERM ||
> subcap_id == TPM_CAP_FLAG_VOL)
>- tpm_buf_append_u32(&buf, TPM_CAP_FLAG);
>+ tpm_buf_append_u32(buf, TPM_CAP_FLAG);
> else
>- tpm_buf_append_u32(&buf, TPM_CAP_PROP);
>+ tpm_buf_append_u32(buf, TPM_CAP_PROP);
>
>- tpm_buf_append_u32(&buf, 4);
>- tpm_buf_append_u32(&buf, subcap_id);
>+ tpm_buf_append_u32(buf, 4);
>+ tpm_buf_append_u32(buf, subcap_id);
> }
>- rc = tpm_transmit_cmd(chip, &buf, min_cap_length, desc);
>+ rc = tpm_transmit_cmd(chip, buf, min_cap_length, desc);
> if (!rc)
>- *cap = *(cap_t *)&buf.data[TPM_HEADER_SIZE + 4];
>- tpm_buf_destroy(&buf);
>+ *cap = *(cap_t *)&buf->data[TPM_HEADER_SIZE + 4];
> return rc;
> }
> EXPORT_SYMBOL_GPL(tpm1_getcap);
>@@ -531,81 +529,72 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
> {
> struct tpm1_get_random_out *out;
> u32 num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA);
>- struct tpm_buf buf;
> u32 total = 0;
> int retries = 5;
> u32 recd;
> int rc;
>
>- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
>- if (rc)
>- return rc;
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
>
> do {
>- tpm_buf_append_u32(&buf, num_bytes);
>+ tpm_buf_append_u32(buf, num_bytes);
>
>- rc = tpm_transmit_cmd(chip, &buf, sizeof(out->rng_data_len),
>+ rc = tpm_transmit_cmd(chip, buf, sizeof(out->rng_data_len),
> "attempting get random");
> if (rc) {
> if (rc > 0)
> rc = -EIO;
>- goto out;
>+ return rc;
> }
>
>- out = (struct tpm1_get_random_out *)&buf.data[TPM_HEADER_SIZE];
>+ out = (struct tpm1_get_random_out *)&buf->data[TPM_HEADER_SIZE];
>
> recd = be32_to_cpu(out->rng_data_len);
>- if (recd > num_bytes) {
>- rc = -EFAULT;
>- goto out;
>- }
>+ if (recd > num_bytes)
>+ return -EFAULT;
>+
>+ if (buf->length < TPM_HEADER_SIZE +
>+ sizeof(out->rng_data_len) + recd)
>+ return -EFAULT;
>
>- if (tpm_buf_length(&buf) < TPM_HEADER_SIZE +
>- sizeof(out->rng_data_len) + recd) {
>- rc = -EFAULT;
>- goto out;
>- }
> memcpy(dest, out->rng_data, recd);
>
> dest += recd;
> total += recd;
> num_bytes -= recd;
>
>- tpm_buf_reset(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
> } while (retries-- && total < max);
>
> rc = total ? (int)total : -EIO;
>-out:
>- tpm_buf_destroy(&buf);
> return rc;
> }
>
> #define TPM_ORD_PCRREAD 21
> int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
> {
>- struct tpm_buf buf;
> int rc;
>
>- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCRREAD);
>- if (rc)
>- return rc;
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>
>- tpm_buf_append_u32(&buf, pcr_idx);
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_PCRREAD);
>+ tpm_buf_append_u32(buf, pcr_idx);
>
>- rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE,
>+ rc = tpm_transmit_cmd(chip, buf, TPM_DIGEST_SIZE,
> "attempting to read a pcr value");
> if (rc)
>- goto out;
>-
>- if (tpm_buf_length(&buf) < TPM_DIGEST_SIZE) {
>- rc = -EFAULT;
>- goto out;
>- }
>+ return rc;
>
>- memcpy(res_buf, &buf.data[TPM_HEADER_SIZE], TPM_DIGEST_SIZE);
>+ if (buf->length < TPM_DIGEST_SIZE)
>+ return -EFAULT;
>
>-out:
>- tpm_buf_destroy(&buf);
>+ memcpy(res_buf, &buf->data[TPM_HEADER_SIZE], TPM_DIGEST_SIZE);
> return rc;
> }
>
>@@ -619,15 +608,14 @@ int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
> */
> static int tpm1_continue_selftest(struct tpm_chip *chip)
> {
>- struct tpm_buf buf;
> int rc;
>
>- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_CONTINUE_SELFTEST);
>- if (rc)
>- return rc;
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>
>- rc = tpm_transmit_cmd(chip, &buf, 0, "continue selftest");
>- tpm_buf_destroy(&buf);
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_CONTINUE_SELFTEST);
>+ rc = tpm_transmit_cmd(chip, buf, 0, "continue selftest");
> return rc;
> }
>
>@@ -742,22 +730,23 @@ int tpm1_auto_startup(struct tpm_chip *chip)
> int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
> {
> u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 };
>- struct tpm_buf buf;
> unsigned int try;
> int rc;
>
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>
> /* for buggy tpm, flush pcrs with extend to selected dummy */
> if (tpm_suspend_pcr)
> rc = tpm1_pcr_extend(chip, tpm_suspend_pcr, dummy_hash,
> "extending dummy pcr before suspend");
>
>- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
>- if (rc)
>- return rc;
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
>+
> /* now do the actual savestate */
> for (try = 0; try < TPM_RETRY; try++) {
>- rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
>+ rc = tpm_transmit_cmd(chip, buf, 0, NULL);
> /*
> * If the TPM indicates that it is too busy to respond to
> * this command then retry before giving up. It can take
>@@ -772,7 +761,7 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
> break;
> tpm_msleep(TPM_TIMEOUT_RETRY);
>
>- tpm_buf_reset(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
> }
>
> if (rc)
>@@ -782,8 +771,6 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
> dev_warn(&chip->dev, "TPM savestate took %dms\n",
> try * TPM_TIMEOUT_RETRY);
>
>- tpm_buf_destroy(&buf);
>-
> return rc;
> }
>
>diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
>index 524d802ede26..56d8bc496cd6 100644
>--- a/drivers/char/tpm/tpm2-cmd.c
>+++ b/drivers/char/tpm/tpm2-cmd.c
>@@ -167,12 +167,15 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
> {
> int i;
> int rc;
>- struct tpm_buf buf;
> struct tpm2_pcr_read_out *out;
> u8 pcr_select[TPM2_PCR_SELECT_MIN] = {0};
> u16 digest_size;
> u16 expected_digest_size = 0;
>
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>+
> if (pcr_idx >= TPM2_PLATFORM_PCR)
> return -EINVAL;
>
>@@ -187,36 +190,30 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
> expected_digest_size = chip->allocated_banks[i].digest_size;
> }
>
>- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ);
>- if (rc)
>- return rc;
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ);
>
> pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
>
>- tpm_buf_append_u32(&buf, 1);
>- tpm_buf_append_u16(&buf, digest->alg_id);
>- tpm_buf_append_u8(&buf, TPM2_PCR_SELECT_MIN);
>- tpm_buf_append(&buf, (const unsigned char *)pcr_select,
>+ tpm_buf_append_u32(buf, 1);
>+ tpm_buf_append_u16(buf, digest->alg_id);
>+ tpm_buf_append_u8(buf, TPM2_PCR_SELECT_MIN);
>+ tpm_buf_append(buf, (const unsigned char *)pcr_select,
> sizeof(pcr_select));
>
>- rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to read a pcr value");
>+ rc = tpm_transmit_cmd(chip, buf, 0, "attempting to read a pcr value");
> if (rc)
>- goto out;
>+ return rc;
>
>- out = (struct tpm2_pcr_read_out *)&buf.data[TPM_HEADER_SIZE];
>+ out = (struct tpm2_pcr_read_out *)&buf->data[TPM_HEADER_SIZE];
> digest_size = be16_to_cpu(out->digest_size);
> if (digest_size > sizeof(digest->digest) ||
>- (!digest_size_ptr && digest_size != expected_digest_size)) {
>- rc = -EINVAL;
>- goto out;
>- }
>+ (!digest_size_ptr && digest_size != expected_digest_size))
>+ return rc;
>
> if (digest_size_ptr)
> *digest_size_ptr = digest_size;
>
> memcpy(digest->digest, out->digest, digest_size);
>-out:
>- tpm_buf_destroy(&buf);
> return rc;
> }
>
>@@ -232,46 +229,42 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
> int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
> struct tpm_digest *digests)
> {
>- struct tpm_buf buf;
> int rc;
> int i;
>
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>+
> if (!disable_pcr_integrity) {
> rc = tpm2_start_auth_session(chip);
> if (rc)
> return rc;
> }
>
>- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
>- if (rc) {
>- if (!disable_pcr_integrity)
>- tpm2_end_auth_session(chip);
>- return rc;
>- }
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
>
> if (!disable_pcr_integrity) {
>- tpm_buf_append_name(chip, &buf, pcr_idx, NULL);
>- tpm_buf_append_hmac_session(chip, &buf, 0, NULL, 0);
>+ tpm_buf_append_name(chip, buf, pcr_idx, NULL);
>+ tpm_buf_append_hmac_session(chip, buf, 0, NULL, 0);
> } else {
>- tpm_buf_append_handle(chip, &buf, pcr_idx);
>- tpm_buf_append_auth(chip, &buf, 0, NULL, 0);
>+ tpm_buf_append_handle(chip, buf, pcr_idx);
>+ tpm_buf_append_auth(chip, buf, 0, NULL, 0);
> }
>
>- tpm_buf_append_u32(&buf, chip->nr_allocated_banks);
>+ tpm_buf_append_u32(buf, chip->nr_allocated_banks);
>
> for (i = 0; i < chip->nr_allocated_banks; i++) {
>- tpm_buf_append_u16(&buf, digests[i].alg_id);
>- tpm_buf_append(&buf, (const unsigned char *)&digests[i].digest,
>+ tpm_buf_append_u16(buf, digests[i].alg_id);
>+ tpm_buf_append(buf, (const unsigned char *)&digests[i].digest,
> chip->allocated_banks[i].digest_size);
> }
>
> if (!disable_pcr_integrity)
>- tpm_buf_fill_hmac_session(chip, &buf);
>- rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value");
>+ tpm_buf_fill_hmac_session(chip, buf);
>+ rc = tpm_transmit_cmd(chip, buf, 0, "attempting extend a PCR value");
> if (!disable_pcr_integrity)
>- rc = tpm_buf_check_hmac_response(chip, &buf, rc);
>-
>- tpm_buf_destroy(&buf);
>+ rc = tpm_buf_check_hmac_response(chip, buf, rc);
>
> return rc;
> }
>@@ -296,7 +289,6 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
> {
> struct tpm2_get_random_out *out;
> struct tpm_header *head;
>- struct tpm_buf buf;
> u32 recd;
> u32 num_bytes = max;
> int err;
>@@ -308,43 +300,41 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
> if (!num_bytes || max > TPM_MAX_RNG_DATA)
> return -EINVAL;
>
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>+
> err = tpm2_start_auth_session(chip);
> if (err)
> return err;
>
>- err = tpm_buf_init(&buf, 0, 0);
>- if (err) {
>- tpm2_end_auth_session(chip);
>- return err;
>- }
>-
> do {
>- tpm_buf_reset(&buf, TPM2_ST_SESSIONS, TPM2_CC_GET_RANDOM);
>- tpm_buf_append_hmac_session_opt(chip, &buf, TPM2_SA_ENCRYPT
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_GET_RANDOM);
>+ tpm_buf_append_hmac_session_opt(chip, buf, TPM2_SA_ENCRYPT
> | TPM2_SA_CONTINUE_SESSION,
> NULL, 0);
>- tpm_buf_append_u16(&buf, num_bytes);
>- tpm_buf_fill_hmac_session(chip, &buf);
>- err = tpm_transmit_cmd(chip, &buf,
>+ tpm_buf_append_u16(buf, num_bytes);
>+ tpm_buf_fill_hmac_session(chip, buf);
>+ err = tpm_transmit_cmd(chip, buf,
> offsetof(struct tpm2_get_random_out,
> buffer),
> "attempting get random");
>- err = tpm_buf_check_hmac_response(chip, &buf, err);
>+ err = tpm_buf_check_hmac_response(chip, buf, err);
> if (err) {
> if (err > 0)
> err = -EIO;
> goto out;
> }
>
>- head = (struct tpm_header *)buf.data;
>+ head = (struct tpm_header *)buf->data;
> offset = TPM_HEADER_SIZE;
> /* Skip the parameter size field: */
> if (be16_to_cpu(head->tag) == TPM2_ST_SESSIONS)
> offset += 4;
>
>- out = (struct tpm2_get_random_out *)&buf.data[offset];
>+ out = (struct tpm2_get_random_out *)&buf->data[offset];
> recd = min_t(u32, be16_to_cpu(out->size), num_bytes);
>- if (tpm_buf_length(&buf) <
>+ if (tpm_buf_length(buf) <
> TPM_HEADER_SIZE +
> offsetof(struct tpm2_get_random_out, buffer) +
> recd) {
>@@ -358,11 +348,9 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
> num_bytes -= recd;
> } while (retries-- && total < max);
>
>- tpm_buf_destroy(&buf);
>-
> return total ? total : -EIO;
>+
> out:
>- tpm_buf_destroy(&buf);
> tpm2_end_auth_session(chip);
> return err;
> }
>@@ -374,20 +362,17 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
> */
> void tpm2_flush_context(struct tpm_chip *chip, u32 handle)
> {
>- struct tpm_buf buf;
>- int rc;
>-
>- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
>- if (rc) {
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf) {
> dev_warn(&chip->dev, "0x%08x was not flushed, out of memory\n",
> handle);
> return;
> }
>
>- tpm_buf_append_u32(&buf, handle);
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
>+ tpm_buf_append_u32(buf, handle);
>
>- tpm_transmit_cmd(chip, &buf, 0, "flushing context");
>- tpm_buf_destroy(&buf);
>+ tpm_transmit_cmd(chip, buf, 0, "flushing context");
> }
> EXPORT_SYMBOL_GPL(tpm2_flush_context);
>
>@@ -414,19 +399,20 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
> const char *desc)
> {
> struct tpm2_get_cap_out *out;
>- struct tpm_buf buf;
> int rc;
>
>- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
>- if (rc)
>- return rc;
>- tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
>- tpm_buf_append_u32(&buf, property_id);
>- tpm_buf_append_u32(&buf, 1);
>- rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
>+ tpm_buf_append_u32(buf, TPM2_CAP_TPM_PROPERTIES);
>+ tpm_buf_append_u32(buf, property_id);
>+ tpm_buf_append_u32(buf, 1);
>+ rc = tpm_transmit_cmd(chip, buf, 0, NULL);
> if (!rc) {
> out = (struct tpm2_get_cap_out *)
>- &buf.data[TPM_HEADER_SIZE];
>+ &buf->data[TPM_HEADER_SIZE];
> /*
> * To prevent failing boot up of some systems, Infineon TPM2.0
> * returns SUCCESS on TPM2_Startup in field upgrade mode. Also
>@@ -438,7 +424,6 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
> else
> rc = -ENODATA;
> }
>- tpm_buf_destroy(&buf);
> return rc;
> }
> EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);
>@@ -455,15 +440,13 @@ EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);
> */
> void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
> {
>- struct tpm_buf buf;
>- int rc;
>-
>- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SHUTDOWN);
>- if (rc)
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
> return;
>- tpm_buf_append_u16(&buf, shutdown_type);
>- tpm_transmit_cmd(chip, &buf, 0, "stopping the TPM");
>- tpm_buf_destroy(&buf);
>+
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_SHUTDOWN);
>+ tpm_buf_append_u16(buf, shutdown_type);
>+ tpm_transmit_cmd(chip, buf, 0, "stopping the TPM");
> }
>
> /**
>@@ -481,19 +464,18 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
> */
> static int tpm2_do_selftest(struct tpm_chip *chip)
> {
>- struct tpm_buf buf;
> int full;
> int rc;
>
>- for (full = 0; full < 2; full++) {
>- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SELF_TEST);
>- if (rc)
>- return rc;
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>
>- tpm_buf_append_u8(&buf, full);
>- rc = tpm_transmit_cmd(chip, &buf, 0,
>+ for (full = 0; full < 2; full++) {
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_SELF_TEST);
>+ tpm_buf_append_u8(buf, full);
>+ rc = tpm_transmit_cmd(chip, buf, 0,
> "attempting the self test");
>- tpm_buf_destroy(&buf);
>
> if (rc == TPM2_RC_TESTING)
> rc = TPM2_RC_SUCCESS;
>@@ -519,23 +501,23 @@ static int tpm2_do_selftest(struct tpm_chip *chip)
> int tpm2_probe(struct tpm_chip *chip)
> {
> struct tpm_header *out;
>- struct tpm_buf buf;
> int rc;
>
>- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
>- if (rc)
>- return rc;
>- tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
>- tpm_buf_append_u32(&buf, TPM_PT_TOTAL_COMMANDS);
>- tpm_buf_append_u32(&buf, 1);
>- rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
>+ tpm_buf_append_u32(buf, TPM2_CAP_TPM_PROPERTIES);
>+ tpm_buf_append_u32(buf, TPM_PT_TOTAL_COMMANDS);
>+ tpm_buf_append_u32(buf, 1);
>+ rc = tpm_transmit_cmd(chip, buf, 0, NULL);
> /* We ignore TPM return codes on purpose. */
> if (rc >= 0) {
>- out = (struct tpm_header *)buf.data;
>+ out = (struct tpm_header *)buf->data;
> if (be16_to_cpu(out->tag) == TPM2_ST_NO_SESSIONS)
> chip->flags |= TPM_CHIP_FLAG_TPM2;
> }
>- tpm_buf_destroy(&buf);
> return 0;
> }
> EXPORT_SYMBOL_GPL(tpm2_probe);
>@@ -575,7 +557,6 @@ struct tpm2_pcr_selection {
> ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
> {
> struct tpm2_pcr_selection pcr_selection;
>- struct tpm_buf buf;
> void *marker;
> void *end;
> void *pcr_select_offset;
>@@ -587,41 +568,38 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
> int rc;
> int i = 0;
>
>- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
>- if (rc)
>- return rc;
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>
>- tpm_buf_append_u32(&buf, TPM2_CAP_PCRS);
>- tpm_buf_append_u32(&buf, 0);
>- tpm_buf_append_u32(&buf, 1);
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
>+ tpm_buf_append_u32(buf, TPM2_CAP_PCRS);
>+ tpm_buf_append_u32(buf, 0);
>+ tpm_buf_append_u32(buf, 1);
>
>- rc = tpm_transmit_cmd(chip, &buf, 9, "get tpm pcr allocation");
>+ rc = tpm_transmit_cmd(chip, buf, 9, "get tpm pcr allocation");
> if (rc)
>- goto out;
>+ return rc;
>
> nr_possible_banks = be32_to_cpup(
>- (__be32 *)&buf.data[TPM_HEADER_SIZE + 5]);
>+ (__be32 *)&buf->data[TPM_HEADER_SIZE + 5]);
>
> chip->allocated_banks = kcalloc(nr_possible_banks,
> sizeof(*chip->allocated_banks),
> GFP_KERNEL);
>- if (!chip->allocated_banks) {
>- rc = -ENOMEM;
>- goto out;
>- }
>+ if (!chip->allocated_banks)
>+ return -ENOMEM;
>
>- marker = &buf.data[TPM_HEADER_SIZE + 9];
>+ marker = &buf->data[TPM_HEADER_SIZE + 9];
>
>- rsp_len = be32_to_cpup((__be32 *)&buf.data[2]);
>- end = &buf.data[rsp_len];
>+ rsp_len = be32_to_cpup((__be32 *)&buf->data[2]);
>+ end = &buf->data[rsp_len];
>
> for (i = 0; i < nr_possible_banks; i++) {
> pcr_select_offset = marker +
> offsetof(struct tpm2_pcr_selection, size_of_select);
>- if (pcr_select_offset >= end) {
>- rc = -EFAULT;
>- break;
>- }
>+ if (pcr_select_offset >= end)
>+ return -EFAULT;
>
> memcpy(&pcr_selection, marker, sizeof(pcr_selection));
> hash_alg = be16_to_cpu(pcr_selection.hash_alg);
>@@ -633,7 +611,7 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
>
> rc = tpm2_init_bank_info(chip, nr_alloc_banks);
> if (rc < 0)
>- break;
>+ return rc;
>
> nr_alloc_banks++;
> }
>@@ -645,21 +623,21 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
> }
>
> chip->nr_allocated_banks = nr_alloc_banks;
>-out:
>- tpm_buf_destroy(&buf);
>-
>- return rc;
>+ return 0;
> }
>
> int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
> {
>- struct tpm_buf buf;
> u32 nr_commands;
> __be32 *attrs;
> u32 cc;
> int i;
> int rc;
>
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>+
> rc = tpm2_get_tpm_pt(chip, TPM_PT_TOTAL_COMMANDS, &nr_commands, NULL);
> if (rc)
> goto out;
>@@ -676,30 +654,24 @@ int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
> goto out;
> }
>
>- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
>- if (rc)
>- goto out;
>-
>- tpm_buf_append_u32(&buf, TPM2_CAP_COMMANDS);
>- tpm_buf_append_u32(&buf, TPM2_CC_FIRST);
>- tpm_buf_append_u32(&buf, nr_commands);
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
>+ tpm_buf_append_u32(buf, TPM2_CAP_COMMANDS);
>+ tpm_buf_append_u32(buf, TPM2_CC_FIRST);
>+ tpm_buf_append_u32(buf, nr_commands);
>
>- rc = tpm_transmit_cmd(chip, &buf, 9 + 4 * nr_commands, NULL);
>- if (rc) {
>- tpm_buf_destroy(&buf);
>+ rc = tpm_transmit_cmd(chip, buf, 9 + 4 * nr_commands, NULL);
>+ if (rc)
> goto out;
>- }
>
> if (nr_commands !=
>- be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE + 5])) {
>+ be32_to_cpup((__be32 *)&buf->data[TPM_HEADER_SIZE + 5])) {
> rc = -EFAULT;
>- tpm_buf_destroy(&buf);
> goto out;
> }
>
> chip->nr_commands = nr_commands;
>
>- attrs = (__be32 *)&buf.data[TPM_HEADER_SIZE + 9];
>+ attrs = (__be32 *)&buf->data[TPM_HEADER_SIZE + 9];
> for (i = 0; i < nr_commands; i++, attrs++) {
> chip->cc_attrs_tbl[i] = be32_to_cpup(attrs);
> cc = chip->cc_attrs_tbl[i] & 0xFFFF;
>@@ -711,8 +683,6 @@ int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
> }
> }
>
>- tpm_buf_destroy(&buf);
>-
> out:
> if (rc > 0)
> rc = -ENODEV;
>@@ -733,20 +703,16 @@ EXPORT_SYMBOL_GPL(tpm2_get_cc_attrs_tbl);
>
> static int tpm2_startup(struct tpm_chip *chip)
> {
>- struct tpm_buf buf;
>- int rc;
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>
> dev_info(&chip->dev, "starting up the TPM manually\n");
>
>- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP);
>- if (rc < 0)
>- return rc;
>-
>- tpm_buf_append_u16(&buf, TPM2_SU_CLEAR);
>- rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM");
>- tpm_buf_destroy(&buf);
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP);
>+ tpm_buf_append_u16(buf, TPM2_SU_CLEAR);
>
>- return rc;
>+ return tpm_transmit_cmd(chip, buf, 0, "attempting to start the TPM");
> }
>
> /**
>diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c
>index 6d03c224e6b2..b2c0c2143adc 100644
>--- a/drivers/char/tpm/tpm2-sessions.c
>+++ b/drivers/char/tpm/tpm2-sessions.c
>@@ -182,19 +182,17 @@ static int tpm2_parse_read_public(char *name, struct tpm_buf *buf)
>
> static int tpm2_read_public(struct tpm_chip *chip, u32 handle, char *name)
> {
>- struct tpm_buf buf;
> int rc;
>
>- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_READ_PUBLIC);
>- if (rc)
>- return rc;
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>
>- tpm_buf_append_u32(&buf, handle);
>- rc = tpm_transmit_cmd(chip, &buf, 0, "read public");
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_READ_PUBLIC);
>+ tpm_buf_append_u32(buf, handle);
>+ rc = tpm_transmit_cmd(chip, buf, 0, "read public");
> if (rc == TPM2_RC_SUCCESS)
>- rc = tpm2_parse_read_public(name, &buf);
>-
>- tpm_buf_destroy(&buf);
>+ rc = tpm2_parse_read_public(name, buf);
>
> return rc;
> }
>@@ -925,7 +923,6 @@ static int tpm2_load_null(struct tpm_chip *chip, u32 *null_key)
> int tpm2_start_auth_session(struct tpm_chip *chip)
> {
> struct tpm2_auth *auth;
>- struct tpm_buf buf;
> u32 null_key;
> int rc;
>
>@@ -934,6 +931,10 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
> return 0;
> }
>
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>+
> auth = kzalloc(sizeof(*auth), GFP_KERNEL);
> if (!auth)
> return -ENOMEM;
>@@ -944,41 +945,36 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
>
> auth->session = TPM_HEADER_SIZE;
>
>- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_START_AUTH_SESS);
>- if (rc)
>- goto out;
>-
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_START_AUTH_SESS);
> /* salt key handle */
>- tpm_buf_append_u32(&buf, null_key);
>+ tpm_buf_append_u32(buf, null_key);
> /* bind key handle */
>- tpm_buf_append_u32(&buf, TPM2_RH_NULL);
>+ tpm_buf_append_u32(buf, TPM2_RH_NULL);
> /* nonce caller */
> get_random_bytes(auth->our_nonce, sizeof(auth->our_nonce));
>- tpm_buf_append_u16(&buf, sizeof(auth->our_nonce));
>- tpm_buf_append(&buf, auth->our_nonce, sizeof(auth->our_nonce));
>+ tpm_buf_append_u16(buf, sizeof(auth->our_nonce));
>+ tpm_buf_append(buf, auth->our_nonce, sizeof(auth->our_nonce));
>
> /* append encrypted salt and squirrel away unencrypted in auth */
>- tpm_buf_append_salt(&buf, chip, auth);
>+ tpm_buf_append_salt(buf, chip, auth);
> /* session type (HMAC, audit or policy) */
>- tpm_buf_append_u8(&buf, TPM2_SE_HMAC);
>+ tpm_buf_append_u8(buf, TPM2_SE_HMAC);
>
> /* symmetric encryption parameters */
> /* symmetric algorithm */
>- tpm_buf_append_u16(&buf, TPM_ALG_AES);
>+ tpm_buf_append_u16(buf, TPM_ALG_AES);
> /* bits for symmetric algorithm */
>- tpm_buf_append_u16(&buf, AES_KEY_BITS);
>+ tpm_buf_append_u16(buf, AES_KEY_BITS);
> /* symmetric algorithm mode (must be CFB) */
>- tpm_buf_append_u16(&buf, TPM_ALG_CFB);
>+ tpm_buf_append_u16(buf, TPM_ALG_CFB);
> /* hash algorithm for session */
>- tpm_buf_append_u16(&buf, TPM_ALG_SHA256);
>+ tpm_buf_append_u16(buf, TPM_ALG_SHA256);
>
>- rc = tpm_ret_to_err(tpm_transmit_cmd(chip, &buf, 0, "StartAuthSession"));
>+ rc = tpm_ret_to_err(tpm_transmit_cmd(chip, buf, 0, "StartAuthSession"));
> tpm2_flush_context(chip, null_key);
>
> if (rc == TPM2_RC_SUCCESS)
>- rc = tpm2_parse_start_auth_session(auth, &buf);
>-
>- tpm_buf_destroy(&buf);
>+ rc = tpm2_parse_start_auth_session(auth, buf);
>
> if (rc == TPM2_RC_SUCCESS) {
> chip->auth = auth;
>@@ -1200,18 +1196,17 @@ static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
> u32 *handle, u8 *name)
> {
> int rc;
>- struct tpm_buf buf;
>- struct tpm_buf template;
>
>- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE_PRIMARY);
>- if (rc)
>- return rc;
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>
>- rc = tpm_buf_init_sized(&template);
>- if (rc) {
>- tpm_buf_destroy(&buf);
>- return rc;
>- }
>+ struct tpm_buf *template __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!template)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_CREATE_PRIMARY);
>+ tpm_buf_reset_sized(template, PAGE_SIZE);
>
> /*
> * create the template. Note: in order for userspace to
>@@ -1223,75 +1218,72 @@ static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
> */
>
> /* key type */
>- tpm_buf_append_u16(&template, TPM_ALG_ECC);
>+ tpm_buf_append_u16(template, TPM_ALG_ECC);
>
> /* name algorithm */
>- tpm_buf_append_u16(&template, TPM_ALG_SHA256);
>+ tpm_buf_append_u16(template, TPM_ALG_SHA256);
>
> /* object properties */
>- tpm_buf_append_u32(&template, TPM2_OA_NULL_KEY);
>+ tpm_buf_append_u32(template, TPM2_OA_NULL_KEY);
>
> /* sauth policy (empty) */
>- tpm_buf_append_u16(&template, 0);
>+ tpm_buf_append_u16(template, 0);
>
> /* BEGIN parameters: key specific; for ECC*/
>
> /* symmetric algorithm */
>- tpm_buf_append_u16(&template, TPM_ALG_AES);
>+ tpm_buf_append_u16(template, TPM_ALG_AES);
>
> /* bits for symmetric algorithm */
>- tpm_buf_append_u16(&template, AES_KEY_BITS);
>+ tpm_buf_append_u16(template, AES_KEY_BITS);
>
> /* algorithm mode (must be CFB) */
>- tpm_buf_append_u16(&template, TPM_ALG_CFB);
>+ tpm_buf_append_u16(template, TPM_ALG_CFB);
>
> /* scheme (NULL means any scheme) */
>- tpm_buf_append_u16(&template, TPM_ALG_NULL);
>+ tpm_buf_append_u16(template, TPM_ALG_NULL);
>
> /* ECC Curve ID */
>- tpm_buf_append_u16(&template, TPM2_ECC_NIST_P256);
>+ tpm_buf_append_u16(template, TPM2_ECC_NIST_P256);
>
> /* KDF Scheme */
>- tpm_buf_append_u16(&template, TPM_ALG_NULL);
>+ tpm_buf_append_u16(template, TPM_ALG_NULL);
>
> /* unique: key specific; for ECC it is two zero size points */
>- tpm_buf_append_u16(&template, 0);
>- tpm_buf_append_u16(&template, 0);
>+ tpm_buf_append_u16(template, 0);
>+ tpm_buf_append_u16(template, 0);
>
> /* END parameters */
>
> /* primary handle */
>- tpm_buf_append_u32(&buf, hierarchy);
>- tpm_buf_append_empty_auth(&buf, TPM2_RS_PW);
>+ tpm_buf_append_u32(buf, hierarchy);
>+ tpm_buf_append_empty_auth(buf, TPM2_RS_PW);
>
> /* sensitive create size is 4 for two empty buffers */
>- tpm_buf_append_u16(&buf, 4);
>+ tpm_buf_append_u16(buf, 4);
>
> /* sensitive create auth data (empty) */
>- tpm_buf_append_u16(&buf, 0);
>+ tpm_buf_append_u16(buf, 0);
>
> /* sensitive create sensitive data (empty) */
>- tpm_buf_append_u16(&buf, 0);
>+ tpm_buf_append_u16(buf, 0);
>
> /* the public template */
>- tpm_buf_append(&buf, template.data, template.length);
>- tpm_buf_destroy(&template);
>+ tpm_buf_append(buf, template->data, template->length);
>
> /* outside info (empty) */
>- tpm_buf_append_u16(&buf, 0);
>+ tpm_buf_append_u16(buf, 0);
>
> /* creation PCR (none) */
>- tpm_buf_append_u32(&buf, 0);
>+ tpm_buf_append_u32(buf, 0);
>
>- rc = tpm_transmit_cmd(chip, &buf, 0,
>+ rc = tpm_transmit_cmd(chip, buf, 0,
> "attempting to create NULL primary");
>
> if (rc == TPM2_RC_SUCCESS)
>- rc = tpm2_parse_create_primary(chip, &buf, handle, hierarchy,
>+ rc = tpm2_parse_create_primary(chip, buf, handle, hierarchy,
> name);
>
>- tpm_buf_destroy(&buf);
>-
> return rc;
> }
>
>diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c
>index 60354cd53b5c..c7409c4c78d0 100644
>--- a/drivers/char/tpm/tpm2-space.c
>+++ b/drivers/char/tpm/tpm2-space.c
>@@ -71,24 +71,24 @@ void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space)
> int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
> unsigned int *offset, u32 *handle)
> {
>- struct tpm_buf tbuf;
> struct tpm2_context *ctx;
> unsigned int body_size;
> int rc;
>
>- rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
>- if (rc)
>- return rc;
>+ struct tpm_buf *tbuf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!tbuf)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(tbuf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
>
> ctx = (struct tpm2_context *)&buf[*offset];
> body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size);
>- tpm_buf_append(&tbuf, &buf[*offset], body_size);
>+ tpm_buf_append(tbuf, &buf[*offset], body_size);
>
>- rc = tpm_transmit_cmd(chip, &tbuf, 4, NULL);
>+ rc = tpm_transmit_cmd(chip, tbuf, 4, NULL);
> if (rc < 0) {
> dev_warn(&chip->dev, "%s: failed with a system error %d\n",
> __func__, rc);
>- tpm_buf_destroy(&tbuf);
> return -EFAULT;
> } else if (tpm2_rc_value(rc) == TPM2_RC_HANDLE ||
> rc == TPM2_RC_REFERENCE_H0) {
>@@ -103,64 +103,54 @@ int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
> * flushed outside the space
> */
> *handle = 0;
>- tpm_buf_destroy(&tbuf);
> return -ENOENT;
> } else if (tpm2_rc_value(rc) == TPM2_RC_INTEGRITY) {
>- tpm_buf_destroy(&tbuf);
> return -EINVAL;
> } else if (rc > 0) {
> dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
> __func__, rc);
>- tpm_buf_destroy(&tbuf);
> return -EFAULT;
> }
>
>- *handle = be32_to_cpup((__be32 *)&tbuf.data[TPM_HEADER_SIZE]);
>+ *handle = be32_to_cpup((__be32 *)&tbuf->data[TPM_HEADER_SIZE]);
> *offset += body_size;
>-
>- tpm_buf_destroy(&tbuf);
> return 0;
> }
>
> int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
> unsigned int buf_size, unsigned int *offset)
> {
>- struct tpm_buf tbuf;
> unsigned int body_size;
> int rc;
>
>- rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE);
>- if (rc)
>- return rc;
>+ struct tpm_buf *tbuf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!tbuf)
>+ return -ENOMEM;
>
>- tpm_buf_append_u32(&tbuf, handle);
>+ tpm_buf_reset(tbuf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE);
>+ tpm_buf_append_u32(tbuf, handle);
>
>- rc = tpm_transmit_cmd(chip, &tbuf, 0, NULL);
>+ rc = tpm_transmit_cmd(chip, tbuf, 0, NULL);
> if (rc < 0) {
> dev_warn(&chip->dev, "%s: failed with a system error %d\n",
> __func__, rc);
>- tpm_buf_destroy(&tbuf);
> return -EFAULT;
> } else if (tpm2_rc_value(rc) == TPM2_RC_REFERENCE_H0) {
>- tpm_buf_destroy(&tbuf);
> return -ENOENT;
> } else if (rc) {
> dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
> __func__, rc);
>- tpm_buf_destroy(&tbuf);
> return -EFAULT;
> }
>
>- body_size = tpm_buf_length(&tbuf) - TPM_HEADER_SIZE;
>+ body_size = tpm_buf_length(tbuf) - TPM_HEADER_SIZE;
> if ((*offset + body_size) > buf_size) {
> dev_warn(&chip->dev, "%s: out of backing storage\n", __func__);
>- tpm_buf_destroy(&tbuf);
> return -ENOMEM;
> }
>
>- memcpy(&buf[*offset], &tbuf.data[TPM_HEADER_SIZE], body_size);
>+ memcpy(&buf[*offset], &tbuf->data[TPM_HEADER_SIZE], body_size);
> *offset += body_size;
>- tpm_buf_destroy(&tbuf);
> return 0;
> }
>
>diff --git a/drivers/char/tpm/tpm_vtpm_proxy.c b/drivers/char/tpm/tpm_vtpm_proxy.c
>index 0818bb517805..7ebe55825215 100644
>--- a/drivers/char/tpm/tpm_vtpm_proxy.c
>+++ b/drivers/char/tpm/tpm_vtpm_proxy.c
>@@ -395,40 +395,35 @@ static bool vtpm_proxy_tpm_req_canceled(struct tpm_chip *chip, u8 status)
>
> static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality)
> {
>- struct tpm_buf buf;
> int rc;
> const struct tpm_header *header;
> struct proxy_dev *proxy_dev = dev_get_drvdata(&chip->dev);
>
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>+
> if (chip->flags & TPM_CHIP_FLAG_TPM2)
>- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS,
>- TPM2_CC_SET_LOCALITY);
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_SET_LOCALITY);
> else
>- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND,
>- TPM_ORD_SET_LOCALITY);
>- if (rc)
>- return rc;
>- tpm_buf_append_u8(&buf, locality);
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_SET_LOCALITY);
>+
>+ tpm_buf_append_u8(buf, locality);
>
> proxy_dev->state |= STATE_DRIVER_COMMAND;
>
>- rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to set locality");
>+ rc = tpm_transmit_cmd(chip, buf, 0, "attempting to set locality");
>
> proxy_dev->state &= ~STATE_DRIVER_COMMAND;
>
>- if (rc < 0) {
>- locality = rc;
>- goto out;
>- }
>+ if (rc < 0)
>+ return rc;
>
>- header = (const struct tpm_header *)buf.data;
>+ header = (const struct tpm_header *)buf->data;
> rc = be32_to_cpu(header->return_code);
> if (rc)
> locality = -1;
>
>-out:
>- tpm_buf_destroy(&buf);
>-
> return locality;
> }
>
>diff --git a/include/linux/tpm.h b/include/linux/tpm.h
>index b0e9eb5ef022..1d8b016dd6bc 100644
>--- a/include/linux/tpm.h
>+++ b/include/linux/tpm.h
>@@ -375,13 +375,15 @@ enum tpm_buf_flags {
> };
>
> /*
>- * A string buffer type for constructing TPM commands.
>+ * A buffer for constructing and parsing TPM commands, responses and sized
>+ * (TPM2B) buffers.
> */
> struct tpm_buf {
>- u32 flags;
>- u32 length;
>- u8 *data;
>+ u8 flags;
> u8 handles;
>+ u16 length;
>+ u16 capacity;
>+ u8 data[];
> };
>
> enum tpm2_object_attributes {
>@@ -412,11 +414,8 @@ struct tpm2_hash {
> unsigned int tpm_id;
> };
>
>-int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal);
>-void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal);
>-int tpm_buf_init_sized(struct tpm_buf *buf);
>-void tpm_buf_reset_sized(struct tpm_buf *buf);
>-void tpm_buf_destroy(struct tpm_buf *buf);
>+void tpm_buf_reset(struct tpm_buf *buf, u16 buf_size, u16 tag, u32 ordinal);
>+void tpm_buf_reset_sized(struct tpm_buf *buf, u16 buf_size);
> u32 tpm_buf_length(struct tpm_buf *buf);
> void tpm_buf_append(struct tpm_buf *buf, const u8 *new_data, u16 new_length);
> void tpm_buf_append_u8(struct tpm_buf *buf, const u8 value);
>diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c
>index 636acb66a4f6..3b710daff084 100644
>--- a/security/keys/trusted-keys/trusted_tpm1.c
>+++ b/security/keys/trusted-keys/trusted_tpm1.c
>@@ -312,21 +312,23 @@ static int TSS_checkhmac2(unsigned char *buffer,
> */
> static int trusted_tpm_send(unsigned char *cmd, size_t buflen)
> {
>- struct tpm_buf buf;
> int rc;
>
> if (!chip)
> return -ENODEV;
>
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>+
> rc = tpm_try_get_ops(chip);
> if (rc)
> return rc;
>
>- buf.flags = 0;
>- buf.length = buflen;
>- buf.data = cmd;
>+ tpm_buf_append(buf, cmd, buflen);
>+
> dump_tpm_buf(cmd);
>- rc = tpm_transmit_cmd(chip, &buf, 4, "sending data");
>+ rc = tpm_transmit_cmd(chip, buf, 4, "sending data");
> dump_tpm_buf(cmd);
>
> if (rc > 0)
>@@ -368,7 +370,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
> if (ret != TPM_NONCE_SIZE)
> return -EIO;
>
>- tpm_buf_reset(tb, TPM_TAG_RQU_COMMAND, TPM_ORD_OSAP);
>+ tpm_buf_reset(tb, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_OSAP);
> tpm_buf_append_u16(tb, type);
> tpm_buf_append_u32(tb, handle);
> tpm_buf_append(tb, ononce, TPM_NONCE_SIZE);
>@@ -396,7 +398,7 @@ static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce)
> if (!chip)
> return -ENODEV;
>
>- tpm_buf_reset(tb, TPM_TAG_RQU_COMMAND, TPM_ORD_OIAP);
>+ tpm_buf_reset(tb, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_OIAP);
> ret = trusted_tpm_send(tb->data, tb->length);
> if (ret < 0)
> return ret;
>@@ -494,7 +496,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
> goto out;
>
> /* build and send the TPM request packet */
>- tpm_buf_reset(tb, TPM_TAG_RQU_AUTH1_COMMAND, TPM_ORD_SEAL);
>+ tpm_buf_reset(tb, PAGE_SIZE, TPM_TAG_RQU_AUTH1_COMMAND, TPM_ORD_SEAL);
> tpm_buf_append_u32(tb, keyhandle);
> tpm_buf_append(tb, td->encauth, SHA1_DIGEST_SIZE);
> tpm_buf_append_u32(tb, pcrinfosize);
>@@ -585,7 +587,7 @@ static int tpm_unseal(struct tpm_buf *tb,
> return ret;
>
> /* build and send TPM request packet */
>- tpm_buf_reset(tb, TPM_TAG_RQU_AUTH2_COMMAND, TPM_ORD_UNSEAL);
>+ tpm_buf_reset(tb, PAGE_SIZE, TPM_TAG_RQU_AUTH2_COMMAND, TPM_ORD_UNSEAL);
> tpm_buf_append_u32(tb, keyhandle);
> tpm_buf_append(tb, blob, bloblen);
> tpm_buf_append_u32(tb, authhandle1);
>@@ -624,23 +626,21 @@ static int tpm_unseal(struct tpm_buf *tb,
> static int key_seal(struct trusted_key_payload *p,
> struct trusted_key_options *o)
> {
>- struct tpm_buf tb;
> int ret;
>
>- ret = tpm_buf_init(&tb, 0, 0);
>- if (ret)
>- return ret;
>+ struct tpm_buf *tb __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!tb)
>+ return -ENOMEM;
>
> /* include migratable flag at end of sealed key */
> p->key[p->key_len] = p->migratable;
>
>- ret = tpm_seal(&tb, o->keytype, o->keyhandle, o->keyauth,
>+ ret = tpm_seal(tb, o->keytype, o->keyhandle, o->keyauth,
> p->key, p->key_len + 1, p->blob, &p->blob_len,
> o->blobauth, o->pcrinfo, o->pcrinfo_len);
> if (ret < 0)
> pr_info("srkseal failed (%d)\n", ret);
>
>- tpm_buf_destroy(&tb);
> return ret;
> }
>
>@@ -650,14 +650,13 @@ static int key_seal(struct trusted_key_payload *p,
> static int key_unseal(struct trusted_key_payload *p,
> struct trusted_key_options *o)
> {
>- struct tpm_buf tb;
> int ret;
>
>- ret = tpm_buf_init(&tb, 0, 0);
>- if (ret)
>- return ret;
>+ struct tpm_buf *tb __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!tb)
>+ return -ENOMEM;
>
>- ret = tpm_unseal(&tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
>+ ret = tpm_unseal(tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
> o->blobauth, p->key, &p->key_len);
> if (ret < 0)
> pr_info("srkunseal failed (%d)\n", ret);
>@@ -665,7 +664,6 @@ static int key_unseal(struct trusted_key_payload *p,
> /* pull migratable flag out of sealed key */
> p->migratable = p->key[--p->key_len];
>
>- tpm_buf_destroy(&tb);
> return ret;
> }
>
>diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
>index 024be262702f..472344c788ec 100644
>--- a/security/keys/trusted-keys/trusted_tpm2.c
>+++ b/security/keys/trusted-keys/trusted_tpm2.c
>@@ -242,13 +242,20 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> struct trusted_key_options *options)
> {
> off_t offset = TPM_HEADER_SIZE;
>- struct tpm_buf buf, sized;
> int blob_len = 0;
> u32 hash;
> u32 flags;
> int i;
> int rc;
>
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>+
>+ struct tpm_buf *sized __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!sized)
>+ return -ENOMEM;
>+
> for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
> if (options->hash == tpm2_hash_map[i].crypto_id) {
> hash = tpm2_hash_map[i].tpm_id;
>@@ -270,89 +277,76 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> if (rc)
> goto out_put;
>
>- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
>- if (rc) {
>- tpm2_end_auth_session(chip);
>- goto out_put;
>- }
>-
>- rc = tpm_buf_init_sized(&sized);
>- if (rc) {
>- tpm_buf_destroy(&buf);
>- tpm2_end_auth_session(chip);
>- goto out_put;
>- }
>-
>- tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);
>- tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_DECRYPT,
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
>+ tpm_buf_reset_sized(sized, PAGE_SIZE);
>+ tpm_buf_append_name(chip, buf, options->keyhandle, NULL);
>+ tpm_buf_append_hmac_session(chip, buf, TPM2_SA_DECRYPT,
> options->keyauth, TPM_DIGEST_SIZE);
>
> /* sensitive */
>- tpm_buf_append_u16(&sized, options->blobauth_len);
>+ tpm_buf_append_u16(sized, options->blobauth_len);
>
> if (options->blobauth_len)
>- tpm_buf_append(&sized, options->blobauth, options->blobauth_len);
>+ tpm_buf_append(sized, options->blobauth, options->blobauth_len);
>
>- tpm_buf_append_u16(&sized, payload->key_len);
>- tpm_buf_append(&sized, payload->key, payload->key_len);
>- tpm_buf_append(&buf, sized.data, sized.length);
>+ tpm_buf_append_u16(sized, payload->key_len);
>+ tpm_buf_append(sized, payload->key, payload->key_len);
>+ tpm_buf_append(buf, sized->data, sized->length);
>
> /* public */
>- tpm_buf_reset_sized(&sized);
>- tpm_buf_append_u16(&sized, TPM_ALG_KEYEDHASH);
>- tpm_buf_append_u16(&sized, hash);
>+ tpm_buf_reset_sized(sized, PAGE_SIZE);
>+ tpm_buf_append_u16(sized, TPM_ALG_KEYEDHASH);
>+ tpm_buf_append_u16(sized, hash);
>
> /* key properties */
> flags = 0;
> flags |= options->policydigest_len ? 0 : TPM2_OA_USER_WITH_AUTH;
> flags |= payload->migratable ? 0 : (TPM2_OA_FIXED_TPM | TPM2_OA_FIXED_PARENT);
>- tpm_buf_append_u32(&sized, flags);
>+ tpm_buf_append_u32(sized, flags);
>
> /* policy */
>- tpm_buf_append_u16(&sized, options->policydigest_len);
>+ tpm_buf_append_u16(sized, options->policydigest_len);
> if (options->policydigest_len)
>- tpm_buf_append(&sized, options->policydigest, options->policydigest_len);
>+ tpm_buf_append(sized, options->policydigest, options->policydigest_len);
>
> /* public parameters */
>- tpm_buf_append_u16(&sized, TPM_ALG_NULL);
>- tpm_buf_append_u16(&sized, 0);
>+ tpm_buf_append_u16(sized, TPM_ALG_NULL);
>+ tpm_buf_append_u16(sized, 0);
>
>- tpm_buf_append(&buf, sized.data, sized.length);
>+ tpm_buf_append(buf, sized->data, sized->length);
>
> /* outside info */
>- tpm_buf_append_u16(&buf, 0);
>+ tpm_buf_append_u16(buf, 0);
>
> /* creation PCR */
>- tpm_buf_append_u32(&buf, 0);
>+ tpm_buf_append_u32(buf, 0);
>
>- if (buf.flags & TPM_BUF_OVERFLOW) {
>+ if (buf->flags & TPM_BUF_OVERFLOW) {
> rc = -E2BIG;
> tpm2_end_auth_session(chip);
> goto out;
> }
>
>- tpm_buf_fill_hmac_session(chip, &buf);
>- rc = tpm_transmit_cmd(chip, &buf, 4, "sealing data");
>- rc = tpm_buf_check_hmac_response(chip, &buf, rc);
>+ tpm_buf_fill_hmac_session(chip, buf);
>+ rc = tpm_transmit_cmd(chip, buf, 4, "sealing data");
>+ rc = tpm_buf_check_hmac_response(chip, buf, rc);
> if (rc)
> goto out;
>
>- blob_len = tpm_buf_read_u32(&buf, &offset);
>- if (blob_len > MAX_BLOB_SIZE || buf.flags & TPM_BUF_BOUNDARY_ERROR) {
>+ blob_len = tpm_buf_read_u32(buf, &offset);
>+ if (blob_len > MAX_BLOB_SIZE || buf->flags & TPM_BUF_BOUNDARY_ERROR) {
> rc = -E2BIG;
> goto out;
> }
>- if (buf.length - offset < blob_len) {
>+ if (buf->length - offset < blob_len) {
> rc = -EFAULT;
> goto out;
> }
>
>- blob_len = tpm2_key_encode(payload, options, &buf.data[offset], blob_len);
>+ blob_len = tpm2_key_encode(payload, options, &buf->data[offset],
>+ blob_len);
>
> out:
>- tpm_buf_destroy(&sized);
>- tpm_buf_destroy(&buf);
>-
> if (rc > 0) {
> if (tpm2_rc_value(rc) == TPM2_RC_HASH)
> rc = -EINVAL;
>@@ -387,7 +381,6 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
> struct trusted_key_options *options,
> u32 *blob_handle)
> {
>- struct tpm_buf buf;
> unsigned int private_len;
> unsigned int public_len;
> unsigned int blob_len;
>@@ -395,6 +388,10 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
> int rc;
> u32 attrs;
>
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>+
> rc = tpm2_key_decode(payload, options, &blob);
> if (rc) {
> /* old form */
>@@ -438,35 +435,29 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
> if (rc)
> return rc;
>
>- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
>- if (rc) {
>- tpm2_end_auth_session(chip);
>- return rc;
>- }
>-
>- tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);
>- tpm_buf_append_hmac_session(chip, &buf, 0, options->keyauth,
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
>+ tpm_buf_append_name(chip, buf, options->keyhandle, NULL);
>+ tpm_buf_append_hmac_session(chip, buf, 0, options->keyauth,
> TPM_DIGEST_SIZE);
>
>- tpm_buf_append(&buf, blob, blob_len);
>+ tpm_buf_append(buf, blob, blob_len);
>
>- if (buf.flags & TPM_BUF_OVERFLOW) {
>+ if (buf->flags & TPM_BUF_OVERFLOW) {
> rc = -E2BIG;
> tpm2_end_auth_session(chip);
> goto out;
> }
>
>- tpm_buf_fill_hmac_session(chip, &buf);
>- rc = tpm_transmit_cmd(chip, &buf, 4, "loading blob");
>- rc = tpm_buf_check_hmac_response(chip, &buf, rc);
>+ tpm_buf_fill_hmac_session(chip, buf);
>+ rc = tpm_transmit_cmd(chip, buf, 4, "loading blob");
>+ rc = tpm_buf_check_hmac_response(chip, buf, rc);
> if (!rc)
> *blob_handle = be32_to_cpup(
>- (__be32 *) &buf.data[TPM_HEADER_SIZE]);
>+ (__be32 *)&buf->data[TPM_HEADER_SIZE]);
>
> out:
> if (blob != payload->blob)
> kfree(blob);
>- tpm_buf_destroy(&buf);
>
> if (rc > 0)
> rc = -EPERM;
>@@ -491,25 +482,23 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
> struct trusted_key_options *options,
> u32 blob_handle)
> {
>- struct tpm_buf buf;
> u16 data_len;
> u8 *data;
> int rc;
>
>+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
>+ if (!buf)
>+ return -ENOMEM;
>+
> rc = tpm2_start_auth_session(chip);
> if (rc)
> return rc;
>
>- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
>- if (rc) {
>- tpm2_end_auth_session(chip);
>- return rc;
>- }
>-
>- tpm_buf_append_name(chip, &buf, blob_handle, NULL);
>+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
>+ tpm_buf_append_name(chip, buf, blob_handle, NULL);
>
> if (!options->policyhandle) {
>- tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_ENCRYPT,
>+ tpm_buf_append_hmac_session(chip, buf, TPM2_SA_ENCRYPT,
> options->blobauth,
> options->blobauth_len);
> } else {
>@@ -524,32 +513,28 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
> * could repeat our actions with the exfiltrated
> * password.
> */
>- tpm2_buf_append_auth(&buf, options->policyhandle,
>+ tpm2_buf_append_auth(buf, options->policyhandle,
> NULL /* nonce */, 0, 0,
> options->blobauth, options->blobauth_len);
>- tpm_buf_append_hmac_session_opt(chip, &buf, TPM2_SA_ENCRYPT,
>+ tpm_buf_append_hmac_session_opt(chip, buf, TPM2_SA_ENCRYPT,
> NULL, 0);
> }
>
>- tpm_buf_fill_hmac_session(chip, &buf);
>- rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing");
>- rc = tpm_buf_check_hmac_response(chip, &buf, rc);
>+ tpm_buf_fill_hmac_session(chip, buf);
>+ rc = tpm_transmit_cmd(chip, buf, 6, "unsealing");
>+ rc = tpm_buf_check_hmac_response(chip, buf, rc);
> if (rc > 0)
> rc = -EPERM;
>
> if (!rc) {
> data_len = be16_to_cpup(
>- (__be16 *) &buf.data[TPM_HEADER_SIZE + 4]);
>- if (data_len < MIN_KEY_SIZE || data_len > MAX_KEY_SIZE) {
>- rc = -EFAULT;
>- goto out;
>- }
>+ (__be16 *)&buf->data[TPM_HEADER_SIZE + 4]);
>+ if (data_len < MIN_KEY_SIZE || data_len > MAX_KEY_SIZE)
>+ return -EFAULT;
>
>- if (tpm_buf_length(&buf) < TPM_HEADER_SIZE + 6 + data_len) {
>- rc = -EFAULT;
>- goto out;
>- }
>- data = &buf.data[TPM_HEADER_SIZE + 6];
>+ if (tpm_buf_length(buf) < TPM_HEADER_SIZE + 6 + data_len)
>+ return -EFAULT;
>+ data = &buf->data[TPM_HEADER_SIZE + 6];
>
> if (payload->old_format) {
> /* migratable flag is at the end of the key */
>@@ -566,8 +551,6 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
> }
> }
>
>-out:
>- tpm_buf_destroy(&buf);
> return rc;
> }
>
>--
>2.39.5
>
>
^ permalink raw reply
* Re: [PATCH v7] tpm: Make TPM buffer allocations more robust
From: Jarkko Sakkinen @ 2025-09-19 12:16 UTC (permalink / raw)
To: linux-integrity
Cc: Stefan Berger, Jarkko Sakkinen, Peter Huewe, Jason Gunthorpe,
James Bottomley, Mimi Zohar, David Howells, Paul Moore,
James Morris, Serge E. Hallyn, open list, open list:KEYS-TRUSTED,
open list:SECURITY SUBSYSTEM, ross.philipson, trenchboot-devel,
daniel.kiper
In-Reply-To: <20250919112448.2543343-1-jarkko@kernel.org>
On Fri, Sep 19, 2025 at 02:24:47PM +0300, Jarkko Sakkinen wrote:
> From: Jarkko Sakkinen <jarkko.sakkinen@opinsys.com>
>
> Drop 'tpm_buf_init', 'tpm_buf_init_sized' and 'tpm_buf_free'. Refine
> 'struct tpm_buf' to hold capacity in order to enable stack allocation and
> sizes other than page size.
>
> The updated 'struct tpm_buf' can be allocated either from stack or heap.
>
> The contract is the following:
>
> 1. 'tpm_buf_reset' and 'tpm_buf_reset_size' expect that on the first run
> the passed buffer is zeroed by the caller (e.g. via memset or kzalloc).
> 2. The same buffer can be reused. On the second and subsequent resets the
> aforementioned functions verify that 'buf_size' has the same value, and
> emits warning if not.
>
> As a consequence 'struct tpm_buf' instance can be easily wrapped into
> managed allocation:
>
> struct tpm_buf *buf __free(kfree) buf = kzalloc(PAGE_SIZE,
> GFP_KERNEL);
>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@opinsys.com>
We need this type of robustness to address:
1. More complex use cases such as HMAC encryption. No giving up on this but
it is easier to experiment when the tools are solid.
2. More decoupled types might be needed for TrenchBoot / D-RTM use cases
that some people are working on. The most likely use case in this are would
be to make 'tpm2-cmd.c' a set of builders, and decouple tpm_transmit() from
it entirely.
While I can describe this motivation only broadly, especially bullet 2 will
be tedious, if tpm buffers are no uplifted a bit (obviously that would also
require header split for tpm_buf* buf that is the trivial step).
Thus, it is right time to do this type of overturn. I.e., it does not
any of these particular paint points but we get a better playing field.
BR, Jarkko
^ permalink raw reply
* [PATCH v7] tpm: Make TPM buffer allocations more robust
From: Jarkko Sakkinen @ 2025-09-19 11:24 UTC (permalink / raw)
To: linux-integrity
Cc: Stefan Berger, Jarkko Sakkinen, Peter Huewe, Jarkko Sakkinen,
Jason Gunthorpe, James Bottomley, Mimi Zohar, David Howells,
Paul Moore, James Morris, Serge E. Hallyn, open list,
open list:KEYS-TRUSTED, open list:SECURITY SUBSYSTEM
From: Jarkko Sakkinen <jarkko.sakkinen@opinsys.com>
Drop 'tpm_buf_init', 'tpm_buf_init_sized' and 'tpm_buf_free'. Refine
'struct tpm_buf' to hold capacity in order to enable stack allocation and
sizes other than page size.
The updated 'struct tpm_buf' can be allocated either from stack or heap.
The contract is the following:
1. 'tpm_buf_reset' and 'tpm_buf_reset_size' expect that on the first run
the passed buffer is zeroed by the caller (e.g. via memset or kzalloc).
2. The same buffer can be reused. On the second and subsequent resets the
aforementioned functions verify that 'buf_size' has the same value, and
emits warning if not.
As a consequence 'struct tpm_buf' instance can be easily wrapped into
managed allocation:
struct tpm_buf *buf __free(kfree) buf = kzalloc(PAGE_SIZE,
GFP_KERNEL);
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@opinsys.com>
---
v7:
- Additional function comments and invariant was unfortunately left to
my staging area so here's the addition (does not affect functionality).
v6:
- Removed two empty lines as requested by Stefan:
https://lore.kernel.org/linux-integrity/be1c5bef-7c97-4173-b417-986dc90d779c@linux.ibm.com/
- Add 'capacity' field as this makes easy to stretch tpm_buf into stack
allocation.
v5:
- I tested this version also with TPM 1.2 by booting up and checking
that sysfs attributes work.
- Fixed the length check against capacity (James) with TPM_BUF_CAPACITY.
- Fixed declaration style: do it at the site (Jason).
- Improved commit message (Stefan).
- Removed "out" label from tpm2_pcr_read() (Stefan).
- Removed spurious "return rc;" from tpm2_get_pcr_allocation() (Stefan).
v4:
- Wrote a more a descriptive short summary and improved description.
- Fixed the error in documentation: there is 4090 bytes of space left
for the payload - not 4088 bytes.
- Turned tpm_buf_alloc() into inline function.
v3:
- Removed the cleanup class and moved on using __free(kfree) instead.
- Removed `buf_size` (James).
- I'm open for the idea of splitting still (Jason) but I'll hold
at least this revision just to check that my core idea here
is correct.
v2:
- Implement also memory allocation using the cleanup class.
- Rewrote the commit message.
- Implemented CLASS_TPM_BUF() helper macro.
---
drivers/char/tpm/tpm-buf.c | 68 ++----
drivers/char/tpm/tpm-sysfs.c | 19 +-
drivers/char/tpm/tpm1-cmd.c | 143 ++++++------
drivers/char/tpm/tpm2-cmd.c | 270 ++++++++++------------
drivers/char/tpm/tpm2-sessions.c | 118 +++++-----
drivers/char/tpm/tpm2-space.c | 42 ++--
drivers/char/tpm/tpm_vtpm_proxy.c | 29 +--
include/linux/tpm.h | 17 +-
security/keys/trusted-keys/trusted_tpm1.c | 40 ++--
security/keys/trusted-keys/trusted_tpm2.c | 153 ++++++------
10 files changed, 390 insertions(+), 509 deletions(-)
diff --git a/drivers/char/tpm/tpm-buf.c b/drivers/char/tpm/tpm-buf.c
index dc882fc9fa9e..19774bc5786f 100644
--- a/drivers/char/tpm/tpm-buf.c
+++ b/drivers/char/tpm/tpm-buf.c
@@ -7,83 +7,57 @@
#include <linux/module.h>
#include <linux/tpm.h>
-/**
- * tpm_buf_init() - Allocate and initialize a TPM command
- * @buf: A &tpm_buf
- * @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS
- * @ordinal: A command ordinal
- *
- * Return: 0 or -ENOMEM
- */
-int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
-{
- buf->data = (u8 *)__get_free_page(GFP_KERNEL);
- if (!buf->data)
- return -ENOMEM;
-
- tpm_buf_reset(buf, tag, ordinal);
- return 0;
-}
-EXPORT_SYMBOL_GPL(tpm_buf_init);
-
/**
* tpm_buf_reset() - Initialize a TPM command
* @buf: A &tpm_buf
+ * @buf_size: Size of the buffer.
* @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS
* @ordinal: A command ordinal
+ *
+ * 1. Expects that on the first run the passed buffer is zeroed by the caller.
+ * 2. Old buffer can be reused. On the second and subsequent resets @buf_size is
+ * verified to be equal to the previous value.
*/
-void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
+void tpm_buf_reset(struct tpm_buf *buf, u16 buf_size, u16 tag, u32 ordinal)
{
struct tpm_header *head = (struct tpm_header *)buf->data;
+ WARN_ON(buf->capacity != 0 && buf_size != (buf->capacity + sizeof(*buf)));
WARN_ON(tag != TPM_TAG_RQU_COMMAND && tag != TPM2_ST_NO_SESSIONS &&
tag != TPM2_ST_SESSIONS && tag != 0);
buf->flags = 0;
buf->length = sizeof(*head);
+ buf->capacity = buf_size - sizeof(*buf);
+ buf->handles = 0;
head->tag = cpu_to_be16(tag);
head->length = cpu_to_be32(sizeof(*head));
head->ordinal = cpu_to_be32(ordinal);
- buf->handles = 0;
}
EXPORT_SYMBOL_GPL(tpm_buf_reset);
-/**
- * tpm_buf_init_sized() - Allocate and initialize a sized (TPM2B) buffer
- * @buf: A @tpm_buf
- *
- * Return: 0 or -ENOMEM
- */
-int tpm_buf_init_sized(struct tpm_buf *buf)
-{
- buf->data = (u8 *)__get_free_page(GFP_KERNEL);
- if (!buf->data)
- return -ENOMEM;
-
- tpm_buf_reset_sized(buf);
- return 0;
-}
-EXPORT_SYMBOL_GPL(tpm_buf_init_sized);
-
/**
* tpm_buf_reset_sized() - Initialize a sized buffer
* @buf: A &tpm_buf
+ * @buf_size: Size of the buffer.
+ *
+ * 1. Expects that on the first run the passed buffer is zeroed by the caller.
+ * 2. Old buffer can be reused. On the second and subsequent resets @buf_size is
+ * verified to be equal to the previous value.
*/
-void tpm_buf_reset_sized(struct tpm_buf *buf)
+void tpm_buf_reset_sized(struct tpm_buf *buf, u16 buf_size)
{
+ WARN_ON(buf->capacity != 0 && buf_size != (buf->capacity + sizeof(*buf)));
+
buf->flags = TPM_BUF_TPM2B;
buf->length = 2;
+ buf->capacity = buf_size - sizeof(*buf);
+ buf->handles = 0;
buf->data[0] = 0;
buf->data[1] = 0;
}
EXPORT_SYMBOL_GPL(tpm_buf_reset_sized);
-void tpm_buf_destroy(struct tpm_buf *buf)
-{
- free_page((unsigned long)buf->data);
-}
-EXPORT_SYMBOL_GPL(tpm_buf_destroy);
-
/**
* tpm_buf_length() - Return the number of bytes consumed by the data
* @buf: A &tpm_buf
@@ -108,7 +82,7 @@ void tpm_buf_append(struct tpm_buf *buf, const u8 *new_data, u16 new_length)
if (buf->flags & TPM_BUF_OVERFLOW)
return;
- if ((buf->length + new_length) > PAGE_SIZE) {
+ if ((buf->length + new_length) > buf->capacity) {
WARN(1, "tpm_buf: write overflow\n");
buf->flags |= TPM_BUF_OVERFLOW;
return;
@@ -242,5 +216,3 @@ u32 tpm_buf_read_u32(struct tpm_buf *buf, off_t *offset)
return be32_to_cpu(value);
}
EXPORT_SYMBOL_GPL(tpm_buf_read_u32);
-
-
diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
index 94231f052ea7..68328ca6367d 100644
--- a/drivers/char/tpm/tpm-sysfs.c
+++ b/drivers/char/tpm/tpm-sysfs.c
@@ -32,28 +32,29 @@ struct tpm_readpubek_out {
static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct tpm_buf tpm_buf;
struct tpm_readpubek_out *out;
int i;
char *str = buf;
struct tpm_chip *chip = to_tpm_chip(dev);
char anti_replay[20];
+ struct tpm_buf *tpm_buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!tpm_buf)
+ return -ENOMEM;
+
memset(&anti_replay, 0, sizeof(anti_replay));
if (tpm_try_get_ops(chip))
return 0;
- if (tpm_buf_init(&tpm_buf, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK))
- goto out_ops;
-
- tpm_buf_append(&tpm_buf, anti_replay, sizeof(anti_replay));
+ tpm_buf_reset(tpm_buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK);
+ tpm_buf_append(tpm_buf, anti_replay, sizeof(anti_replay));
- if (tpm_transmit_cmd(chip, &tpm_buf, READ_PUBEK_RESULT_MIN_BODY_SIZE,
+ if (tpm_transmit_cmd(chip, tpm_buf, READ_PUBEK_RESULT_MIN_BODY_SIZE,
"attempting to read the PUBEK"))
- goto out_buf;
+ goto out_ops;
- out = (struct tpm_readpubek_out *)&tpm_buf.data[10];
+ out = (struct tpm_readpubek_out *)&tpm_buf->data[10];
str +=
sprintf(str,
"Algorithm: %4ph\n"
@@ -71,8 +72,6 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
for (i = 0; i < 256; i += 16)
str += sprintf(str, "%16ph\n", &out->modulus[i]);
-out_buf:
- tpm_buf_destroy(&tpm_buf);
out_ops:
tpm_put_ops(chip);
return str - buf;
diff --git a/drivers/char/tpm/tpm1-cmd.c b/drivers/char/tpm/tpm1-cmd.c
index cf64c7385105..e7dc01c68a92 100644
--- a/drivers/char/tpm/tpm1-cmd.c
+++ b/drivers/char/tpm/tpm1-cmd.c
@@ -323,19 +323,18 @@ unsigned long tpm1_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
*/
static int tpm1_startup(struct tpm_chip *chip)
{
- struct tpm_buf buf;
int rc;
- dev_info(&chip->dev, "starting up the TPM manually\n");
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_STARTUP);
- if (rc < 0)
- return rc;
+ dev_info(&chip->dev, "starting up the TPM manually\n");
- tpm_buf_append_u16(&buf, TPM_ST_CLEAR);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_STARTUP);
+ tpm_buf_append_u16(buf, TPM_ST_CLEAR);
- rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM");
- tpm_buf_destroy(&buf);
+ rc = tpm_transmit_cmd(chip, buf, 0, "attempting to start the TPM");
return rc;
}
@@ -463,18 +462,17 @@ int tpm1_get_timeouts(struct tpm_chip *chip)
int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash,
const char *log_msg)
{
- struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_EXTEND);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- tpm_buf_append_u32(&buf, pcr_idx);
- tpm_buf_append(&buf, hash, TPM_DIGEST_SIZE);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_EXTEND);
+ tpm_buf_append_u32(buf, pcr_idx);
+ tpm_buf_append(buf, hash, TPM_DIGEST_SIZE);
- rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE, log_msg);
- tpm_buf_destroy(&buf);
+ rc = tpm_transmit_cmd(chip, buf, TPM_DIGEST_SIZE, log_msg);
return rc;
}
@@ -482,31 +480,31 @@ int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash,
ssize_t tpm1_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
const char *desc, size_t min_cap_length)
{
- struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_CAP);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_CAP);
if (subcap_id == TPM_CAP_VERSION_1_1 ||
subcap_id == TPM_CAP_VERSION_1_2) {
- tpm_buf_append_u32(&buf, subcap_id);
- tpm_buf_append_u32(&buf, 0);
+ tpm_buf_append_u32(buf, subcap_id);
+ tpm_buf_append_u32(buf, 0);
} else {
if (subcap_id == TPM_CAP_FLAG_PERM ||
subcap_id == TPM_CAP_FLAG_VOL)
- tpm_buf_append_u32(&buf, TPM_CAP_FLAG);
+ tpm_buf_append_u32(buf, TPM_CAP_FLAG);
else
- tpm_buf_append_u32(&buf, TPM_CAP_PROP);
+ tpm_buf_append_u32(buf, TPM_CAP_PROP);
- tpm_buf_append_u32(&buf, 4);
- tpm_buf_append_u32(&buf, subcap_id);
+ tpm_buf_append_u32(buf, 4);
+ tpm_buf_append_u32(buf, subcap_id);
}
- rc = tpm_transmit_cmd(chip, &buf, min_cap_length, desc);
+ rc = tpm_transmit_cmd(chip, buf, min_cap_length, desc);
if (!rc)
- *cap = *(cap_t *)&buf.data[TPM_HEADER_SIZE + 4];
- tpm_buf_destroy(&buf);
+ *cap = *(cap_t *)&buf->data[TPM_HEADER_SIZE + 4];
return rc;
}
EXPORT_SYMBOL_GPL(tpm1_getcap);
@@ -531,81 +529,72 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
{
struct tpm1_get_random_out *out;
u32 num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA);
- struct tpm_buf buf;
u32 total = 0;
int retries = 5;
u32 recd;
int rc;
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
do {
- tpm_buf_append_u32(&buf, num_bytes);
+ tpm_buf_append_u32(buf, num_bytes);
- rc = tpm_transmit_cmd(chip, &buf, sizeof(out->rng_data_len),
+ rc = tpm_transmit_cmd(chip, buf, sizeof(out->rng_data_len),
"attempting get random");
if (rc) {
if (rc > 0)
rc = -EIO;
- goto out;
+ return rc;
}
- out = (struct tpm1_get_random_out *)&buf.data[TPM_HEADER_SIZE];
+ out = (struct tpm1_get_random_out *)&buf->data[TPM_HEADER_SIZE];
recd = be32_to_cpu(out->rng_data_len);
- if (recd > num_bytes) {
- rc = -EFAULT;
- goto out;
- }
+ if (recd > num_bytes)
+ return -EFAULT;
+
+ if (buf->length < TPM_HEADER_SIZE +
+ sizeof(out->rng_data_len) + recd)
+ return -EFAULT;
- if (tpm_buf_length(&buf) < TPM_HEADER_SIZE +
- sizeof(out->rng_data_len) + recd) {
- rc = -EFAULT;
- goto out;
- }
memcpy(dest, out->rng_data, recd);
dest += recd;
total += recd;
num_bytes -= recd;
- tpm_buf_reset(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
} while (retries-- && total < max);
rc = total ? (int)total : -EIO;
-out:
- tpm_buf_destroy(&buf);
return rc;
}
#define TPM_ORD_PCRREAD 21
int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
{
- struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCRREAD);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- tpm_buf_append_u32(&buf, pcr_idx);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_PCRREAD);
+ tpm_buf_append_u32(buf, pcr_idx);
- rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE,
+ rc = tpm_transmit_cmd(chip, buf, TPM_DIGEST_SIZE,
"attempting to read a pcr value");
if (rc)
- goto out;
-
- if (tpm_buf_length(&buf) < TPM_DIGEST_SIZE) {
- rc = -EFAULT;
- goto out;
- }
+ return rc;
- memcpy(res_buf, &buf.data[TPM_HEADER_SIZE], TPM_DIGEST_SIZE);
+ if (buf->length < TPM_DIGEST_SIZE)
+ return -EFAULT;
-out:
- tpm_buf_destroy(&buf);
+ memcpy(res_buf, &buf->data[TPM_HEADER_SIZE], TPM_DIGEST_SIZE);
return rc;
}
@@ -619,15 +608,14 @@ int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
*/
static int tpm1_continue_selftest(struct tpm_chip *chip)
{
- struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_CONTINUE_SELFTEST);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- rc = tpm_transmit_cmd(chip, &buf, 0, "continue selftest");
- tpm_buf_destroy(&buf);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_CONTINUE_SELFTEST);
+ rc = tpm_transmit_cmd(chip, buf, 0, "continue selftest");
return rc;
}
@@ -742,22 +730,23 @@ int tpm1_auto_startup(struct tpm_chip *chip)
int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
{
u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 };
- struct tpm_buf buf;
unsigned int try;
int rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
/* for buggy tpm, flush pcrs with extend to selected dummy */
if (tpm_suspend_pcr)
rc = tpm1_pcr_extend(chip, tpm_suspend_pcr, dummy_hash,
"extending dummy pcr before suspend");
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
- if (rc)
- return rc;
+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
+
/* now do the actual savestate */
for (try = 0; try < TPM_RETRY; try++) {
- rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
+ rc = tpm_transmit_cmd(chip, buf, 0, NULL);
/*
* If the TPM indicates that it is too busy to respond to
* this command then retry before giving up. It can take
@@ -772,7 +761,7 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
break;
tpm_msleep(TPM_TIMEOUT_RETRY);
- tpm_buf_reset(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
}
if (rc)
@@ -782,8 +771,6 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
dev_warn(&chip->dev, "TPM savestate took %dms\n",
try * TPM_TIMEOUT_RETRY);
- tpm_buf_destroy(&buf);
-
return rc;
}
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 524d802ede26..56d8bc496cd6 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -167,12 +167,15 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
{
int i;
int rc;
- struct tpm_buf buf;
struct tpm2_pcr_read_out *out;
u8 pcr_select[TPM2_PCR_SELECT_MIN] = {0};
u16 digest_size;
u16 expected_digest_size = 0;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
if (pcr_idx >= TPM2_PLATFORM_PCR)
return -EINVAL;
@@ -187,36 +190,30 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
expected_digest_size = chip->allocated_banks[i].digest_size;
}
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ);
- if (rc)
- return rc;
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ);
pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
- tpm_buf_append_u32(&buf, 1);
- tpm_buf_append_u16(&buf, digest->alg_id);
- tpm_buf_append_u8(&buf, TPM2_PCR_SELECT_MIN);
- tpm_buf_append(&buf, (const unsigned char *)pcr_select,
+ tpm_buf_append_u32(buf, 1);
+ tpm_buf_append_u16(buf, digest->alg_id);
+ tpm_buf_append_u8(buf, TPM2_PCR_SELECT_MIN);
+ tpm_buf_append(buf, (const unsigned char *)pcr_select,
sizeof(pcr_select));
- rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to read a pcr value");
+ rc = tpm_transmit_cmd(chip, buf, 0, "attempting to read a pcr value");
if (rc)
- goto out;
+ return rc;
- out = (struct tpm2_pcr_read_out *)&buf.data[TPM_HEADER_SIZE];
+ out = (struct tpm2_pcr_read_out *)&buf->data[TPM_HEADER_SIZE];
digest_size = be16_to_cpu(out->digest_size);
if (digest_size > sizeof(digest->digest) ||
- (!digest_size_ptr && digest_size != expected_digest_size)) {
- rc = -EINVAL;
- goto out;
- }
+ (!digest_size_ptr && digest_size != expected_digest_size))
+ return rc;
if (digest_size_ptr)
*digest_size_ptr = digest_size;
memcpy(digest->digest, out->digest, digest_size);
-out:
- tpm_buf_destroy(&buf);
return rc;
}
@@ -232,46 +229,42 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
struct tpm_digest *digests)
{
- struct tpm_buf buf;
int rc;
int i;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
if (!disable_pcr_integrity) {
rc = tpm2_start_auth_session(chip);
if (rc)
return rc;
}
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
- if (rc) {
- if (!disable_pcr_integrity)
- tpm2_end_auth_session(chip);
- return rc;
- }
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
if (!disable_pcr_integrity) {
- tpm_buf_append_name(chip, &buf, pcr_idx, NULL);
- tpm_buf_append_hmac_session(chip, &buf, 0, NULL, 0);
+ tpm_buf_append_name(chip, buf, pcr_idx, NULL);
+ tpm_buf_append_hmac_session(chip, buf, 0, NULL, 0);
} else {
- tpm_buf_append_handle(chip, &buf, pcr_idx);
- tpm_buf_append_auth(chip, &buf, 0, NULL, 0);
+ tpm_buf_append_handle(chip, buf, pcr_idx);
+ tpm_buf_append_auth(chip, buf, 0, NULL, 0);
}
- tpm_buf_append_u32(&buf, chip->nr_allocated_banks);
+ tpm_buf_append_u32(buf, chip->nr_allocated_banks);
for (i = 0; i < chip->nr_allocated_banks; i++) {
- tpm_buf_append_u16(&buf, digests[i].alg_id);
- tpm_buf_append(&buf, (const unsigned char *)&digests[i].digest,
+ tpm_buf_append_u16(buf, digests[i].alg_id);
+ tpm_buf_append(buf, (const unsigned char *)&digests[i].digest,
chip->allocated_banks[i].digest_size);
}
if (!disable_pcr_integrity)
- tpm_buf_fill_hmac_session(chip, &buf);
- rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value");
+ tpm_buf_fill_hmac_session(chip, buf);
+ rc = tpm_transmit_cmd(chip, buf, 0, "attempting extend a PCR value");
if (!disable_pcr_integrity)
- rc = tpm_buf_check_hmac_response(chip, &buf, rc);
-
- tpm_buf_destroy(&buf);
+ rc = tpm_buf_check_hmac_response(chip, buf, rc);
return rc;
}
@@ -296,7 +289,6 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
{
struct tpm2_get_random_out *out;
struct tpm_header *head;
- struct tpm_buf buf;
u32 recd;
u32 num_bytes = max;
int err;
@@ -308,43 +300,41 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
if (!num_bytes || max > TPM_MAX_RNG_DATA)
return -EINVAL;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
err = tpm2_start_auth_session(chip);
if (err)
return err;
- err = tpm_buf_init(&buf, 0, 0);
- if (err) {
- tpm2_end_auth_session(chip);
- return err;
- }
-
do {
- tpm_buf_reset(&buf, TPM2_ST_SESSIONS, TPM2_CC_GET_RANDOM);
- tpm_buf_append_hmac_session_opt(chip, &buf, TPM2_SA_ENCRYPT
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_GET_RANDOM);
+ tpm_buf_append_hmac_session_opt(chip, buf, TPM2_SA_ENCRYPT
| TPM2_SA_CONTINUE_SESSION,
NULL, 0);
- tpm_buf_append_u16(&buf, num_bytes);
- tpm_buf_fill_hmac_session(chip, &buf);
- err = tpm_transmit_cmd(chip, &buf,
+ tpm_buf_append_u16(buf, num_bytes);
+ tpm_buf_fill_hmac_session(chip, buf);
+ err = tpm_transmit_cmd(chip, buf,
offsetof(struct tpm2_get_random_out,
buffer),
"attempting get random");
- err = tpm_buf_check_hmac_response(chip, &buf, err);
+ err = tpm_buf_check_hmac_response(chip, buf, err);
if (err) {
if (err > 0)
err = -EIO;
goto out;
}
- head = (struct tpm_header *)buf.data;
+ head = (struct tpm_header *)buf->data;
offset = TPM_HEADER_SIZE;
/* Skip the parameter size field: */
if (be16_to_cpu(head->tag) == TPM2_ST_SESSIONS)
offset += 4;
- out = (struct tpm2_get_random_out *)&buf.data[offset];
+ out = (struct tpm2_get_random_out *)&buf->data[offset];
recd = min_t(u32, be16_to_cpu(out->size), num_bytes);
- if (tpm_buf_length(&buf) <
+ if (tpm_buf_length(buf) <
TPM_HEADER_SIZE +
offsetof(struct tpm2_get_random_out, buffer) +
recd) {
@@ -358,11 +348,9 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
num_bytes -= recd;
} while (retries-- && total < max);
- tpm_buf_destroy(&buf);
-
return total ? total : -EIO;
+
out:
- tpm_buf_destroy(&buf);
tpm2_end_auth_session(chip);
return err;
}
@@ -374,20 +362,17 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
*/
void tpm2_flush_context(struct tpm_chip *chip, u32 handle)
{
- struct tpm_buf buf;
- int rc;
-
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
- if (rc) {
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf) {
dev_warn(&chip->dev, "0x%08x was not flushed, out of memory\n",
handle);
return;
}
- tpm_buf_append_u32(&buf, handle);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
+ tpm_buf_append_u32(buf, handle);
- tpm_transmit_cmd(chip, &buf, 0, "flushing context");
- tpm_buf_destroy(&buf);
+ tpm_transmit_cmd(chip, buf, 0, "flushing context");
}
EXPORT_SYMBOL_GPL(tpm2_flush_context);
@@ -414,19 +399,20 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
const char *desc)
{
struct tpm2_get_cap_out *out;
- struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
- if (rc)
- return rc;
- tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
- tpm_buf_append_u32(&buf, property_id);
- tpm_buf_append_u32(&buf, 1);
- rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
+ tpm_buf_append_u32(buf, TPM2_CAP_TPM_PROPERTIES);
+ tpm_buf_append_u32(buf, property_id);
+ tpm_buf_append_u32(buf, 1);
+ rc = tpm_transmit_cmd(chip, buf, 0, NULL);
if (!rc) {
out = (struct tpm2_get_cap_out *)
- &buf.data[TPM_HEADER_SIZE];
+ &buf->data[TPM_HEADER_SIZE];
/*
* To prevent failing boot up of some systems, Infineon TPM2.0
* returns SUCCESS on TPM2_Startup in field upgrade mode. Also
@@ -438,7 +424,6 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
else
rc = -ENODATA;
}
- tpm_buf_destroy(&buf);
return rc;
}
EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);
@@ -455,15 +440,13 @@ EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);
*/
void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
{
- struct tpm_buf buf;
- int rc;
-
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SHUTDOWN);
- if (rc)
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
return;
- tpm_buf_append_u16(&buf, shutdown_type);
- tpm_transmit_cmd(chip, &buf, 0, "stopping the TPM");
- tpm_buf_destroy(&buf);
+
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_SHUTDOWN);
+ tpm_buf_append_u16(buf, shutdown_type);
+ tpm_transmit_cmd(chip, buf, 0, "stopping the TPM");
}
/**
@@ -481,19 +464,18 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
*/
static int tpm2_do_selftest(struct tpm_chip *chip)
{
- struct tpm_buf buf;
int full;
int rc;
- for (full = 0; full < 2; full++) {
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SELF_TEST);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- tpm_buf_append_u8(&buf, full);
- rc = tpm_transmit_cmd(chip, &buf, 0,
+ for (full = 0; full < 2; full++) {
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_SELF_TEST);
+ tpm_buf_append_u8(buf, full);
+ rc = tpm_transmit_cmd(chip, buf, 0,
"attempting the self test");
- tpm_buf_destroy(&buf);
if (rc == TPM2_RC_TESTING)
rc = TPM2_RC_SUCCESS;
@@ -519,23 +501,23 @@ static int tpm2_do_selftest(struct tpm_chip *chip)
int tpm2_probe(struct tpm_chip *chip)
{
struct tpm_header *out;
- struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
- if (rc)
- return rc;
- tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
- tpm_buf_append_u32(&buf, TPM_PT_TOTAL_COMMANDS);
- tpm_buf_append_u32(&buf, 1);
- rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
+ tpm_buf_append_u32(buf, TPM2_CAP_TPM_PROPERTIES);
+ tpm_buf_append_u32(buf, TPM_PT_TOTAL_COMMANDS);
+ tpm_buf_append_u32(buf, 1);
+ rc = tpm_transmit_cmd(chip, buf, 0, NULL);
/* We ignore TPM return codes on purpose. */
if (rc >= 0) {
- out = (struct tpm_header *)buf.data;
+ out = (struct tpm_header *)buf->data;
if (be16_to_cpu(out->tag) == TPM2_ST_NO_SESSIONS)
chip->flags |= TPM_CHIP_FLAG_TPM2;
}
- tpm_buf_destroy(&buf);
return 0;
}
EXPORT_SYMBOL_GPL(tpm2_probe);
@@ -575,7 +557,6 @@ struct tpm2_pcr_selection {
ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
{
struct tpm2_pcr_selection pcr_selection;
- struct tpm_buf buf;
void *marker;
void *end;
void *pcr_select_offset;
@@ -587,41 +568,38 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
int rc;
int i = 0;
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- tpm_buf_append_u32(&buf, TPM2_CAP_PCRS);
- tpm_buf_append_u32(&buf, 0);
- tpm_buf_append_u32(&buf, 1);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
+ tpm_buf_append_u32(buf, TPM2_CAP_PCRS);
+ tpm_buf_append_u32(buf, 0);
+ tpm_buf_append_u32(buf, 1);
- rc = tpm_transmit_cmd(chip, &buf, 9, "get tpm pcr allocation");
+ rc = tpm_transmit_cmd(chip, buf, 9, "get tpm pcr allocation");
if (rc)
- goto out;
+ return rc;
nr_possible_banks = be32_to_cpup(
- (__be32 *)&buf.data[TPM_HEADER_SIZE + 5]);
+ (__be32 *)&buf->data[TPM_HEADER_SIZE + 5]);
chip->allocated_banks = kcalloc(nr_possible_banks,
sizeof(*chip->allocated_banks),
GFP_KERNEL);
- if (!chip->allocated_banks) {
- rc = -ENOMEM;
- goto out;
- }
+ if (!chip->allocated_banks)
+ return -ENOMEM;
- marker = &buf.data[TPM_HEADER_SIZE + 9];
+ marker = &buf->data[TPM_HEADER_SIZE + 9];
- rsp_len = be32_to_cpup((__be32 *)&buf.data[2]);
- end = &buf.data[rsp_len];
+ rsp_len = be32_to_cpup((__be32 *)&buf->data[2]);
+ end = &buf->data[rsp_len];
for (i = 0; i < nr_possible_banks; i++) {
pcr_select_offset = marker +
offsetof(struct tpm2_pcr_selection, size_of_select);
- if (pcr_select_offset >= end) {
- rc = -EFAULT;
- break;
- }
+ if (pcr_select_offset >= end)
+ return -EFAULT;
memcpy(&pcr_selection, marker, sizeof(pcr_selection));
hash_alg = be16_to_cpu(pcr_selection.hash_alg);
@@ -633,7 +611,7 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
rc = tpm2_init_bank_info(chip, nr_alloc_banks);
if (rc < 0)
- break;
+ return rc;
nr_alloc_banks++;
}
@@ -645,21 +623,21 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
}
chip->nr_allocated_banks = nr_alloc_banks;
-out:
- tpm_buf_destroy(&buf);
-
- return rc;
+ return 0;
}
int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
{
- struct tpm_buf buf;
u32 nr_commands;
__be32 *attrs;
u32 cc;
int i;
int rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
rc = tpm2_get_tpm_pt(chip, TPM_PT_TOTAL_COMMANDS, &nr_commands, NULL);
if (rc)
goto out;
@@ -676,30 +654,24 @@ int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
goto out;
}
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
- if (rc)
- goto out;
-
- tpm_buf_append_u32(&buf, TPM2_CAP_COMMANDS);
- tpm_buf_append_u32(&buf, TPM2_CC_FIRST);
- tpm_buf_append_u32(&buf, nr_commands);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
+ tpm_buf_append_u32(buf, TPM2_CAP_COMMANDS);
+ tpm_buf_append_u32(buf, TPM2_CC_FIRST);
+ tpm_buf_append_u32(buf, nr_commands);
- rc = tpm_transmit_cmd(chip, &buf, 9 + 4 * nr_commands, NULL);
- if (rc) {
- tpm_buf_destroy(&buf);
+ rc = tpm_transmit_cmd(chip, buf, 9 + 4 * nr_commands, NULL);
+ if (rc)
goto out;
- }
if (nr_commands !=
- be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE + 5])) {
+ be32_to_cpup((__be32 *)&buf->data[TPM_HEADER_SIZE + 5])) {
rc = -EFAULT;
- tpm_buf_destroy(&buf);
goto out;
}
chip->nr_commands = nr_commands;
- attrs = (__be32 *)&buf.data[TPM_HEADER_SIZE + 9];
+ attrs = (__be32 *)&buf->data[TPM_HEADER_SIZE + 9];
for (i = 0; i < nr_commands; i++, attrs++) {
chip->cc_attrs_tbl[i] = be32_to_cpup(attrs);
cc = chip->cc_attrs_tbl[i] & 0xFFFF;
@@ -711,8 +683,6 @@ int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
}
}
- tpm_buf_destroy(&buf);
-
out:
if (rc > 0)
rc = -ENODEV;
@@ -733,20 +703,16 @@ EXPORT_SYMBOL_GPL(tpm2_get_cc_attrs_tbl);
static int tpm2_startup(struct tpm_chip *chip)
{
- struct tpm_buf buf;
- int rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
dev_info(&chip->dev, "starting up the TPM manually\n");
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP);
- if (rc < 0)
- return rc;
-
- tpm_buf_append_u16(&buf, TPM2_SU_CLEAR);
- rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM");
- tpm_buf_destroy(&buf);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP);
+ tpm_buf_append_u16(buf, TPM2_SU_CLEAR);
- return rc;
+ return tpm_transmit_cmd(chip, buf, 0, "attempting to start the TPM");
}
/**
diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c
index 6d03c224e6b2..b2c0c2143adc 100644
--- a/drivers/char/tpm/tpm2-sessions.c
+++ b/drivers/char/tpm/tpm2-sessions.c
@@ -182,19 +182,17 @@ static int tpm2_parse_read_public(char *name, struct tpm_buf *buf)
static int tpm2_read_public(struct tpm_chip *chip, u32 handle, char *name)
{
- struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_READ_PUBLIC);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- tpm_buf_append_u32(&buf, handle);
- rc = tpm_transmit_cmd(chip, &buf, 0, "read public");
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_READ_PUBLIC);
+ tpm_buf_append_u32(buf, handle);
+ rc = tpm_transmit_cmd(chip, buf, 0, "read public");
if (rc == TPM2_RC_SUCCESS)
- rc = tpm2_parse_read_public(name, &buf);
-
- tpm_buf_destroy(&buf);
+ rc = tpm2_parse_read_public(name, buf);
return rc;
}
@@ -925,7 +923,6 @@ static int tpm2_load_null(struct tpm_chip *chip, u32 *null_key)
int tpm2_start_auth_session(struct tpm_chip *chip)
{
struct tpm2_auth *auth;
- struct tpm_buf buf;
u32 null_key;
int rc;
@@ -934,6 +931,10 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
return 0;
}
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
auth = kzalloc(sizeof(*auth), GFP_KERNEL);
if (!auth)
return -ENOMEM;
@@ -944,41 +945,36 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
auth->session = TPM_HEADER_SIZE;
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_START_AUTH_SESS);
- if (rc)
- goto out;
-
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_START_AUTH_SESS);
/* salt key handle */
- tpm_buf_append_u32(&buf, null_key);
+ tpm_buf_append_u32(buf, null_key);
/* bind key handle */
- tpm_buf_append_u32(&buf, TPM2_RH_NULL);
+ tpm_buf_append_u32(buf, TPM2_RH_NULL);
/* nonce caller */
get_random_bytes(auth->our_nonce, sizeof(auth->our_nonce));
- tpm_buf_append_u16(&buf, sizeof(auth->our_nonce));
- tpm_buf_append(&buf, auth->our_nonce, sizeof(auth->our_nonce));
+ tpm_buf_append_u16(buf, sizeof(auth->our_nonce));
+ tpm_buf_append(buf, auth->our_nonce, sizeof(auth->our_nonce));
/* append encrypted salt and squirrel away unencrypted in auth */
- tpm_buf_append_salt(&buf, chip, auth);
+ tpm_buf_append_salt(buf, chip, auth);
/* session type (HMAC, audit or policy) */
- tpm_buf_append_u8(&buf, TPM2_SE_HMAC);
+ tpm_buf_append_u8(buf, TPM2_SE_HMAC);
/* symmetric encryption parameters */
/* symmetric algorithm */
- tpm_buf_append_u16(&buf, TPM_ALG_AES);
+ tpm_buf_append_u16(buf, TPM_ALG_AES);
/* bits for symmetric algorithm */
- tpm_buf_append_u16(&buf, AES_KEY_BITS);
+ tpm_buf_append_u16(buf, AES_KEY_BITS);
/* symmetric algorithm mode (must be CFB) */
- tpm_buf_append_u16(&buf, TPM_ALG_CFB);
+ tpm_buf_append_u16(buf, TPM_ALG_CFB);
/* hash algorithm for session */
- tpm_buf_append_u16(&buf, TPM_ALG_SHA256);
+ tpm_buf_append_u16(buf, TPM_ALG_SHA256);
- rc = tpm_ret_to_err(tpm_transmit_cmd(chip, &buf, 0, "StartAuthSession"));
+ rc = tpm_ret_to_err(tpm_transmit_cmd(chip, buf, 0, "StartAuthSession"));
tpm2_flush_context(chip, null_key);
if (rc == TPM2_RC_SUCCESS)
- rc = tpm2_parse_start_auth_session(auth, &buf);
-
- tpm_buf_destroy(&buf);
+ rc = tpm2_parse_start_auth_session(auth, buf);
if (rc == TPM2_RC_SUCCESS) {
chip->auth = auth;
@@ -1200,18 +1196,17 @@ static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
u32 *handle, u8 *name)
{
int rc;
- struct tpm_buf buf;
- struct tpm_buf template;
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE_PRIMARY);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- rc = tpm_buf_init_sized(&template);
- if (rc) {
- tpm_buf_destroy(&buf);
- return rc;
- }
+ struct tpm_buf *template __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!template)
+ return -ENOMEM;
+
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_CREATE_PRIMARY);
+ tpm_buf_reset_sized(template, PAGE_SIZE);
/*
* create the template. Note: in order for userspace to
@@ -1223,75 +1218,72 @@ static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
*/
/* key type */
- tpm_buf_append_u16(&template, TPM_ALG_ECC);
+ tpm_buf_append_u16(template, TPM_ALG_ECC);
/* name algorithm */
- tpm_buf_append_u16(&template, TPM_ALG_SHA256);
+ tpm_buf_append_u16(template, TPM_ALG_SHA256);
/* object properties */
- tpm_buf_append_u32(&template, TPM2_OA_NULL_KEY);
+ tpm_buf_append_u32(template, TPM2_OA_NULL_KEY);
/* sauth policy (empty) */
- tpm_buf_append_u16(&template, 0);
+ tpm_buf_append_u16(template, 0);
/* BEGIN parameters: key specific; for ECC*/
/* symmetric algorithm */
- tpm_buf_append_u16(&template, TPM_ALG_AES);
+ tpm_buf_append_u16(template, TPM_ALG_AES);
/* bits for symmetric algorithm */
- tpm_buf_append_u16(&template, AES_KEY_BITS);
+ tpm_buf_append_u16(template, AES_KEY_BITS);
/* algorithm mode (must be CFB) */
- tpm_buf_append_u16(&template, TPM_ALG_CFB);
+ tpm_buf_append_u16(template, TPM_ALG_CFB);
/* scheme (NULL means any scheme) */
- tpm_buf_append_u16(&template, TPM_ALG_NULL);
+ tpm_buf_append_u16(template, TPM_ALG_NULL);
/* ECC Curve ID */
- tpm_buf_append_u16(&template, TPM2_ECC_NIST_P256);
+ tpm_buf_append_u16(template, TPM2_ECC_NIST_P256);
/* KDF Scheme */
- tpm_buf_append_u16(&template, TPM_ALG_NULL);
+ tpm_buf_append_u16(template, TPM_ALG_NULL);
/* unique: key specific; for ECC it is two zero size points */
- tpm_buf_append_u16(&template, 0);
- tpm_buf_append_u16(&template, 0);
+ tpm_buf_append_u16(template, 0);
+ tpm_buf_append_u16(template, 0);
/* END parameters */
/* primary handle */
- tpm_buf_append_u32(&buf, hierarchy);
- tpm_buf_append_empty_auth(&buf, TPM2_RS_PW);
+ tpm_buf_append_u32(buf, hierarchy);
+ tpm_buf_append_empty_auth(buf, TPM2_RS_PW);
/* sensitive create size is 4 for two empty buffers */
- tpm_buf_append_u16(&buf, 4);
+ tpm_buf_append_u16(buf, 4);
/* sensitive create auth data (empty) */
- tpm_buf_append_u16(&buf, 0);
+ tpm_buf_append_u16(buf, 0);
/* sensitive create sensitive data (empty) */
- tpm_buf_append_u16(&buf, 0);
+ tpm_buf_append_u16(buf, 0);
/* the public template */
- tpm_buf_append(&buf, template.data, template.length);
- tpm_buf_destroy(&template);
+ tpm_buf_append(buf, template->data, template->length);
/* outside info (empty) */
- tpm_buf_append_u16(&buf, 0);
+ tpm_buf_append_u16(buf, 0);
/* creation PCR (none) */
- tpm_buf_append_u32(&buf, 0);
+ tpm_buf_append_u32(buf, 0);
- rc = tpm_transmit_cmd(chip, &buf, 0,
+ rc = tpm_transmit_cmd(chip, buf, 0,
"attempting to create NULL primary");
if (rc == TPM2_RC_SUCCESS)
- rc = tpm2_parse_create_primary(chip, &buf, handle, hierarchy,
+ rc = tpm2_parse_create_primary(chip, buf, handle, hierarchy,
name);
- tpm_buf_destroy(&buf);
-
return rc;
}
diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c
index 60354cd53b5c..c7409c4c78d0 100644
--- a/drivers/char/tpm/tpm2-space.c
+++ b/drivers/char/tpm/tpm2-space.c
@@ -71,24 +71,24 @@ void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space)
int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
unsigned int *offset, u32 *handle)
{
- struct tpm_buf tbuf;
struct tpm2_context *ctx;
unsigned int body_size;
int rc;
- rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
- if (rc)
- return rc;
+ struct tpm_buf *tbuf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!tbuf)
+ return -ENOMEM;
+
+ tpm_buf_reset(tbuf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
ctx = (struct tpm2_context *)&buf[*offset];
body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size);
- tpm_buf_append(&tbuf, &buf[*offset], body_size);
+ tpm_buf_append(tbuf, &buf[*offset], body_size);
- rc = tpm_transmit_cmd(chip, &tbuf, 4, NULL);
+ rc = tpm_transmit_cmd(chip, tbuf, 4, NULL);
if (rc < 0) {
dev_warn(&chip->dev, "%s: failed with a system error %d\n",
__func__, rc);
- tpm_buf_destroy(&tbuf);
return -EFAULT;
} else if (tpm2_rc_value(rc) == TPM2_RC_HANDLE ||
rc == TPM2_RC_REFERENCE_H0) {
@@ -103,64 +103,54 @@ int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
* flushed outside the space
*/
*handle = 0;
- tpm_buf_destroy(&tbuf);
return -ENOENT;
} else if (tpm2_rc_value(rc) == TPM2_RC_INTEGRITY) {
- tpm_buf_destroy(&tbuf);
return -EINVAL;
} else if (rc > 0) {
dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
__func__, rc);
- tpm_buf_destroy(&tbuf);
return -EFAULT;
}
- *handle = be32_to_cpup((__be32 *)&tbuf.data[TPM_HEADER_SIZE]);
+ *handle = be32_to_cpup((__be32 *)&tbuf->data[TPM_HEADER_SIZE]);
*offset += body_size;
-
- tpm_buf_destroy(&tbuf);
return 0;
}
int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
unsigned int buf_size, unsigned int *offset)
{
- struct tpm_buf tbuf;
unsigned int body_size;
int rc;
- rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE);
- if (rc)
- return rc;
+ struct tpm_buf *tbuf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!tbuf)
+ return -ENOMEM;
- tpm_buf_append_u32(&tbuf, handle);
+ tpm_buf_reset(tbuf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE);
+ tpm_buf_append_u32(tbuf, handle);
- rc = tpm_transmit_cmd(chip, &tbuf, 0, NULL);
+ rc = tpm_transmit_cmd(chip, tbuf, 0, NULL);
if (rc < 0) {
dev_warn(&chip->dev, "%s: failed with a system error %d\n",
__func__, rc);
- tpm_buf_destroy(&tbuf);
return -EFAULT;
} else if (tpm2_rc_value(rc) == TPM2_RC_REFERENCE_H0) {
- tpm_buf_destroy(&tbuf);
return -ENOENT;
} else if (rc) {
dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
__func__, rc);
- tpm_buf_destroy(&tbuf);
return -EFAULT;
}
- body_size = tpm_buf_length(&tbuf) - TPM_HEADER_SIZE;
+ body_size = tpm_buf_length(tbuf) - TPM_HEADER_SIZE;
if ((*offset + body_size) > buf_size) {
dev_warn(&chip->dev, "%s: out of backing storage\n", __func__);
- tpm_buf_destroy(&tbuf);
return -ENOMEM;
}
- memcpy(&buf[*offset], &tbuf.data[TPM_HEADER_SIZE], body_size);
+ memcpy(&buf[*offset], &tbuf->data[TPM_HEADER_SIZE], body_size);
*offset += body_size;
- tpm_buf_destroy(&tbuf);
return 0;
}
diff --git a/drivers/char/tpm/tpm_vtpm_proxy.c b/drivers/char/tpm/tpm_vtpm_proxy.c
index 0818bb517805..7ebe55825215 100644
--- a/drivers/char/tpm/tpm_vtpm_proxy.c
+++ b/drivers/char/tpm/tpm_vtpm_proxy.c
@@ -395,40 +395,35 @@ static bool vtpm_proxy_tpm_req_canceled(struct tpm_chip *chip, u8 status)
static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality)
{
- struct tpm_buf buf;
int rc;
const struct tpm_header *header;
struct proxy_dev *proxy_dev = dev_get_drvdata(&chip->dev);
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
if (chip->flags & TPM_CHIP_FLAG_TPM2)
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS,
- TPM2_CC_SET_LOCALITY);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_SET_LOCALITY);
else
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND,
- TPM_ORD_SET_LOCALITY);
- if (rc)
- return rc;
- tpm_buf_append_u8(&buf, locality);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_SET_LOCALITY);
+
+ tpm_buf_append_u8(buf, locality);
proxy_dev->state |= STATE_DRIVER_COMMAND;
- rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to set locality");
+ rc = tpm_transmit_cmd(chip, buf, 0, "attempting to set locality");
proxy_dev->state &= ~STATE_DRIVER_COMMAND;
- if (rc < 0) {
- locality = rc;
- goto out;
- }
+ if (rc < 0)
+ return rc;
- header = (const struct tpm_header *)buf.data;
+ header = (const struct tpm_header *)buf->data;
rc = be32_to_cpu(header->return_code);
if (rc)
locality = -1;
-out:
- tpm_buf_destroy(&buf);
-
return locality;
}
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index b0e9eb5ef022..1d8b016dd6bc 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -375,13 +375,15 @@ enum tpm_buf_flags {
};
/*
- * A string buffer type for constructing TPM commands.
+ * A buffer for constructing and parsing TPM commands, responses and sized
+ * (TPM2B) buffers.
*/
struct tpm_buf {
- u32 flags;
- u32 length;
- u8 *data;
+ u8 flags;
u8 handles;
+ u16 length;
+ u16 capacity;
+ u8 data[];
};
enum tpm2_object_attributes {
@@ -412,11 +414,8 @@ struct tpm2_hash {
unsigned int tpm_id;
};
-int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal);
-void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal);
-int tpm_buf_init_sized(struct tpm_buf *buf);
-void tpm_buf_reset_sized(struct tpm_buf *buf);
-void tpm_buf_destroy(struct tpm_buf *buf);
+void tpm_buf_reset(struct tpm_buf *buf, u16 buf_size, u16 tag, u32 ordinal);
+void tpm_buf_reset_sized(struct tpm_buf *buf, u16 buf_size);
u32 tpm_buf_length(struct tpm_buf *buf);
void tpm_buf_append(struct tpm_buf *buf, const u8 *new_data, u16 new_length);
void tpm_buf_append_u8(struct tpm_buf *buf, const u8 value);
diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c
index 636acb66a4f6..3b710daff084 100644
--- a/security/keys/trusted-keys/trusted_tpm1.c
+++ b/security/keys/trusted-keys/trusted_tpm1.c
@@ -312,21 +312,23 @@ static int TSS_checkhmac2(unsigned char *buffer,
*/
static int trusted_tpm_send(unsigned char *cmd, size_t buflen)
{
- struct tpm_buf buf;
int rc;
if (!chip)
return -ENODEV;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
rc = tpm_try_get_ops(chip);
if (rc)
return rc;
- buf.flags = 0;
- buf.length = buflen;
- buf.data = cmd;
+ tpm_buf_append(buf, cmd, buflen);
+
dump_tpm_buf(cmd);
- rc = tpm_transmit_cmd(chip, &buf, 4, "sending data");
+ rc = tpm_transmit_cmd(chip, buf, 4, "sending data");
dump_tpm_buf(cmd);
if (rc > 0)
@@ -368,7 +370,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
if (ret != TPM_NONCE_SIZE)
return -EIO;
- tpm_buf_reset(tb, TPM_TAG_RQU_COMMAND, TPM_ORD_OSAP);
+ tpm_buf_reset(tb, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_OSAP);
tpm_buf_append_u16(tb, type);
tpm_buf_append_u32(tb, handle);
tpm_buf_append(tb, ononce, TPM_NONCE_SIZE);
@@ -396,7 +398,7 @@ static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce)
if (!chip)
return -ENODEV;
- tpm_buf_reset(tb, TPM_TAG_RQU_COMMAND, TPM_ORD_OIAP);
+ tpm_buf_reset(tb, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_OIAP);
ret = trusted_tpm_send(tb->data, tb->length);
if (ret < 0)
return ret;
@@ -494,7 +496,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
goto out;
/* build and send the TPM request packet */
- tpm_buf_reset(tb, TPM_TAG_RQU_AUTH1_COMMAND, TPM_ORD_SEAL);
+ tpm_buf_reset(tb, PAGE_SIZE, TPM_TAG_RQU_AUTH1_COMMAND, TPM_ORD_SEAL);
tpm_buf_append_u32(tb, keyhandle);
tpm_buf_append(tb, td->encauth, SHA1_DIGEST_SIZE);
tpm_buf_append_u32(tb, pcrinfosize);
@@ -585,7 +587,7 @@ static int tpm_unseal(struct tpm_buf *tb,
return ret;
/* build and send TPM request packet */
- tpm_buf_reset(tb, TPM_TAG_RQU_AUTH2_COMMAND, TPM_ORD_UNSEAL);
+ tpm_buf_reset(tb, PAGE_SIZE, TPM_TAG_RQU_AUTH2_COMMAND, TPM_ORD_UNSEAL);
tpm_buf_append_u32(tb, keyhandle);
tpm_buf_append(tb, blob, bloblen);
tpm_buf_append_u32(tb, authhandle1);
@@ -624,23 +626,21 @@ static int tpm_unseal(struct tpm_buf *tb,
static int key_seal(struct trusted_key_payload *p,
struct trusted_key_options *o)
{
- struct tpm_buf tb;
int ret;
- ret = tpm_buf_init(&tb, 0, 0);
- if (ret)
- return ret;
+ struct tpm_buf *tb __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!tb)
+ return -ENOMEM;
/* include migratable flag at end of sealed key */
p->key[p->key_len] = p->migratable;
- ret = tpm_seal(&tb, o->keytype, o->keyhandle, o->keyauth,
+ ret = tpm_seal(tb, o->keytype, o->keyhandle, o->keyauth,
p->key, p->key_len + 1, p->blob, &p->blob_len,
o->blobauth, o->pcrinfo, o->pcrinfo_len);
if (ret < 0)
pr_info("srkseal failed (%d)\n", ret);
- tpm_buf_destroy(&tb);
return ret;
}
@@ -650,14 +650,13 @@ static int key_seal(struct trusted_key_payload *p,
static int key_unseal(struct trusted_key_payload *p,
struct trusted_key_options *o)
{
- struct tpm_buf tb;
int ret;
- ret = tpm_buf_init(&tb, 0, 0);
- if (ret)
- return ret;
+ struct tpm_buf *tb __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!tb)
+ return -ENOMEM;
- ret = tpm_unseal(&tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
+ ret = tpm_unseal(tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
o->blobauth, p->key, &p->key_len);
if (ret < 0)
pr_info("srkunseal failed (%d)\n", ret);
@@ -665,7 +664,6 @@ static int key_unseal(struct trusted_key_payload *p,
/* pull migratable flag out of sealed key */
p->migratable = p->key[--p->key_len];
- tpm_buf_destroy(&tb);
return ret;
}
diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
index 024be262702f..472344c788ec 100644
--- a/security/keys/trusted-keys/trusted_tpm2.c
+++ b/security/keys/trusted-keys/trusted_tpm2.c
@@ -242,13 +242,20 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
struct trusted_key_options *options)
{
off_t offset = TPM_HEADER_SIZE;
- struct tpm_buf buf, sized;
int blob_len = 0;
u32 hash;
u32 flags;
int i;
int rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ struct tpm_buf *sized __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!sized)
+ return -ENOMEM;
+
for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
if (options->hash == tpm2_hash_map[i].crypto_id) {
hash = tpm2_hash_map[i].tpm_id;
@@ -270,89 +277,76 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
if (rc)
goto out_put;
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
- if (rc) {
- tpm2_end_auth_session(chip);
- goto out_put;
- }
-
- rc = tpm_buf_init_sized(&sized);
- if (rc) {
- tpm_buf_destroy(&buf);
- tpm2_end_auth_session(chip);
- goto out_put;
- }
-
- tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);
- tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_DECRYPT,
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
+ tpm_buf_reset_sized(sized, PAGE_SIZE);
+ tpm_buf_append_name(chip, buf, options->keyhandle, NULL);
+ tpm_buf_append_hmac_session(chip, buf, TPM2_SA_DECRYPT,
options->keyauth, TPM_DIGEST_SIZE);
/* sensitive */
- tpm_buf_append_u16(&sized, options->blobauth_len);
+ tpm_buf_append_u16(sized, options->blobauth_len);
if (options->blobauth_len)
- tpm_buf_append(&sized, options->blobauth, options->blobauth_len);
+ tpm_buf_append(sized, options->blobauth, options->blobauth_len);
- tpm_buf_append_u16(&sized, payload->key_len);
- tpm_buf_append(&sized, payload->key, payload->key_len);
- tpm_buf_append(&buf, sized.data, sized.length);
+ tpm_buf_append_u16(sized, payload->key_len);
+ tpm_buf_append(sized, payload->key, payload->key_len);
+ tpm_buf_append(buf, sized->data, sized->length);
/* public */
- tpm_buf_reset_sized(&sized);
- tpm_buf_append_u16(&sized, TPM_ALG_KEYEDHASH);
- tpm_buf_append_u16(&sized, hash);
+ tpm_buf_reset_sized(sized, PAGE_SIZE);
+ tpm_buf_append_u16(sized, TPM_ALG_KEYEDHASH);
+ tpm_buf_append_u16(sized, hash);
/* key properties */
flags = 0;
flags |= options->policydigest_len ? 0 : TPM2_OA_USER_WITH_AUTH;
flags |= payload->migratable ? 0 : (TPM2_OA_FIXED_TPM | TPM2_OA_FIXED_PARENT);
- tpm_buf_append_u32(&sized, flags);
+ tpm_buf_append_u32(sized, flags);
/* policy */
- tpm_buf_append_u16(&sized, options->policydigest_len);
+ tpm_buf_append_u16(sized, options->policydigest_len);
if (options->policydigest_len)
- tpm_buf_append(&sized, options->policydigest, options->policydigest_len);
+ tpm_buf_append(sized, options->policydigest, options->policydigest_len);
/* public parameters */
- tpm_buf_append_u16(&sized, TPM_ALG_NULL);
- tpm_buf_append_u16(&sized, 0);
+ tpm_buf_append_u16(sized, TPM_ALG_NULL);
+ tpm_buf_append_u16(sized, 0);
- tpm_buf_append(&buf, sized.data, sized.length);
+ tpm_buf_append(buf, sized->data, sized->length);
/* outside info */
- tpm_buf_append_u16(&buf, 0);
+ tpm_buf_append_u16(buf, 0);
/* creation PCR */
- tpm_buf_append_u32(&buf, 0);
+ tpm_buf_append_u32(buf, 0);
- if (buf.flags & TPM_BUF_OVERFLOW) {
+ if (buf->flags & TPM_BUF_OVERFLOW) {
rc = -E2BIG;
tpm2_end_auth_session(chip);
goto out;
}
- tpm_buf_fill_hmac_session(chip, &buf);
- rc = tpm_transmit_cmd(chip, &buf, 4, "sealing data");
- rc = tpm_buf_check_hmac_response(chip, &buf, rc);
+ tpm_buf_fill_hmac_session(chip, buf);
+ rc = tpm_transmit_cmd(chip, buf, 4, "sealing data");
+ rc = tpm_buf_check_hmac_response(chip, buf, rc);
if (rc)
goto out;
- blob_len = tpm_buf_read_u32(&buf, &offset);
- if (blob_len > MAX_BLOB_SIZE || buf.flags & TPM_BUF_BOUNDARY_ERROR) {
+ blob_len = tpm_buf_read_u32(buf, &offset);
+ if (blob_len > MAX_BLOB_SIZE || buf->flags & TPM_BUF_BOUNDARY_ERROR) {
rc = -E2BIG;
goto out;
}
- if (buf.length - offset < blob_len) {
+ if (buf->length - offset < blob_len) {
rc = -EFAULT;
goto out;
}
- blob_len = tpm2_key_encode(payload, options, &buf.data[offset], blob_len);
+ blob_len = tpm2_key_encode(payload, options, &buf->data[offset],
+ blob_len);
out:
- tpm_buf_destroy(&sized);
- tpm_buf_destroy(&buf);
-
if (rc > 0) {
if (tpm2_rc_value(rc) == TPM2_RC_HASH)
rc = -EINVAL;
@@ -387,7 +381,6 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
struct trusted_key_options *options,
u32 *blob_handle)
{
- struct tpm_buf buf;
unsigned int private_len;
unsigned int public_len;
unsigned int blob_len;
@@ -395,6 +388,10 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
int rc;
u32 attrs;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
rc = tpm2_key_decode(payload, options, &blob);
if (rc) {
/* old form */
@@ -438,35 +435,29 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
if (rc)
return rc;
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
- if (rc) {
- tpm2_end_auth_session(chip);
- return rc;
- }
-
- tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);
- tpm_buf_append_hmac_session(chip, &buf, 0, options->keyauth,
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
+ tpm_buf_append_name(chip, buf, options->keyhandle, NULL);
+ tpm_buf_append_hmac_session(chip, buf, 0, options->keyauth,
TPM_DIGEST_SIZE);
- tpm_buf_append(&buf, blob, blob_len);
+ tpm_buf_append(buf, blob, blob_len);
- if (buf.flags & TPM_BUF_OVERFLOW) {
+ if (buf->flags & TPM_BUF_OVERFLOW) {
rc = -E2BIG;
tpm2_end_auth_session(chip);
goto out;
}
- tpm_buf_fill_hmac_session(chip, &buf);
- rc = tpm_transmit_cmd(chip, &buf, 4, "loading blob");
- rc = tpm_buf_check_hmac_response(chip, &buf, rc);
+ tpm_buf_fill_hmac_session(chip, buf);
+ rc = tpm_transmit_cmd(chip, buf, 4, "loading blob");
+ rc = tpm_buf_check_hmac_response(chip, buf, rc);
if (!rc)
*blob_handle = be32_to_cpup(
- (__be32 *) &buf.data[TPM_HEADER_SIZE]);
+ (__be32 *)&buf->data[TPM_HEADER_SIZE]);
out:
if (blob != payload->blob)
kfree(blob);
- tpm_buf_destroy(&buf);
if (rc > 0)
rc = -EPERM;
@@ -491,25 +482,23 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
struct trusted_key_options *options,
u32 blob_handle)
{
- struct tpm_buf buf;
u16 data_len;
u8 *data;
int rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
rc = tpm2_start_auth_session(chip);
if (rc)
return rc;
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
- if (rc) {
- tpm2_end_auth_session(chip);
- return rc;
- }
-
- tpm_buf_append_name(chip, &buf, blob_handle, NULL);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
+ tpm_buf_append_name(chip, buf, blob_handle, NULL);
if (!options->policyhandle) {
- tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_ENCRYPT,
+ tpm_buf_append_hmac_session(chip, buf, TPM2_SA_ENCRYPT,
options->blobauth,
options->blobauth_len);
} else {
@@ -524,32 +513,28 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
* could repeat our actions with the exfiltrated
* password.
*/
- tpm2_buf_append_auth(&buf, options->policyhandle,
+ tpm2_buf_append_auth(buf, options->policyhandle,
NULL /* nonce */, 0, 0,
options->blobauth, options->blobauth_len);
- tpm_buf_append_hmac_session_opt(chip, &buf, TPM2_SA_ENCRYPT,
+ tpm_buf_append_hmac_session_opt(chip, buf, TPM2_SA_ENCRYPT,
NULL, 0);
}
- tpm_buf_fill_hmac_session(chip, &buf);
- rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing");
- rc = tpm_buf_check_hmac_response(chip, &buf, rc);
+ tpm_buf_fill_hmac_session(chip, buf);
+ rc = tpm_transmit_cmd(chip, buf, 6, "unsealing");
+ rc = tpm_buf_check_hmac_response(chip, buf, rc);
if (rc > 0)
rc = -EPERM;
if (!rc) {
data_len = be16_to_cpup(
- (__be16 *) &buf.data[TPM_HEADER_SIZE + 4]);
- if (data_len < MIN_KEY_SIZE || data_len > MAX_KEY_SIZE) {
- rc = -EFAULT;
- goto out;
- }
+ (__be16 *)&buf->data[TPM_HEADER_SIZE + 4]);
+ if (data_len < MIN_KEY_SIZE || data_len > MAX_KEY_SIZE)
+ return -EFAULT;
- if (tpm_buf_length(&buf) < TPM_HEADER_SIZE + 6 + data_len) {
- rc = -EFAULT;
- goto out;
- }
- data = &buf.data[TPM_HEADER_SIZE + 6];
+ if (tpm_buf_length(buf) < TPM_HEADER_SIZE + 6 + data_len)
+ return -EFAULT;
+ data = &buf->data[TPM_HEADER_SIZE + 6];
if (payload->old_format) {
/* migratable flag is at the end of the key */
@@ -566,8 +551,6 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
}
}
-out:
- tpm_buf_destroy(&buf);
return rc;
}
--
2.39.5
^ permalink raw reply related
* [PATCH v6] tpm: Make TPM buffer allocations more robust
From: Jarkko Sakkinen @ 2025-09-19 11:11 UTC (permalink / raw)
To: linux-integrity
Cc: Stefan Berger, Jarkko Sakkinen, Peter Huewe, Jarkko Sakkinen,
Jason Gunthorpe, James Bottomley, Mimi Zohar, David Howells,
Paul Moore, James Morris, Serge E. Hallyn, open list,
open list:KEYS-TRUSTED, open list:SECURITY SUBSYSTEM
From: Jarkko Sakkinen <jarkko.sakkinen@opinsys.com>
Drop 'tpm_buf_init', 'tpm_buf_init_sized' and 'tpm_buf_free'. Refine
'struct tpm_buf' to hold capacity in order to enable stack allocation and
sizes other than page size.
The updated 'struct tpm_buf' can be allocated either from stack or heap.
The contract is the following:
1. 'tpm_buf_reset' and 'tpm_buf_reset_size' expect that on the first run
the passed buffer is zeroed by the caller (e.g. via memset or kzalloc).
2. The same buffer can be reused. On the second and subsequent resets the
aforementioned functions verify that 'buf_size' has the same value, and
emits warning if not.
As a consequence 'struct tpm_buf' instance can be easily wrapped into
managed allocation:
struct tpm_buf *buf __free(kfree) buf = kzalloc(PAGE_SIZE,
GFP_KERNEL);
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@opinsys.com>
---
v6:
- Removed two empty lines as requested by Stefan:
https://lore.kernel.org/linux-integrity/be1c5bef-7c97-4173-b417-986dc90d779c@linux.ibm.com/
- Add 'capacity' field as this makes easy to stretch tpm_buf into stack
allocation.
v5:
- I tested this version also with TPM 1.2 by booting up and checking
that sysfs attributes work.
- Fixed the length check against capacity (James) with TPM_BUF_CAPACITY.
- Fixed declaration style: do it at the site (Jason).
- Improved commit message (Stefan).
- Removed "out" label from tpm2_pcr_read() (Stefan).
- Removed spurious "return rc;" from tpm2_get_pcr_allocation() (Stefan).
v4:
- Wrote a more a descriptive short summary and improved description.
- Fixed the error in documentation: there is 4090 bytes of space left
for the payload - not 4088 bytes.
- Turned tpm_buf_alloc() into inline function.
v3:
- Removed the cleanup class and moved on using __free(kfree) instead.
- Removed `buf_size` (James).
- I'm open for the idea of splitting still (Jason) but I'll hold
at least this revision just to check that my core idea here
is correct.
v2:
- Implement also memory allocation using the cleanup class.
- Rewrote the commit message.
- Implemented CLASS_TPM_BUF() helper macro.
---
drivers/char/tpm/tpm-buf.c | 57 +----
drivers/char/tpm/tpm-sysfs.c | 19 +-
drivers/char/tpm/tpm1-cmd.c | 143 ++++++------
drivers/char/tpm/tpm2-cmd.c | 270 ++++++++++------------
drivers/char/tpm/tpm2-sessions.c | 118 +++++-----
drivers/char/tpm/tpm2-space.c | 42 ++--
drivers/char/tpm/tpm_vtpm_proxy.c | 29 +--
include/linux/tpm.h | 17 +-
security/keys/trusted-keys/trusted_tpm1.c | 40 ++--
security/keys/trusted-keys/trusted_tpm2.c | 153 ++++++------
10 files changed, 379 insertions(+), 509 deletions(-)
diff --git a/drivers/char/tpm/tpm-buf.c b/drivers/char/tpm/tpm-buf.c
index dc882fc9fa9e..1fe9bc99305c 100644
--- a/drivers/char/tpm/tpm-buf.c
+++ b/drivers/char/tpm/tpm-buf.c
@@ -7,32 +7,14 @@
#include <linux/module.h>
#include <linux/tpm.h>
-/**
- * tpm_buf_init() - Allocate and initialize a TPM command
- * @buf: A &tpm_buf
- * @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS
- * @ordinal: A command ordinal
- *
- * Return: 0 or -ENOMEM
- */
-int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
-{
- buf->data = (u8 *)__get_free_page(GFP_KERNEL);
- if (!buf->data)
- return -ENOMEM;
-
- tpm_buf_reset(buf, tag, ordinal);
- return 0;
-}
-EXPORT_SYMBOL_GPL(tpm_buf_init);
-
/**
* tpm_buf_reset() - Initialize a TPM command
* @buf: A &tpm_buf
+ * @buf_size: Size of the buffer.
* @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS
* @ordinal: A command ordinal
*/
-void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
+void tpm_buf_reset(struct tpm_buf *buf, u16 buf_size, u16 tag, u32 ordinal)
{
struct tpm_header *head = (struct tpm_header *)buf->data;
@@ -41,49 +23,30 @@ void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
buf->flags = 0;
buf->length = sizeof(*head);
+ buf->capacity = buf_size - sizeof(*buf);
+ buf->handles = 0;
head->tag = cpu_to_be16(tag);
head->length = cpu_to_be32(sizeof(*head));
head->ordinal = cpu_to_be32(ordinal);
- buf->handles = 0;
}
EXPORT_SYMBOL_GPL(tpm_buf_reset);
-/**
- * tpm_buf_init_sized() - Allocate and initialize a sized (TPM2B) buffer
- * @buf: A @tpm_buf
- *
- * Return: 0 or -ENOMEM
- */
-int tpm_buf_init_sized(struct tpm_buf *buf)
-{
- buf->data = (u8 *)__get_free_page(GFP_KERNEL);
- if (!buf->data)
- return -ENOMEM;
-
- tpm_buf_reset_sized(buf);
- return 0;
-}
-EXPORT_SYMBOL_GPL(tpm_buf_init_sized);
-
/**
* tpm_buf_reset_sized() - Initialize a sized buffer
* @buf: A &tpm_buf
+ * @buf_size: Size of the buffer.
*/
-void tpm_buf_reset_sized(struct tpm_buf *buf)
+void tpm_buf_reset_sized(struct tpm_buf *buf, u16 buf_size)
{
buf->flags = TPM_BUF_TPM2B;
buf->length = 2;
+ buf->capacity = buf_size - sizeof(*buf);
+ buf->handles = 0;
buf->data[0] = 0;
buf->data[1] = 0;
}
EXPORT_SYMBOL_GPL(tpm_buf_reset_sized);
-void tpm_buf_destroy(struct tpm_buf *buf)
-{
- free_page((unsigned long)buf->data);
-}
-EXPORT_SYMBOL_GPL(tpm_buf_destroy);
-
/**
* tpm_buf_length() - Return the number of bytes consumed by the data
* @buf: A &tpm_buf
@@ -108,7 +71,7 @@ void tpm_buf_append(struct tpm_buf *buf, const u8 *new_data, u16 new_length)
if (buf->flags & TPM_BUF_OVERFLOW)
return;
- if ((buf->length + new_length) > PAGE_SIZE) {
+ if ((buf->length + new_length) > buf->capacity) {
WARN(1, "tpm_buf: write overflow\n");
buf->flags |= TPM_BUF_OVERFLOW;
return;
@@ -242,5 +205,3 @@ u32 tpm_buf_read_u32(struct tpm_buf *buf, off_t *offset)
return be32_to_cpu(value);
}
EXPORT_SYMBOL_GPL(tpm_buf_read_u32);
-
-
diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
index 94231f052ea7..68328ca6367d 100644
--- a/drivers/char/tpm/tpm-sysfs.c
+++ b/drivers/char/tpm/tpm-sysfs.c
@@ -32,28 +32,29 @@ struct tpm_readpubek_out {
static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct tpm_buf tpm_buf;
struct tpm_readpubek_out *out;
int i;
char *str = buf;
struct tpm_chip *chip = to_tpm_chip(dev);
char anti_replay[20];
+ struct tpm_buf *tpm_buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!tpm_buf)
+ return -ENOMEM;
+
memset(&anti_replay, 0, sizeof(anti_replay));
if (tpm_try_get_ops(chip))
return 0;
- if (tpm_buf_init(&tpm_buf, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK))
- goto out_ops;
-
- tpm_buf_append(&tpm_buf, anti_replay, sizeof(anti_replay));
+ tpm_buf_reset(tpm_buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK);
+ tpm_buf_append(tpm_buf, anti_replay, sizeof(anti_replay));
- if (tpm_transmit_cmd(chip, &tpm_buf, READ_PUBEK_RESULT_MIN_BODY_SIZE,
+ if (tpm_transmit_cmd(chip, tpm_buf, READ_PUBEK_RESULT_MIN_BODY_SIZE,
"attempting to read the PUBEK"))
- goto out_buf;
+ goto out_ops;
- out = (struct tpm_readpubek_out *)&tpm_buf.data[10];
+ out = (struct tpm_readpubek_out *)&tpm_buf->data[10];
str +=
sprintf(str,
"Algorithm: %4ph\n"
@@ -71,8 +72,6 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
for (i = 0; i < 256; i += 16)
str += sprintf(str, "%16ph\n", &out->modulus[i]);
-out_buf:
- tpm_buf_destroy(&tpm_buf);
out_ops:
tpm_put_ops(chip);
return str - buf;
diff --git a/drivers/char/tpm/tpm1-cmd.c b/drivers/char/tpm/tpm1-cmd.c
index cf64c7385105..e7dc01c68a92 100644
--- a/drivers/char/tpm/tpm1-cmd.c
+++ b/drivers/char/tpm/tpm1-cmd.c
@@ -323,19 +323,18 @@ unsigned long tpm1_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
*/
static int tpm1_startup(struct tpm_chip *chip)
{
- struct tpm_buf buf;
int rc;
- dev_info(&chip->dev, "starting up the TPM manually\n");
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_STARTUP);
- if (rc < 0)
- return rc;
+ dev_info(&chip->dev, "starting up the TPM manually\n");
- tpm_buf_append_u16(&buf, TPM_ST_CLEAR);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_STARTUP);
+ tpm_buf_append_u16(buf, TPM_ST_CLEAR);
- rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM");
- tpm_buf_destroy(&buf);
+ rc = tpm_transmit_cmd(chip, buf, 0, "attempting to start the TPM");
return rc;
}
@@ -463,18 +462,17 @@ int tpm1_get_timeouts(struct tpm_chip *chip)
int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash,
const char *log_msg)
{
- struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_EXTEND);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- tpm_buf_append_u32(&buf, pcr_idx);
- tpm_buf_append(&buf, hash, TPM_DIGEST_SIZE);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_EXTEND);
+ tpm_buf_append_u32(buf, pcr_idx);
+ tpm_buf_append(buf, hash, TPM_DIGEST_SIZE);
- rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE, log_msg);
- tpm_buf_destroy(&buf);
+ rc = tpm_transmit_cmd(chip, buf, TPM_DIGEST_SIZE, log_msg);
return rc;
}
@@ -482,31 +480,31 @@ int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash,
ssize_t tpm1_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
const char *desc, size_t min_cap_length)
{
- struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_CAP);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_CAP);
if (subcap_id == TPM_CAP_VERSION_1_1 ||
subcap_id == TPM_CAP_VERSION_1_2) {
- tpm_buf_append_u32(&buf, subcap_id);
- tpm_buf_append_u32(&buf, 0);
+ tpm_buf_append_u32(buf, subcap_id);
+ tpm_buf_append_u32(buf, 0);
} else {
if (subcap_id == TPM_CAP_FLAG_PERM ||
subcap_id == TPM_CAP_FLAG_VOL)
- tpm_buf_append_u32(&buf, TPM_CAP_FLAG);
+ tpm_buf_append_u32(buf, TPM_CAP_FLAG);
else
- tpm_buf_append_u32(&buf, TPM_CAP_PROP);
+ tpm_buf_append_u32(buf, TPM_CAP_PROP);
- tpm_buf_append_u32(&buf, 4);
- tpm_buf_append_u32(&buf, subcap_id);
+ tpm_buf_append_u32(buf, 4);
+ tpm_buf_append_u32(buf, subcap_id);
}
- rc = tpm_transmit_cmd(chip, &buf, min_cap_length, desc);
+ rc = tpm_transmit_cmd(chip, buf, min_cap_length, desc);
if (!rc)
- *cap = *(cap_t *)&buf.data[TPM_HEADER_SIZE + 4];
- tpm_buf_destroy(&buf);
+ *cap = *(cap_t *)&buf->data[TPM_HEADER_SIZE + 4];
return rc;
}
EXPORT_SYMBOL_GPL(tpm1_getcap);
@@ -531,81 +529,72 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
{
struct tpm1_get_random_out *out;
u32 num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA);
- struct tpm_buf buf;
u32 total = 0;
int retries = 5;
u32 recd;
int rc;
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
do {
- tpm_buf_append_u32(&buf, num_bytes);
+ tpm_buf_append_u32(buf, num_bytes);
- rc = tpm_transmit_cmd(chip, &buf, sizeof(out->rng_data_len),
+ rc = tpm_transmit_cmd(chip, buf, sizeof(out->rng_data_len),
"attempting get random");
if (rc) {
if (rc > 0)
rc = -EIO;
- goto out;
+ return rc;
}
- out = (struct tpm1_get_random_out *)&buf.data[TPM_HEADER_SIZE];
+ out = (struct tpm1_get_random_out *)&buf->data[TPM_HEADER_SIZE];
recd = be32_to_cpu(out->rng_data_len);
- if (recd > num_bytes) {
- rc = -EFAULT;
- goto out;
- }
+ if (recd > num_bytes)
+ return -EFAULT;
+
+ if (buf->length < TPM_HEADER_SIZE +
+ sizeof(out->rng_data_len) + recd)
+ return -EFAULT;
- if (tpm_buf_length(&buf) < TPM_HEADER_SIZE +
- sizeof(out->rng_data_len) + recd) {
- rc = -EFAULT;
- goto out;
- }
memcpy(dest, out->rng_data, recd);
dest += recd;
total += recd;
num_bytes -= recd;
- tpm_buf_reset(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
} while (retries-- && total < max);
rc = total ? (int)total : -EIO;
-out:
- tpm_buf_destroy(&buf);
return rc;
}
#define TPM_ORD_PCRREAD 21
int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
{
- struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCRREAD);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- tpm_buf_append_u32(&buf, pcr_idx);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_PCRREAD);
+ tpm_buf_append_u32(buf, pcr_idx);
- rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE,
+ rc = tpm_transmit_cmd(chip, buf, TPM_DIGEST_SIZE,
"attempting to read a pcr value");
if (rc)
- goto out;
-
- if (tpm_buf_length(&buf) < TPM_DIGEST_SIZE) {
- rc = -EFAULT;
- goto out;
- }
+ return rc;
- memcpy(res_buf, &buf.data[TPM_HEADER_SIZE], TPM_DIGEST_SIZE);
+ if (buf->length < TPM_DIGEST_SIZE)
+ return -EFAULT;
-out:
- tpm_buf_destroy(&buf);
+ memcpy(res_buf, &buf->data[TPM_HEADER_SIZE], TPM_DIGEST_SIZE);
return rc;
}
@@ -619,15 +608,14 @@ int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
*/
static int tpm1_continue_selftest(struct tpm_chip *chip)
{
- struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_CONTINUE_SELFTEST);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- rc = tpm_transmit_cmd(chip, &buf, 0, "continue selftest");
- tpm_buf_destroy(&buf);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_CONTINUE_SELFTEST);
+ rc = tpm_transmit_cmd(chip, buf, 0, "continue selftest");
return rc;
}
@@ -742,22 +730,23 @@ int tpm1_auto_startup(struct tpm_chip *chip)
int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
{
u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 };
- struct tpm_buf buf;
unsigned int try;
int rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
/* for buggy tpm, flush pcrs with extend to selected dummy */
if (tpm_suspend_pcr)
rc = tpm1_pcr_extend(chip, tpm_suspend_pcr, dummy_hash,
"extending dummy pcr before suspend");
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
- if (rc)
- return rc;
+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
+
/* now do the actual savestate */
for (try = 0; try < TPM_RETRY; try++) {
- rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
+ rc = tpm_transmit_cmd(chip, buf, 0, NULL);
/*
* If the TPM indicates that it is too busy to respond to
* this command then retry before giving up. It can take
@@ -772,7 +761,7 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
break;
tpm_msleep(TPM_TIMEOUT_RETRY);
- tpm_buf_reset(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
}
if (rc)
@@ -782,8 +771,6 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
dev_warn(&chip->dev, "TPM savestate took %dms\n",
try * TPM_TIMEOUT_RETRY);
- tpm_buf_destroy(&buf);
-
return rc;
}
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 524d802ede26..56d8bc496cd6 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -167,12 +167,15 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
{
int i;
int rc;
- struct tpm_buf buf;
struct tpm2_pcr_read_out *out;
u8 pcr_select[TPM2_PCR_SELECT_MIN] = {0};
u16 digest_size;
u16 expected_digest_size = 0;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
if (pcr_idx >= TPM2_PLATFORM_PCR)
return -EINVAL;
@@ -187,36 +190,30 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
expected_digest_size = chip->allocated_banks[i].digest_size;
}
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ);
- if (rc)
- return rc;
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ);
pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
- tpm_buf_append_u32(&buf, 1);
- tpm_buf_append_u16(&buf, digest->alg_id);
- tpm_buf_append_u8(&buf, TPM2_PCR_SELECT_MIN);
- tpm_buf_append(&buf, (const unsigned char *)pcr_select,
+ tpm_buf_append_u32(buf, 1);
+ tpm_buf_append_u16(buf, digest->alg_id);
+ tpm_buf_append_u8(buf, TPM2_PCR_SELECT_MIN);
+ tpm_buf_append(buf, (const unsigned char *)pcr_select,
sizeof(pcr_select));
- rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to read a pcr value");
+ rc = tpm_transmit_cmd(chip, buf, 0, "attempting to read a pcr value");
if (rc)
- goto out;
+ return rc;
- out = (struct tpm2_pcr_read_out *)&buf.data[TPM_HEADER_SIZE];
+ out = (struct tpm2_pcr_read_out *)&buf->data[TPM_HEADER_SIZE];
digest_size = be16_to_cpu(out->digest_size);
if (digest_size > sizeof(digest->digest) ||
- (!digest_size_ptr && digest_size != expected_digest_size)) {
- rc = -EINVAL;
- goto out;
- }
+ (!digest_size_ptr && digest_size != expected_digest_size))
+ return rc;
if (digest_size_ptr)
*digest_size_ptr = digest_size;
memcpy(digest->digest, out->digest, digest_size);
-out:
- tpm_buf_destroy(&buf);
return rc;
}
@@ -232,46 +229,42 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
struct tpm_digest *digests)
{
- struct tpm_buf buf;
int rc;
int i;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
if (!disable_pcr_integrity) {
rc = tpm2_start_auth_session(chip);
if (rc)
return rc;
}
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
- if (rc) {
- if (!disable_pcr_integrity)
- tpm2_end_auth_session(chip);
- return rc;
- }
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
if (!disable_pcr_integrity) {
- tpm_buf_append_name(chip, &buf, pcr_idx, NULL);
- tpm_buf_append_hmac_session(chip, &buf, 0, NULL, 0);
+ tpm_buf_append_name(chip, buf, pcr_idx, NULL);
+ tpm_buf_append_hmac_session(chip, buf, 0, NULL, 0);
} else {
- tpm_buf_append_handle(chip, &buf, pcr_idx);
- tpm_buf_append_auth(chip, &buf, 0, NULL, 0);
+ tpm_buf_append_handle(chip, buf, pcr_idx);
+ tpm_buf_append_auth(chip, buf, 0, NULL, 0);
}
- tpm_buf_append_u32(&buf, chip->nr_allocated_banks);
+ tpm_buf_append_u32(buf, chip->nr_allocated_banks);
for (i = 0; i < chip->nr_allocated_banks; i++) {
- tpm_buf_append_u16(&buf, digests[i].alg_id);
- tpm_buf_append(&buf, (const unsigned char *)&digests[i].digest,
+ tpm_buf_append_u16(buf, digests[i].alg_id);
+ tpm_buf_append(buf, (const unsigned char *)&digests[i].digest,
chip->allocated_banks[i].digest_size);
}
if (!disable_pcr_integrity)
- tpm_buf_fill_hmac_session(chip, &buf);
- rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value");
+ tpm_buf_fill_hmac_session(chip, buf);
+ rc = tpm_transmit_cmd(chip, buf, 0, "attempting extend a PCR value");
if (!disable_pcr_integrity)
- rc = tpm_buf_check_hmac_response(chip, &buf, rc);
-
- tpm_buf_destroy(&buf);
+ rc = tpm_buf_check_hmac_response(chip, buf, rc);
return rc;
}
@@ -296,7 +289,6 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
{
struct tpm2_get_random_out *out;
struct tpm_header *head;
- struct tpm_buf buf;
u32 recd;
u32 num_bytes = max;
int err;
@@ -308,43 +300,41 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
if (!num_bytes || max > TPM_MAX_RNG_DATA)
return -EINVAL;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
err = tpm2_start_auth_session(chip);
if (err)
return err;
- err = tpm_buf_init(&buf, 0, 0);
- if (err) {
- tpm2_end_auth_session(chip);
- return err;
- }
-
do {
- tpm_buf_reset(&buf, TPM2_ST_SESSIONS, TPM2_CC_GET_RANDOM);
- tpm_buf_append_hmac_session_opt(chip, &buf, TPM2_SA_ENCRYPT
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_GET_RANDOM);
+ tpm_buf_append_hmac_session_opt(chip, buf, TPM2_SA_ENCRYPT
| TPM2_SA_CONTINUE_SESSION,
NULL, 0);
- tpm_buf_append_u16(&buf, num_bytes);
- tpm_buf_fill_hmac_session(chip, &buf);
- err = tpm_transmit_cmd(chip, &buf,
+ tpm_buf_append_u16(buf, num_bytes);
+ tpm_buf_fill_hmac_session(chip, buf);
+ err = tpm_transmit_cmd(chip, buf,
offsetof(struct tpm2_get_random_out,
buffer),
"attempting get random");
- err = tpm_buf_check_hmac_response(chip, &buf, err);
+ err = tpm_buf_check_hmac_response(chip, buf, err);
if (err) {
if (err > 0)
err = -EIO;
goto out;
}
- head = (struct tpm_header *)buf.data;
+ head = (struct tpm_header *)buf->data;
offset = TPM_HEADER_SIZE;
/* Skip the parameter size field: */
if (be16_to_cpu(head->tag) == TPM2_ST_SESSIONS)
offset += 4;
- out = (struct tpm2_get_random_out *)&buf.data[offset];
+ out = (struct tpm2_get_random_out *)&buf->data[offset];
recd = min_t(u32, be16_to_cpu(out->size), num_bytes);
- if (tpm_buf_length(&buf) <
+ if (tpm_buf_length(buf) <
TPM_HEADER_SIZE +
offsetof(struct tpm2_get_random_out, buffer) +
recd) {
@@ -358,11 +348,9 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
num_bytes -= recd;
} while (retries-- && total < max);
- tpm_buf_destroy(&buf);
-
return total ? total : -EIO;
+
out:
- tpm_buf_destroy(&buf);
tpm2_end_auth_session(chip);
return err;
}
@@ -374,20 +362,17 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
*/
void tpm2_flush_context(struct tpm_chip *chip, u32 handle)
{
- struct tpm_buf buf;
- int rc;
-
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
- if (rc) {
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf) {
dev_warn(&chip->dev, "0x%08x was not flushed, out of memory\n",
handle);
return;
}
- tpm_buf_append_u32(&buf, handle);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
+ tpm_buf_append_u32(buf, handle);
- tpm_transmit_cmd(chip, &buf, 0, "flushing context");
- tpm_buf_destroy(&buf);
+ tpm_transmit_cmd(chip, buf, 0, "flushing context");
}
EXPORT_SYMBOL_GPL(tpm2_flush_context);
@@ -414,19 +399,20 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
const char *desc)
{
struct tpm2_get_cap_out *out;
- struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
- if (rc)
- return rc;
- tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
- tpm_buf_append_u32(&buf, property_id);
- tpm_buf_append_u32(&buf, 1);
- rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
+ tpm_buf_append_u32(buf, TPM2_CAP_TPM_PROPERTIES);
+ tpm_buf_append_u32(buf, property_id);
+ tpm_buf_append_u32(buf, 1);
+ rc = tpm_transmit_cmd(chip, buf, 0, NULL);
if (!rc) {
out = (struct tpm2_get_cap_out *)
- &buf.data[TPM_HEADER_SIZE];
+ &buf->data[TPM_HEADER_SIZE];
/*
* To prevent failing boot up of some systems, Infineon TPM2.0
* returns SUCCESS on TPM2_Startup in field upgrade mode. Also
@@ -438,7 +424,6 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
else
rc = -ENODATA;
}
- tpm_buf_destroy(&buf);
return rc;
}
EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);
@@ -455,15 +440,13 @@ EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);
*/
void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
{
- struct tpm_buf buf;
- int rc;
-
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SHUTDOWN);
- if (rc)
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
return;
- tpm_buf_append_u16(&buf, shutdown_type);
- tpm_transmit_cmd(chip, &buf, 0, "stopping the TPM");
- tpm_buf_destroy(&buf);
+
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_SHUTDOWN);
+ tpm_buf_append_u16(buf, shutdown_type);
+ tpm_transmit_cmd(chip, buf, 0, "stopping the TPM");
}
/**
@@ -481,19 +464,18 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
*/
static int tpm2_do_selftest(struct tpm_chip *chip)
{
- struct tpm_buf buf;
int full;
int rc;
- for (full = 0; full < 2; full++) {
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SELF_TEST);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- tpm_buf_append_u8(&buf, full);
- rc = tpm_transmit_cmd(chip, &buf, 0,
+ for (full = 0; full < 2; full++) {
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_SELF_TEST);
+ tpm_buf_append_u8(buf, full);
+ rc = tpm_transmit_cmd(chip, buf, 0,
"attempting the self test");
- tpm_buf_destroy(&buf);
if (rc == TPM2_RC_TESTING)
rc = TPM2_RC_SUCCESS;
@@ -519,23 +501,23 @@ static int tpm2_do_selftest(struct tpm_chip *chip)
int tpm2_probe(struct tpm_chip *chip)
{
struct tpm_header *out;
- struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
- if (rc)
- return rc;
- tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
- tpm_buf_append_u32(&buf, TPM_PT_TOTAL_COMMANDS);
- tpm_buf_append_u32(&buf, 1);
- rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
+ tpm_buf_append_u32(buf, TPM2_CAP_TPM_PROPERTIES);
+ tpm_buf_append_u32(buf, TPM_PT_TOTAL_COMMANDS);
+ tpm_buf_append_u32(buf, 1);
+ rc = tpm_transmit_cmd(chip, buf, 0, NULL);
/* We ignore TPM return codes on purpose. */
if (rc >= 0) {
- out = (struct tpm_header *)buf.data;
+ out = (struct tpm_header *)buf->data;
if (be16_to_cpu(out->tag) == TPM2_ST_NO_SESSIONS)
chip->flags |= TPM_CHIP_FLAG_TPM2;
}
- tpm_buf_destroy(&buf);
return 0;
}
EXPORT_SYMBOL_GPL(tpm2_probe);
@@ -575,7 +557,6 @@ struct tpm2_pcr_selection {
ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
{
struct tpm2_pcr_selection pcr_selection;
- struct tpm_buf buf;
void *marker;
void *end;
void *pcr_select_offset;
@@ -587,41 +568,38 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
int rc;
int i = 0;
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- tpm_buf_append_u32(&buf, TPM2_CAP_PCRS);
- tpm_buf_append_u32(&buf, 0);
- tpm_buf_append_u32(&buf, 1);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
+ tpm_buf_append_u32(buf, TPM2_CAP_PCRS);
+ tpm_buf_append_u32(buf, 0);
+ tpm_buf_append_u32(buf, 1);
- rc = tpm_transmit_cmd(chip, &buf, 9, "get tpm pcr allocation");
+ rc = tpm_transmit_cmd(chip, buf, 9, "get tpm pcr allocation");
if (rc)
- goto out;
+ return rc;
nr_possible_banks = be32_to_cpup(
- (__be32 *)&buf.data[TPM_HEADER_SIZE + 5]);
+ (__be32 *)&buf->data[TPM_HEADER_SIZE + 5]);
chip->allocated_banks = kcalloc(nr_possible_banks,
sizeof(*chip->allocated_banks),
GFP_KERNEL);
- if (!chip->allocated_banks) {
- rc = -ENOMEM;
- goto out;
- }
+ if (!chip->allocated_banks)
+ return -ENOMEM;
- marker = &buf.data[TPM_HEADER_SIZE + 9];
+ marker = &buf->data[TPM_HEADER_SIZE + 9];
- rsp_len = be32_to_cpup((__be32 *)&buf.data[2]);
- end = &buf.data[rsp_len];
+ rsp_len = be32_to_cpup((__be32 *)&buf->data[2]);
+ end = &buf->data[rsp_len];
for (i = 0; i < nr_possible_banks; i++) {
pcr_select_offset = marker +
offsetof(struct tpm2_pcr_selection, size_of_select);
- if (pcr_select_offset >= end) {
- rc = -EFAULT;
- break;
- }
+ if (pcr_select_offset >= end)
+ return -EFAULT;
memcpy(&pcr_selection, marker, sizeof(pcr_selection));
hash_alg = be16_to_cpu(pcr_selection.hash_alg);
@@ -633,7 +611,7 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
rc = tpm2_init_bank_info(chip, nr_alloc_banks);
if (rc < 0)
- break;
+ return rc;
nr_alloc_banks++;
}
@@ -645,21 +623,21 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
}
chip->nr_allocated_banks = nr_alloc_banks;
-out:
- tpm_buf_destroy(&buf);
-
- return rc;
+ return 0;
}
int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
{
- struct tpm_buf buf;
u32 nr_commands;
__be32 *attrs;
u32 cc;
int i;
int rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
rc = tpm2_get_tpm_pt(chip, TPM_PT_TOTAL_COMMANDS, &nr_commands, NULL);
if (rc)
goto out;
@@ -676,30 +654,24 @@ int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
goto out;
}
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
- if (rc)
- goto out;
-
- tpm_buf_append_u32(&buf, TPM2_CAP_COMMANDS);
- tpm_buf_append_u32(&buf, TPM2_CC_FIRST);
- tpm_buf_append_u32(&buf, nr_commands);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
+ tpm_buf_append_u32(buf, TPM2_CAP_COMMANDS);
+ tpm_buf_append_u32(buf, TPM2_CC_FIRST);
+ tpm_buf_append_u32(buf, nr_commands);
- rc = tpm_transmit_cmd(chip, &buf, 9 + 4 * nr_commands, NULL);
- if (rc) {
- tpm_buf_destroy(&buf);
+ rc = tpm_transmit_cmd(chip, buf, 9 + 4 * nr_commands, NULL);
+ if (rc)
goto out;
- }
if (nr_commands !=
- be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE + 5])) {
+ be32_to_cpup((__be32 *)&buf->data[TPM_HEADER_SIZE + 5])) {
rc = -EFAULT;
- tpm_buf_destroy(&buf);
goto out;
}
chip->nr_commands = nr_commands;
- attrs = (__be32 *)&buf.data[TPM_HEADER_SIZE + 9];
+ attrs = (__be32 *)&buf->data[TPM_HEADER_SIZE + 9];
for (i = 0; i < nr_commands; i++, attrs++) {
chip->cc_attrs_tbl[i] = be32_to_cpup(attrs);
cc = chip->cc_attrs_tbl[i] & 0xFFFF;
@@ -711,8 +683,6 @@ int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
}
}
- tpm_buf_destroy(&buf);
-
out:
if (rc > 0)
rc = -ENODEV;
@@ -733,20 +703,16 @@ EXPORT_SYMBOL_GPL(tpm2_get_cc_attrs_tbl);
static int tpm2_startup(struct tpm_chip *chip)
{
- struct tpm_buf buf;
- int rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
dev_info(&chip->dev, "starting up the TPM manually\n");
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP);
- if (rc < 0)
- return rc;
-
- tpm_buf_append_u16(&buf, TPM2_SU_CLEAR);
- rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM");
- tpm_buf_destroy(&buf);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP);
+ tpm_buf_append_u16(buf, TPM2_SU_CLEAR);
- return rc;
+ return tpm_transmit_cmd(chip, buf, 0, "attempting to start the TPM");
}
/**
diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c
index 6d03c224e6b2..b2c0c2143adc 100644
--- a/drivers/char/tpm/tpm2-sessions.c
+++ b/drivers/char/tpm/tpm2-sessions.c
@@ -182,19 +182,17 @@ static int tpm2_parse_read_public(char *name, struct tpm_buf *buf)
static int tpm2_read_public(struct tpm_chip *chip, u32 handle, char *name)
{
- struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_READ_PUBLIC);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- tpm_buf_append_u32(&buf, handle);
- rc = tpm_transmit_cmd(chip, &buf, 0, "read public");
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_READ_PUBLIC);
+ tpm_buf_append_u32(buf, handle);
+ rc = tpm_transmit_cmd(chip, buf, 0, "read public");
if (rc == TPM2_RC_SUCCESS)
- rc = tpm2_parse_read_public(name, &buf);
-
- tpm_buf_destroy(&buf);
+ rc = tpm2_parse_read_public(name, buf);
return rc;
}
@@ -925,7 +923,6 @@ static int tpm2_load_null(struct tpm_chip *chip, u32 *null_key)
int tpm2_start_auth_session(struct tpm_chip *chip)
{
struct tpm2_auth *auth;
- struct tpm_buf buf;
u32 null_key;
int rc;
@@ -934,6 +931,10 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
return 0;
}
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
auth = kzalloc(sizeof(*auth), GFP_KERNEL);
if (!auth)
return -ENOMEM;
@@ -944,41 +945,36 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
auth->session = TPM_HEADER_SIZE;
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_START_AUTH_SESS);
- if (rc)
- goto out;
-
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_START_AUTH_SESS);
/* salt key handle */
- tpm_buf_append_u32(&buf, null_key);
+ tpm_buf_append_u32(buf, null_key);
/* bind key handle */
- tpm_buf_append_u32(&buf, TPM2_RH_NULL);
+ tpm_buf_append_u32(buf, TPM2_RH_NULL);
/* nonce caller */
get_random_bytes(auth->our_nonce, sizeof(auth->our_nonce));
- tpm_buf_append_u16(&buf, sizeof(auth->our_nonce));
- tpm_buf_append(&buf, auth->our_nonce, sizeof(auth->our_nonce));
+ tpm_buf_append_u16(buf, sizeof(auth->our_nonce));
+ tpm_buf_append(buf, auth->our_nonce, sizeof(auth->our_nonce));
/* append encrypted salt and squirrel away unencrypted in auth */
- tpm_buf_append_salt(&buf, chip, auth);
+ tpm_buf_append_salt(buf, chip, auth);
/* session type (HMAC, audit or policy) */
- tpm_buf_append_u8(&buf, TPM2_SE_HMAC);
+ tpm_buf_append_u8(buf, TPM2_SE_HMAC);
/* symmetric encryption parameters */
/* symmetric algorithm */
- tpm_buf_append_u16(&buf, TPM_ALG_AES);
+ tpm_buf_append_u16(buf, TPM_ALG_AES);
/* bits for symmetric algorithm */
- tpm_buf_append_u16(&buf, AES_KEY_BITS);
+ tpm_buf_append_u16(buf, AES_KEY_BITS);
/* symmetric algorithm mode (must be CFB) */
- tpm_buf_append_u16(&buf, TPM_ALG_CFB);
+ tpm_buf_append_u16(buf, TPM_ALG_CFB);
/* hash algorithm for session */
- tpm_buf_append_u16(&buf, TPM_ALG_SHA256);
+ tpm_buf_append_u16(buf, TPM_ALG_SHA256);
- rc = tpm_ret_to_err(tpm_transmit_cmd(chip, &buf, 0, "StartAuthSession"));
+ rc = tpm_ret_to_err(tpm_transmit_cmd(chip, buf, 0, "StartAuthSession"));
tpm2_flush_context(chip, null_key);
if (rc == TPM2_RC_SUCCESS)
- rc = tpm2_parse_start_auth_session(auth, &buf);
-
- tpm_buf_destroy(&buf);
+ rc = tpm2_parse_start_auth_session(auth, buf);
if (rc == TPM2_RC_SUCCESS) {
chip->auth = auth;
@@ -1200,18 +1196,17 @@ static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
u32 *handle, u8 *name)
{
int rc;
- struct tpm_buf buf;
- struct tpm_buf template;
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE_PRIMARY);
- if (rc)
- return rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
- rc = tpm_buf_init_sized(&template);
- if (rc) {
- tpm_buf_destroy(&buf);
- return rc;
- }
+ struct tpm_buf *template __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!template)
+ return -ENOMEM;
+
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_CREATE_PRIMARY);
+ tpm_buf_reset_sized(template, PAGE_SIZE);
/*
* create the template. Note: in order for userspace to
@@ -1223,75 +1218,72 @@ static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
*/
/* key type */
- tpm_buf_append_u16(&template, TPM_ALG_ECC);
+ tpm_buf_append_u16(template, TPM_ALG_ECC);
/* name algorithm */
- tpm_buf_append_u16(&template, TPM_ALG_SHA256);
+ tpm_buf_append_u16(template, TPM_ALG_SHA256);
/* object properties */
- tpm_buf_append_u32(&template, TPM2_OA_NULL_KEY);
+ tpm_buf_append_u32(template, TPM2_OA_NULL_KEY);
/* sauth policy (empty) */
- tpm_buf_append_u16(&template, 0);
+ tpm_buf_append_u16(template, 0);
/* BEGIN parameters: key specific; for ECC*/
/* symmetric algorithm */
- tpm_buf_append_u16(&template, TPM_ALG_AES);
+ tpm_buf_append_u16(template, TPM_ALG_AES);
/* bits for symmetric algorithm */
- tpm_buf_append_u16(&template, AES_KEY_BITS);
+ tpm_buf_append_u16(template, AES_KEY_BITS);
/* algorithm mode (must be CFB) */
- tpm_buf_append_u16(&template, TPM_ALG_CFB);
+ tpm_buf_append_u16(template, TPM_ALG_CFB);
/* scheme (NULL means any scheme) */
- tpm_buf_append_u16(&template, TPM_ALG_NULL);
+ tpm_buf_append_u16(template, TPM_ALG_NULL);
/* ECC Curve ID */
- tpm_buf_append_u16(&template, TPM2_ECC_NIST_P256);
+ tpm_buf_append_u16(template, TPM2_ECC_NIST_P256);
/* KDF Scheme */
- tpm_buf_append_u16(&template, TPM_ALG_NULL);
+ tpm_buf_append_u16(template, TPM_ALG_NULL);
/* unique: key specific; for ECC it is two zero size points */
- tpm_buf_append_u16(&template, 0);
- tpm_buf_append_u16(&template, 0);
+ tpm_buf_append_u16(template, 0);
+ tpm_buf_append_u16(template, 0);
/* END parameters */
/* primary handle */
- tpm_buf_append_u32(&buf, hierarchy);
- tpm_buf_append_empty_auth(&buf, TPM2_RS_PW);
+ tpm_buf_append_u32(buf, hierarchy);
+ tpm_buf_append_empty_auth(buf, TPM2_RS_PW);
/* sensitive create size is 4 for two empty buffers */
- tpm_buf_append_u16(&buf, 4);
+ tpm_buf_append_u16(buf, 4);
/* sensitive create auth data (empty) */
- tpm_buf_append_u16(&buf, 0);
+ tpm_buf_append_u16(buf, 0);
/* sensitive create sensitive data (empty) */
- tpm_buf_append_u16(&buf, 0);
+ tpm_buf_append_u16(buf, 0);
/* the public template */
- tpm_buf_append(&buf, template.data, template.length);
- tpm_buf_destroy(&template);
+ tpm_buf_append(buf, template->data, template->length);
/* outside info (empty) */
- tpm_buf_append_u16(&buf, 0);
+ tpm_buf_append_u16(buf, 0);
/* creation PCR (none) */
- tpm_buf_append_u32(&buf, 0);
+ tpm_buf_append_u32(buf, 0);
- rc = tpm_transmit_cmd(chip, &buf, 0,
+ rc = tpm_transmit_cmd(chip, buf, 0,
"attempting to create NULL primary");
if (rc == TPM2_RC_SUCCESS)
- rc = tpm2_parse_create_primary(chip, &buf, handle, hierarchy,
+ rc = tpm2_parse_create_primary(chip, buf, handle, hierarchy,
name);
- tpm_buf_destroy(&buf);
-
return rc;
}
diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c
index 60354cd53b5c..c7409c4c78d0 100644
--- a/drivers/char/tpm/tpm2-space.c
+++ b/drivers/char/tpm/tpm2-space.c
@@ -71,24 +71,24 @@ void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space)
int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
unsigned int *offset, u32 *handle)
{
- struct tpm_buf tbuf;
struct tpm2_context *ctx;
unsigned int body_size;
int rc;
- rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
- if (rc)
- return rc;
+ struct tpm_buf *tbuf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!tbuf)
+ return -ENOMEM;
+
+ tpm_buf_reset(tbuf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
ctx = (struct tpm2_context *)&buf[*offset];
body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size);
- tpm_buf_append(&tbuf, &buf[*offset], body_size);
+ tpm_buf_append(tbuf, &buf[*offset], body_size);
- rc = tpm_transmit_cmd(chip, &tbuf, 4, NULL);
+ rc = tpm_transmit_cmd(chip, tbuf, 4, NULL);
if (rc < 0) {
dev_warn(&chip->dev, "%s: failed with a system error %d\n",
__func__, rc);
- tpm_buf_destroy(&tbuf);
return -EFAULT;
} else if (tpm2_rc_value(rc) == TPM2_RC_HANDLE ||
rc == TPM2_RC_REFERENCE_H0) {
@@ -103,64 +103,54 @@ int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
* flushed outside the space
*/
*handle = 0;
- tpm_buf_destroy(&tbuf);
return -ENOENT;
} else if (tpm2_rc_value(rc) == TPM2_RC_INTEGRITY) {
- tpm_buf_destroy(&tbuf);
return -EINVAL;
} else if (rc > 0) {
dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
__func__, rc);
- tpm_buf_destroy(&tbuf);
return -EFAULT;
}
- *handle = be32_to_cpup((__be32 *)&tbuf.data[TPM_HEADER_SIZE]);
+ *handle = be32_to_cpup((__be32 *)&tbuf->data[TPM_HEADER_SIZE]);
*offset += body_size;
-
- tpm_buf_destroy(&tbuf);
return 0;
}
int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
unsigned int buf_size, unsigned int *offset)
{
- struct tpm_buf tbuf;
unsigned int body_size;
int rc;
- rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE);
- if (rc)
- return rc;
+ struct tpm_buf *tbuf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!tbuf)
+ return -ENOMEM;
- tpm_buf_append_u32(&tbuf, handle);
+ tpm_buf_reset(tbuf, PAGE_SIZE, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE);
+ tpm_buf_append_u32(tbuf, handle);
- rc = tpm_transmit_cmd(chip, &tbuf, 0, NULL);
+ rc = tpm_transmit_cmd(chip, tbuf, 0, NULL);
if (rc < 0) {
dev_warn(&chip->dev, "%s: failed with a system error %d\n",
__func__, rc);
- tpm_buf_destroy(&tbuf);
return -EFAULT;
} else if (tpm2_rc_value(rc) == TPM2_RC_REFERENCE_H0) {
- tpm_buf_destroy(&tbuf);
return -ENOENT;
} else if (rc) {
dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
__func__, rc);
- tpm_buf_destroy(&tbuf);
return -EFAULT;
}
- body_size = tpm_buf_length(&tbuf) - TPM_HEADER_SIZE;
+ body_size = tpm_buf_length(tbuf) - TPM_HEADER_SIZE;
if ((*offset + body_size) > buf_size) {
dev_warn(&chip->dev, "%s: out of backing storage\n", __func__);
- tpm_buf_destroy(&tbuf);
return -ENOMEM;
}
- memcpy(&buf[*offset], &tbuf.data[TPM_HEADER_SIZE], body_size);
+ memcpy(&buf[*offset], &tbuf->data[TPM_HEADER_SIZE], body_size);
*offset += body_size;
- tpm_buf_destroy(&tbuf);
return 0;
}
diff --git a/drivers/char/tpm/tpm_vtpm_proxy.c b/drivers/char/tpm/tpm_vtpm_proxy.c
index 0818bb517805..7ebe55825215 100644
--- a/drivers/char/tpm/tpm_vtpm_proxy.c
+++ b/drivers/char/tpm/tpm_vtpm_proxy.c
@@ -395,40 +395,35 @@ static bool vtpm_proxy_tpm_req_canceled(struct tpm_chip *chip, u8 status)
static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality)
{
- struct tpm_buf buf;
int rc;
const struct tpm_header *header;
struct proxy_dev *proxy_dev = dev_get_drvdata(&chip->dev);
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
if (chip->flags & TPM_CHIP_FLAG_TPM2)
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS,
- TPM2_CC_SET_LOCALITY);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_SET_LOCALITY);
else
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND,
- TPM_ORD_SET_LOCALITY);
- if (rc)
- return rc;
- tpm_buf_append_u8(&buf, locality);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_SET_LOCALITY);
+
+ tpm_buf_append_u8(buf, locality);
proxy_dev->state |= STATE_DRIVER_COMMAND;
- rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to set locality");
+ rc = tpm_transmit_cmd(chip, buf, 0, "attempting to set locality");
proxy_dev->state &= ~STATE_DRIVER_COMMAND;
- if (rc < 0) {
- locality = rc;
- goto out;
- }
+ if (rc < 0)
+ return rc;
- header = (const struct tpm_header *)buf.data;
+ header = (const struct tpm_header *)buf->data;
rc = be32_to_cpu(header->return_code);
if (rc)
locality = -1;
-out:
- tpm_buf_destroy(&buf);
-
return locality;
}
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index b0e9eb5ef022..1d8b016dd6bc 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -375,13 +375,15 @@ enum tpm_buf_flags {
};
/*
- * A string buffer type for constructing TPM commands.
+ * A buffer for constructing and parsing TPM commands, responses and sized
+ * (TPM2B) buffers.
*/
struct tpm_buf {
- u32 flags;
- u32 length;
- u8 *data;
+ u8 flags;
u8 handles;
+ u16 length;
+ u16 capacity;
+ u8 data[];
};
enum tpm2_object_attributes {
@@ -412,11 +414,8 @@ struct tpm2_hash {
unsigned int tpm_id;
};
-int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal);
-void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal);
-int tpm_buf_init_sized(struct tpm_buf *buf);
-void tpm_buf_reset_sized(struct tpm_buf *buf);
-void tpm_buf_destroy(struct tpm_buf *buf);
+void tpm_buf_reset(struct tpm_buf *buf, u16 buf_size, u16 tag, u32 ordinal);
+void tpm_buf_reset_sized(struct tpm_buf *buf, u16 buf_size);
u32 tpm_buf_length(struct tpm_buf *buf);
void tpm_buf_append(struct tpm_buf *buf, const u8 *new_data, u16 new_length);
void tpm_buf_append_u8(struct tpm_buf *buf, const u8 value);
diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c
index 636acb66a4f6..3b710daff084 100644
--- a/security/keys/trusted-keys/trusted_tpm1.c
+++ b/security/keys/trusted-keys/trusted_tpm1.c
@@ -312,21 +312,23 @@ static int TSS_checkhmac2(unsigned char *buffer,
*/
static int trusted_tpm_send(unsigned char *cmd, size_t buflen)
{
- struct tpm_buf buf;
int rc;
if (!chip)
return -ENODEV;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
rc = tpm_try_get_ops(chip);
if (rc)
return rc;
- buf.flags = 0;
- buf.length = buflen;
- buf.data = cmd;
+ tpm_buf_append(buf, cmd, buflen);
+
dump_tpm_buf(cmd);
- rc = tpm_transmit_cmd(chip, &buf, 4, "sending data");
+ rc = tpm_transmit_cmd(chip, buf, 4, "sending data");
dump_tpm_buf(cmd);
if (rc > 0)
@@ -368,7 +370,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
if (ret != TPM_NONCE_SIZE)
return -EIO;
- tpm_buf_reset(tb, TPM_TAG_RQU_COMMAND, TPM_ORD_OSAP);
+ tpm_buf_reset(tb, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_OSAP);
tpm_buf_append_u16(tb, type);
tpm_buf_append_u32(tb, handle);
tpm_buf_append(tb, ononce, TPM_NONCE_SIZE);
@@ -396,7 +398,7 @@ static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce)
if (!chip)
return -ENODEV;
- tpm_buf_reset(tb, TPM_TAG_RQU_COMMAND, TPM_ORD_OIAP);
+ tpm_buf_reset(tb, PAGE_SIZE, TPM_TAG_RQU_COMMAND, TPM_ORD_OIAP);
ret = trusted_tpm_send(tb->data, tb->length);
if (ret < 0)
return ret;
@@ -494,7 +496,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
goto out;
/* build and send the TPM request packet */
- tpm_buf_reset(tb, TPM_TAG_RQU_AUTH1_COMMAND, TPM_ORD_SEAL);
+ tpm_buf_reset(tb, PAGE_SIZE, TPM_TAG_RQU_AUTH1_COMMAND, TPM_ORD_SEAL);
tpm_buf_append_u32(tb, keyhandle);
tpm_buf_append(tb, td->encauth, SHA1_DIGEST_SIZE);
tpm_buf_append_u32(tb, pcrinfosize);
@@ -585,7 +587,7 @@ static int tpm_unseal(struct tpm_buf *tb,
return ret;
/* build and send TPM request packet */
- tpm_buf_reset(tb, TPM_TAG_RQU_AUTH2_COMMAND, TPM_ORD_UNSEAL);
+ tpm_buf_reset(tb, PAGE_SIZE, TPM_TAG_RQU_AUTH2_COMMAND, TPM_ORD_UNSEAL);
tpm_buf_append_u32(tb, keyhandle);
tpm_buf_append(tb, blob, bloblen);
tpm_buf_append_u32(tb, authhandle1);
@@ -624,23 +626,21 @@ static int tpm_unseal(struct tpm_buf *tb,
static int key_seal(struct trusted_key_payload *p,
struct trusted_key_options *o)
{
- struct tpm_buf tb;
int ret;
- ret = tpm_buf_init(&tb, 0, 0);
- if (ret)
- return ret;
+ struct tpm_buf *tb __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!tb)
+ return -ENOMEM;
/* include migratable flag at end of sealed key */
p->key[p->key_len] = p->migratable;
- ret = tpm_seal(&tb, o->keytype, o->keyhandle, o->keyauth,
+ ret = tpm_seal(tb, o->keytype, o->keyhandle, o->keyauth,
p->key, p->key_len + 1, p->blob, &p->blob_len,
o->blobauth, o->pcrinfo, o->pcrinfo_len);
if (ret < 0)
pr_info("srkseal failed (%d)\n", ret);
- tpm_buf_destroy(&tb);
return ret;
}
@@ -650,14 +650,13 @@ static int key_seal(struct trusted_key_payload *p,
static int key_unseal(struct trusted_key_payload *p,
struct trusted_key_options *o)
{
- struct tpm_buf tb;
int ret;
- ret = tpm_buf_init(&tb, 0, 0);
- if (ret)
- return ret;
+ struct tpm_buf *tb __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!tb)
+ return -ENOMEM;
- ret = tpm_unseal(&tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
+ ret = tpm_unseal(tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
o->blobauth, p->key, &p->key_len);
if (ret < 0)
pr_info("srkunseal failed (%d)\n", ret);
@@ -665,7 +664,6 @@ static int key_unseal(struct trusted_key_payload *p,
/* pull migratable flag out of sealed key */
p->migratable = p->key[--p->key_len];
- tpm_buf_destroy(&tb);
return ret;
}
diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
index 024be262702f..472344c788ec 100644
--- a/security/keys/trusted-keys/trusted_tpm2.c
+++ b/security/keys/trusted-keys/trusted_tpm2.c
@@ -242,13 +242,20 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
struct trusted_key_options *options)
{
off_t offset = TPM_HEADER_SIZE;
- struct tpm_buf buf, sized;
int blob_len = 0;
u32 hash;
u32 flags;
int i;
int rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ struct tpm_buf *sized __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!sized)
+ return -ENOMEM;
+
for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
if (options->hash == tpm2_hash_map[i].crypto_id) {
hash = tpm2_hash_map[i].tpm_id;
@@ -270,89 +277,76 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
if (rc)
goto out_put;
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
- if (rc) {
- tpm2_end_auth_session(chip);
- goto out_put;
- }
-
- rc = tpm_buf_init_sized(&sized);
- if (rc) {
- tpm_buf_destroy(&buf);
- tpm2_end_auth_session(chip);
- goto out_put;
- }
-
- tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);
- tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_DECRYPT,
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
+ tpm_buf_reset_sized(sized, PAGE_SIZE);
+ tpm_buf_append_name(chip, buf, options->keyhandle, NULL);
+ tpm_buf_append_hmac_session(chip, buf, TPM2_SA_DECRYPT,
options->keyauth, TPM_DIGEST_SIZE);
/* sensitive */
- tpm_buf_append_u16(&sized, options->blobauth_len);
+ tpm_buf_append_u16(sized, options->blobauth_len);
if (options->blobauth_len)
- tpm_buf_append(&sized, options->blobauth, options->blobauth_len);
+ tpm_buf_append(sized, options->blobauth, options->blobauth_len);
- tpm_buf_append_u16(&sized, payload->key_len);
- tpm_buf_append(&sized, payload->key, payload->key_len);
- tpm_buf_append(&buf, sized.data, sized.length);
+ tpm_buf_append_u16(sized, payload->key_len);
+ tpm_buf_append(sized, payload->key, payload->key_len);
+ tpm_buf_append(buf, sized->data, sized->length);
/* public */
- tpm_buf_reset_sized(&sized);
- tpm_buf_append_u16(&sized, TPM_ALG_KEYEDHASH);
- tpm_buf_append_u16(&sized, hash);
+ tpm_buf_reset_sized(sized, PAGE_SIZE);
+ tpm_buf_append_u16(sized, TPM_ALG_KEYEDHASH);
+ tpm_buf_append_u16(sized, hash);
/* key properties */
flags = 0;
flags |= options->policydigest_len ? 0 : TPM2_OA_USER_WITH_AUTH;
flags |= payload->migratable ? 0 : (TPM2_OA_FIXED_TPM | TPM2_OA_FIXED_PARENT);
- tpm_buf_append_u32(&sized, flags);
+ tpm_buf_append_u32(sized, flags);
/* policy */
- tpm_buf_append_u16(&sized, options->policydigest_len);
+ tpm_buf_append_u16(sized, options->policydigest_len);
if (options->policydigest_len)
- tpm_buf_append(&sized, options->policydigest, options->policydigest_len);
+ tpm_buf_append(sized, options->policydigest, options->policydigest_len);
/* public parameters */
- tpm_buf_append_u16(&sized, TPM_ALG_NULL);
- tpm_buf_append_u16(&sized, 0);
+ tpm_buf_append_u16(sized, TPM_ALG_NULL);
+ tpm_buf_append_u16(sized, 0);
- tpm_buf_append(&buf, sized.data, sized.length);
+ tpm_buf_append(buf, sized->data, sized->length);
/* outside info */
- tpm_buf_append_u16(&buf, 0);
+ tpm_buf_append_u16(buf, 0);
/* creation PCR */
- tpm_buf_append_u32(&buf, 0);
+ tpm_buf_append_u32(buf, 0);
- if (buf.flags & TPM_BUF_OVERFLOW) {
+ if (buf->flags & TPM_BUF_OVERFLOW) {
rc = -E2BIG;
tpm2_end_auth_session(chip);
goto out;
}
- tpm_buf_fill_hmac_session(chip, &buf);
- rc = tpm_transmit_cmd(chip, &buf, 4, "sealing data");
- rc = tpm_buf_check_hmac_response(chip, &buf, rc);
+ tpm_buf_fill_hmac_session(chip, buf);
+ rc = tpm_transmit_cmd(chip, buf, 4, "sealing data");
+ rc = tpm_buf_check_hmac_response(chip, buf, rc);
if (rc)
goto out;
- blob_len = tpm_buf_read_u32(&buf, &offset);
- if (blob_len > MAX_BLOB_SIZE || buf.flags & TPM_BUF_BOUNDARY_ERROR) {
+ blob_len = tpm_buf_read_u32(buf, &offset);
+ if (blob_len > MAX_BLOB_SIZE || buf->flags & TPM_BUF_BOUNDARY_ERROR) {
rc = -E2BIG;
goto out;
}
- if (buf.length - offset < blob_len) {
+ if (buf->length - offset < blob_len) {
rc = -EFAULT;
goto out;
}
- blob_len = tpm2_key_encode(payload, options, &buf.data[offset], blob_len);
+ blob_len = tpm2_key_encode(payload, options, &buf->data[offset],
+ blob_len);
out:
- tpm_buf_destroy(&sized);
- tpm_buf_destroy(&buf);
-
if (rc > 0) {
if (tpm2_rc_value(rc) == TPM2_RC_HASH)
rc = -EINVAL;
@@ -387,7 +381,6 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
struct trusted_key_options *options,
u32 *blob_handle)
{
- struct tpm_buf buf;
unsigned int private_len;
unsigned int public_len;
unsigned int blob_len;
@@ -395,6 +388,10 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
int rc;
u32 attrs;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
rc = tpm2_key_decode(payload, options, &blob);
if (rc) {
/* old form */
@@ -438,35 +435,29 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
if (rc)
return rc;
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
- if (rc) {
- tpm2_end_auth_session(chip);
- return rc;
- }
-
- tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);
- tpm_buf_append_hmac_session(chip, &buf, 0, options->keyauth,
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
+ tpm_buf_append_name(chip, buf, options->keyhandle, NULL);
+ tpm_buf_append_hmac_session(chip, buf, 0, options->keyauth,
TPM_DIGEST_SIZE);
- tpm_buf_append(&buf, blob, blob_len);
+ tpm_buf_append(buf, blob, blob_len);
- if (buf.flags & TPM_BUF_OVERFLOW) {
+ if (buf->flags & TPM_BUF_OVERFLOW) {
rc = -E2BIG;
tpm2_end_auth_session(chip);
goto out;
}
- tpm_buf_fill_hmac_session(chip, &buf);
- rc = tpm_transmit_cmd(chip, &buf, 4, "loading blob");
- rc = tpm_buf_check_hmac_response(chip, &buf, rc);
+ tpm_buf_fill_hmac_session(chip, buf);
+ rc = tpm_transmit_cmd(chip, buf, 4, "loading blob");
+ rc = tpm_buf_check_hmac_response(chip, buf, rc);
if (!rc)
*blob_handle = be32_to_cpup(
- (__be32 *) &buf.data[TPM_HEADER_SIZE]);
+ (__be32 *)&buf->data[TPM_HEADER_SIZE]);
out:
if (blob != payload->blob)
kfree(blob);
- tpm_buf_destroy(&buf);
if (rc > 0)
rc = -EPERM;
@@ -491,25 +482,23 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
struct trusted_key_options *options,
u32 blob_handle)
{
- struct tpm_buf buf;
u16 data_len;
u8 *data;
int rc;
+ struct tpm_buf *buf __free(kfree) = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
rc = tpm2_start_auth_session(chip);
if (rc)
return rc;
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
- if (rc) {
- tpm2_end_auth_session(chip);
- return rc;
- }
-
- tpm_buf_append_name(chip, &buf, blob_handle, NULL);
+ tpm_buf_reset(buf, PAGE_SIZE, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
+ tpm_buf_append_name(chip, buf, blob_handle, NULL);
if (!options->policyhandle) {
- tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_ENCRYPT,
+ tpm_buf_append_hmac_session(chip, buf, TPM2_SA_ENCRYPT,
options->blobauth,
options->blobauth_len);
} else {
@@ -524,32 +513,28 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
* could repeat our actions with the exfiltrated
* password.
*/
- tpm2_buf_append_auth(&buf, options->policyhandle,
+ tpm2_buf_append_auth(buf, options->policyhandle,
NULL /* nonce */, 0, 0,
options->blobauth, options->blobauth_len);
- tpm_buf_append_hmac_session_opt(chip, &buf, TPM2_SA_ENCRYPT,
+ tpm_buf_append_hmac_session_opt(chip, buf, TPM2_SA_ENCRYPT,
NULL, 0);
}
- tpm_buf_fill_hmac_session(chip, &buf);
- rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing");
- rc = tpm_buf_check_hmac_response(chip, &buf, rc);
+ tpm_buf_fill_hmac_session(chip, buf);
+ rc = tpm_transmit_cmd(chip, buf, 6, "unsealing");
+ rc = tpm_buf_check_hmac_response(chip, buf, rc);
if (rc > 0)
rc = -EPERM;
if (!rc) {
data_len = be16_to_cpup(
- (__be16 *) &buf.data[TPM_HEADER_SIZE + 4]);
- if (data_len < MIN_KEY_SIZE || data_len > MAX_KEY_SIZE) {
- rc = -EFAULT;
- goto out;
- }
+ (__be16 *)&buf->data[TPM_HEADER_SIZE + 4]);
+ if (data_len < MIN_KEY_SIZE || data_len > MAX_KEY_SIZE)
+ return -EFAULT;
- if (tpm_buf_length(&buf) < TPM_HEADER_SIZE + 6 + data_len) {
- rc = -EFAULT;
- goto out;
- }
- data = &buf.data[TPM_HEADER_SIZE + 6];
+ if (tpm_buf_length(buf) < TPM_HEADER_SIZE + 6 + data_len)
+ return -EFAULT;
+ data = &buf->data[TPM_HEADER_SIZE + 6];
if (payload->old_format) {
/* migratable flag is at the end of the key */
@@ -566,8 +551,6 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
}
}
-out:
- tpm_buf_destroy(&buf);
return rc;
}
--
2.39.5
^ permalink raw reply related
* Re: [PATCH] pid: use ns_capable_noaudit() when determining net sysctl permissions
From: Christian Brauner @ 2025-09-19 11:08 UTC (permalink / raw)
To: linux-kernel, Christian Göttsche
Cc: Christian Brauner, Christian Göttsche, linux-security-module,
selinux
In-Reply-To: <20250910192605.16431-1-cgoettsche@seltendoof.de>
On Wed, 10 Sep 2025 21:26:05 +0200, Christian Göttsche wrote:
> The capability check should not be audited since it is only being used
> to determine the inode permissions. A failed check does not indicate a
> violation of security policy but, when an LSM is enabled, a denial audit
> message was being generated.
>
> The denial audit message can either lead to the capability being
> unnecessarily allowed in a security policy, or being silenced potentially
> masking a legitimate capability check at a later point in time.
>
> [...]
Applied to the vfs-6.18.misc branch of the vfs/vfs.git tree.
Patches in the vfs-6.18.misc branch should appear in linux-next soon.
Please report any outstanding bugs that were missed during review in a
new review to the original patch series allowing us to drop it.
It's encouraged to provide Acked-bys and Reviewed-bys even though the
patch has now been applied. If possible patch trailers will be updated.
Note that commit hashes shown below are subject to change due to rebase,
trailer updates or similar. If in doubt, please check the listed branch.
tree: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git
branch: vfs-6.18.misc
[1/1] pid: use ns_capable_noaudit() when determining net sysctl permissions
https://git.kernel.org/vfs/vfs/c/b9cb7e59ac4a
^ permalink raw reply
* Re: [PATCH v4 07/34] lsm: rename ordered_lsm_init() to lsm_init_ordered()
From: Mimi Zohar @ 2025-09-19 10:45 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: John Johansen, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250916220355.252592-43-paul@paul-moore.com>
On Tue, 2025-09-16 at 18:03 -0400, Paul Moore wrote:
> The new name more closely fits the rest of the naming scheme in
> security/lsm_init.c. This patch also adds a trivial comment block to
> the top of the function.
>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> Reviewed-by: John Johansen <john.johhansen@canonical.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
> security/lsm_init.c | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index a8b82329c76a..4a108b03c23d 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -291,7 +291,10 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> kfree(sep);
> }
>
> -static void __init ordered_lsm_init(void)
> +/**
> + * lsm_init_ordered - Initialize the ordered LSMs
> + */
> +static void __init lsm_init_ordered(void)
> {
> unsigned int first = 0;
> struct lsm_info **lsm;
> @@ -342,9 +345,6 @@ static void __init ordered_lsm_init(void)
> init_debug("bpf prog blob size = %d\n", blob_sizes.lbs_bpf_prog);
> init_debug("bpf token blob size = %d\n", blob_sizes.lbs_bpf_token);
>
> - /*
> - * Create any kmem_caches needed for blobs
> - */
> if (blob_sizes.lbs_file)
> lsm_file_cache = kmem_cache_create("lsm_file_cache",
> blob_sizes.lbs_file, 0,
> @@ -498,7 +498,7 @@ int __init security_init(void)
> }
>
> /* Load LSMs in specified order. */
> - ordered_lsm_init();
> + lsm_init_ordered();
>
> return 0;
> }
^ permalink raw reply
* Re: [PATCH v4 06/34] lsm: integrate lsm_early_cred() and lsm_early_task() into caller
From: Mimi Zohar @ 2025-09-19 10:45 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: John Johansen, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250916220355.252592-42-paul@paul-moore.com>
On Tue, 2025-09-16 at 18:03 -0400, Paul Moore wrote:
> With only one caller of lsm_early_cred() and lsm_early_task(), insert
> the functions' code directly into the caller and ger rid of the two
> functions.
>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> Reviewed-by: John Johansen <john.johhansen@canonical.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
> security/lsm_init.c | 35 +++++------------------------------
> 1 file changed, 5 insertions(+), 30 deletions(-)
>
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 09afa7ad719e..a8b82329c76a 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -291,34 +291,6 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> kfree(sep);
> }
>
> -/**
> - * lsm_early_cred - during initialization allocate a composite cred blob
> - * @cred: the cred that needs a blob
> - *
> - * Allocate the cred blob for all the modules
> - */
> -static void __init lsm_early_cred(struct cred *cred)
> -{
> - int rc = lsm_cred_alloc(cred, GFP_KERNEL);
> -
> - if (rc)
> - panic("%s: Early cred alloc failed.\n", __func__);
> -}
> -
> -/**
> - * lsm_early_task - during initialization allocate a composite task blob
> - * @task: the task that needs a blob
> - *
> - * Allocate the task blob for all the modules
> - */
> -static void __init lsm_early_task(struct task_struct *task)
> -{
> - int rc = lsm_task_alloc(task);
> -
> - if (rc)
> - panic("%s: Early task alloc failed.\n", __func__);
> -}
> -
> static void __init ordered_lsm_init(void)
> {
> unsigned int first = 0;
> @@ -382,8 +354,11 @@ static void __init ordered_lsm_init(void)
> blob_sizes.lbs_inode, 0,
> SLAB_PANIC, NULL);
>
> - lsm_early_cred((struct cred *) current->cred);
> - lsm_early_task(current);
> + if (lsm_cred_alloc((struct cred *)current->cred, GFP_KERNEL))
> + panic("%s: early cred alloc failed.\n", __func__);
> + if (lsm_task_alloc(current))
> + panic("%s: early task alloc failed.\n", __func__);
> +
> lsm_order_for_each(lsm) {
> initialize_lsm(*lsm);
> }
^ permalink raw reply
* Re: [PATCH v4 05/34] lsm: integrate report_lsm_order() code into caller
From: Mimi Zohar @ 2025-09-19 10:45 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: John Johansen, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250916220355.252592-41-paul@paul-moore.com>
On Tue, 2025-09-16 at 18:03 -0400, Paul Moore wrote:
> With only one caller of report_lsm_order(), insert the function's code
> directly into the caller and ger rid of report_lsm_order().
>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> Reviewed-by: John Johansen <john.johhansen@canonical.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
> security/lsm_init.c | 33 ++++++++++++---------------------
> 1 file changed, 12 insertions(+), 21 deletions(-)
>
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 18828a65c364..09afa7ad719e 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -291,26 +291,6 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> kfree(sep);
> }
>
> -static void __init report_lsm_order(void)
> -{
> - struct lsm_info **lsm, *early;
> - int first = 0;
> -
> - pr_info("initializing lsm=");
> -
> - /* Report each enabled LSM name, comma separated. */
> - lsm_early_for_each_raw(early) {
> - if (is_enabled(early))
> - pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
> - }
> - lsm_order_for_each(lsm) {
> - if (is_enabled(*lsm))
> - pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
> - }
> -
> - pr_cont("\n");
> -}
> -
> /**
> * lsm_early_cred - during initialization allocate a composite cred blob
> * @cred: the cred that needs a blob
> @@ -341,7 +321,9 @@ static void __init lsm_early_task(struct task_struct *task)
>
> static void __init ordered_lsm_init(void)
> {
> + unsigned int first = 0;
> struct lsm_info **lsm;
> + struct lsm_info *early;
>
> if (chosen_lsm_order) {
> if (chosen_major_lsm) {
> @@ -357,7 +339,16 @@ static void __init ordered_lsm_init(void)
> lsm_prepare(*lsm);
> }
>
> - report_lsm_order();
> + pr_info("initializing lsm=");
> + lsm_early_for_each_raw(early) {
> + if (is_enabled(early))
> + pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
> + }
> + lsm_order_for_each(lsm) {
> + if (is_enabled(*lsm))
> + pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
> + }
> + pr_cont("\n");
>
> init_debug("cred blob size = %d\n", blob_sizes.lbs_cred);
> init_debug("file blob size = %d\n", blob_sizes.lbs_file);
^ permalink raw reply
* Re: [PATCH v4 04/34] lsm: introduce looping macros for the initialization code
From: Mimi Zohar @ 2025-09-19 10:45 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: John Johansen, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250916220355.252592-40-paul@paul-moore.com>
On Tue, 2025-09-16 at 18:03 -0400, Paul Moore wrote:
> There are three common for loop patterns in the LSM initialization code
> to loop through the ordered LSM list and the registered "early" LSMs.
> This patch implements these loop patterns as macros to help simplify the
> code and reduce the chance for errors.
>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> Reviewed-by: John Johansen <john.johhansen@canonical.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
> security/lsm_init.c | 42 +++++++++++++++++++++++++++---------------
> 1 file changed, 27 insertions(+), 15 deletions(-)
>
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 6f40ab1d2f54..18828a65c364 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -32,6 +32,15 @@ static __initdata bool debug;
> pr_info(__VA_ARGS__); \
> } while (0)
>
> +#define lsm_order_for_each(iter) \
> + for ((iter) = ordered_lsms; *(iter); (iter)++)
> +#define lsm_for_each_raw(iter) \
> + for ((iter) = __start_lsm_info; \
> + (iter) < __end_lsm_info; (iter)++)
> +#define lsm_early_for_each_raw(iter) \
> + for ((iter) = __start_early_lsm_info; \
> + (iter) < __end_early_lsm_info; (iter)++)
> +
> static int lsm_append(const char *new, char **result);
>
> /* Save user chosen LSM */
> @@ -96,9 +105,10 @@ static bool __init exists_ordered_lsm(struct lsm_info *lsm)
> {
> struct lsm_info **check;
>
> - for (check = ordered_lsms; *check; check++)
> + lsm_order_for_each(check) {
> if (*check == lsm)
> return true;
> + }
>
> return false;
> }
> @@ -209,7 +219,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> char *sep, *name, *next;
>
> /* LSM_ORDER_FIRST is always first. */
> - for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> + lsm_for_each_raw(lsm) {
> if (lsm->order == LSM_ORDER_FIRST)
> append_ordered_lsm(lsm, " first");
> }
> @@ -224,8 +234,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> * if the selected one was separately disabled: disable
> * all non-matching Legacy Major LSMs.
> */
> - for (major = __start_lsm_info; major < __end_lsm_info;
> - major++) {
> + lsm_for_each_raw(major) {
> if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
> strcmp(major->name, chosen_major_lsm) != 0) {
> set_enabled(major, false);
> @@ -241,7 +250,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> while ((name = strsep(&next, ",")) != NULL) {
> bool found = false;
>
> - for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> + lsm_for_each_raw(lsm) {
> if (strcmp(lsm->name, name) == 0) {
> if (lsm->order == LSM_ORDER_MUTABLE)
> append_ordered_lsm(lsm, origin);
> @@ -256,7 +265,7 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
>
> /* Process "security=", if given. */
> if (chosen_major_lsm) {
> - for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> + lsm_for_each_raw(lsm) {
> if (exists_ordered_lsm(lsm))
> continue;
> if (strcmp(lsm->name, chosen_major_lsm) == 0)
> @@ -265,13 +274,13 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
> }
>
> /* LSM_ORDER_LAST is always last. */
> - for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> + lsm_for_each_raw(lsm) {
> if (lsm->order == LSM_ORDER_LAST)
> append_ordered_lsm(lsm, " last");
> }
>
> /* Disable all LSMs not in the ordered list. */
> - for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
> + lsm_for_each_raw(lsm) {
> if (exists_ordered_lsm(lsm))
> continue;
> set_enabled(lsm, false);
> @@ -290,13 +299,14 @@ static void __init report_lsm_order(void)
> pr_info("initializing lsm=");
>
> /* Report each enabled LSM name, comma separated. */
> - for (early = __start_early_lsm_info;
> - early < __end_early_lsm_info; early++)
> + lsm_early_for_each_raw(early) {
> if (is_enabled(early))
> pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
> - for (lsm = ordered_lsms; *lsm; lsm++)
> + }
> + lsm_order_for_each(lsm) {
> if (is_enabled(*lsm))
> pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
> + }
>
> pr_cont("\n");
> }
> @@ -343,8 +353,9 @@ static void __init ordered_lsm_init(void)
> } else
> ordered_lsm_parse(builtin_lsm_order, "builtin");
>
> - for (lsm = ordered_lsms; *lsm; lsm++)
> + lsm_order_for_each(lsm) {
> lsm_prepare(*lsm);
> + }
>
> report_lsm_order();
>
> @@ -382,8 +393,9 @@ static void __init ordered_lsm_init(void)
>
> lsm_early_cred((struct cred *) current->cred);
> lsm_early_task(current);
> - for (lsm = ordered_lsms; *lsm; lsm++)
> + lsm_order_for_each(lsm) {
> initialize_lsm(*lsm);
> + }
> }
>
> static bool match_last_lsm(const char *list, const char *lsm)
> @@ -485,7 +497,7 @@ int __init early_security_init(void)
> {
> struct lsm_info *lsm;
>
> - for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
> + lsm_early_for_each_raw(lsm) {
> if (!lsm->enabled)
> lsm->enabled = &lsm_enabled_true;
> lsm_prepare(lsm);
> @@ -512,7 +524,7 @@ int __init security_init(void)
> * Append the names of the early LSM modules now that kmalloc() is
> * available
> */
> - for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
> + lsm_early_for_each_raw(lsm) {
> init_debug(" early started: %s (%s)\n", lsm->name,
> is_enabled(lsm) ? "enabled" : "disabled");
> if (lsm->enabled)
^ permalink raw reply
* Re: [PATCH v4 03/34] lsm: consolidate lsm_allowed() and prepare_lsm() into lsm_prepare()
From: Mimi Zohar @ 2025-09-19 10:45 UTC (permalink / raw)
To: Paul Moore, linux-security-module, linux-integrity, selinux
Cc: John Johansen, Roberto Sassu, Fan Wu, Mickaël Salaün,
Günther Noack, Kees Cook, Micah Morton, Casey Schaufler,
Tetsuo Handa, Nicolas Bouchinet, Xiu Jianfeng
In-Reply-To: <20250916220355.252592-39-paul@paul-moore.com>
On Tue, 2025-09-16 at 18:03 -0400, Paul Moore wrote:
> Simplify and consolidate the lsm_allowed() and prepare_lsm() functions
> into a new function, lsm_prepare().
>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
> Reviewed-by: John Johansen <john.johhansen@canonical.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
> security/lsm_init.c | 109 +++++++++++++++++++-------------------------
> 1 file changed, 46 insertions(+), 63 deletions(-)
>
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 124213b906af..6f40ab1d2f54 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -123,22 +123,6 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
> is_enabled(lsm) ? "enabled" : "disabled");
> }
>
> -/* Is an LSM allowed to be initialized? */
> -static bool __init lsm_allowed(struct lsm_info *lsm)
> -{
> - /* Skip if the LSM is disabled. */
> - if (!is_enabled(lsm))
> - return false;
> -
> - /* Not allowed if another exclusive LSM already initialized. */
> - if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
> - init_debug("exclusive disabled: %s\n", lsm->name);
> - return false;
> - }
> -
> - return true;
> -}
> -
> static void __init lsm_set_blob_size(int *need, int *lbs)
> {
> int offset;
> @@ -151,54 +135,53 @@ static void __init lsm_set_blob_size(int *need, int *lbs)
> *need = offset;
> }
>
> -static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
> +/**
> + * lsm_prepare - Prepare the LSM framework for a new LSM
> + * @lsm: LSM definition
> + */
> +static void __init lsm_prepare(struct lsm_info *lsm)
> {
> - if (!needed)
> + struct lsm_blob_sizes *blobs;
> +
> + if (!is_enabled(lsm)) {
> + set_enabled(lsm, false);
> + return;
> + } else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
> + init_debug("exclusive disabled: %s\n", lsm->name);
> + set_enabled(lsm, false);
> return;
> -
> - lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
> - lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file);
> - lsm_set_blob_size(&needed->lbs_ib, &blob_sizes.lbs_ib);
> - /*
> - * The inode blob gets an rcu_head in addition to
> - * what the modules might need.
> - */
> - if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
> - blob_sizes.lbs_inode = sizeof(struct rcu_head);
> - lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
> - lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
> - lsm_set_blob_size(&needed->lbs_key, &blob_sizes.lbs_key);
> - lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
> - lsm_set_blob_size(&needed->lbs_perf_event, &blob_sizes.lbs_perf_event);
> - lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
> - lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
> - lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
> - lsm_set_blob_size(&needed->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
> - lsm_set_blob_size(&needed->lbs_xattr_count,
> - &blob_sizes.lbs_xattr_count);
> - lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev);
> - lsm_set_blob_size(&needed->lbs_bpf_map, &blob_sizes.lbs_bpf_map);
> - lsm_set_blob_size(&needed->lbs_bpf_prog, &blob_sizes.lbs_bpf_prog);
> - lsm_set_blob_size(&needed->lbs_bpf_token, &blob_sizes.lbs_bpf_token);
> -}
> -
> -/* Prepare LSM for initialization. */
> -static void __init prepare_lsm(struct lsm_info *lsm)
> -{
> - int enabled = lsm_allowed(lsm);
> -
> - /* Record enablement (to handle any following exclusive LSMs). */
> - set_enabled(lsm, enabled);
> -
> - /* If enabled, do pre-initialization work. */
> - if (enabled) {
> - if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
> - exclusive = lsm;
> - init_debug("exclusive chosen: %s\n", lsm->name);
> - }
> -
> - lsm_set_blob_sizes(lsm->blobs);
> }
> +
> + /* Mark the LSM as enabled. */
> + set_enabled(lsm, true);
> + if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
> + init_debug("exclusive chosen: %s\n", lsm->name);
> + exclusive = lsm;
> + }
> +
> + /* Register the LSM blob sizes. */
> + blobs = lsm->blobs;
> + lsm_set_blob_size(&blobs->lbs_cred, &blob_sizes.lbs_cred);
> + lsm_set_blob_size(&blobs->lbs_file, &blob_sizes.lbs_file);
> + lsm_set_blob_size(&blobs->lbs_ib, &blob_sizes.lbs_ib);
> + /* inode blob gets an rcu_head in addition to LSM blobs. */
> + if (blobs->lbs_inode && blob_sizes.lbs_inode == 0)
> + blob_sizes.lbs_inode = sizeof(struct rcu_head);
> + lsm_set_blob_size(&blobs->lbs_inode, &blob_sizes.lbs_inode);
> + lsm_set_blob_size(&blobs->lbs_ipc, &blob_sizes.lbs_ipc);
> + lsm_set_blob_size(&blobs->lbs_key, &blob_sizes.lbs_key);
> + lsm_set_blob_size(&blobs->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
> + lsm_set_blob_size(&blobs->lbs_perf_event, &blob_sizes.lbs_perf_event);
> + lsm_set_blob_size(&blobs->lbs_sock, &blob_sizes.lbs_sock);
> + lsm_set_blob_size(&blobs->lbs_superblock, &blob_sizes.lbs_superblock);
> + lsm_set_blob_size(&blobs->lbs_task, &blob_sizes.lbs_task);
> + lsm_set_blob_size(&blobs->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
> + lsm_set_blob_size(&blobs->lbs_xattr_count,
> + &blob_sizes.lbs_xattr_count);
> + lsm_set_blob_size(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
> + lsm_set_blob_size(&blobs->lbs_bpf_map, &blob_sizes.lbs_bpf_map);
> + lsm_set_blob_size(&blobs->lbs_bpf_prog, &blob_sizes.lbs_bpf_prog);
> + lsm_set_blob_size(&blobs->lbs_bpf_token, &blob_sizes.lbs_bpf_token);
> }
>
> /* Initialize a given LSM, if it is enabled. */
> @@ -361,7 +344,7 @@ static void __init ordered_lsm_init(void)
> ordered_lsm_parse(builtin_lsm_order, "builtin");
>
> for (lsm = ordered_lsms; *lsm; lsm++)
> - prepare_lsm(*lsm);
> + lsm_prepare(*lsm);
>
> report_lsm_order();
>
> @@ -505,7 +488,7 @@ int __init early_security_init(void)
> for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
> if (!lsm->enabled)
> lsm->enabled = &lsm_enabled_true;
> - prepare_lsm(lsm);
> + lsm_prepare(lsm);
> initialize_lsm(lsm);
> }
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox