public inbox for linux-coco@lists.linux.dev
 help / color / mirror / Atom feed
From: "Edgecombe, Rick P" <rick.p.edgecombe@intel.com>
To: "Gao, Chao" <chao.gao@intel.com>
Cc: "kvm@vger.kernel.org" <kvm@vger.kernel.org>,
	"Li, Xiaoyao" <xiaoyao.li@intel.com>,
	"linux-coco@lists.linux.dev" <linux-coco@lists.linux.dev>,
	"Huang, Kai" <kai.huang@intel.com>,
	"x86@kernel.org" <x86@kernel.org>,
	"Zhao, Yan Y" <yan.y.zhao@intel.com>,
	"dave.hansen@linux.intel.com" <dave.hansen@linux.intel.com>,
	"kas@kernel.org" <kas@kernel.org>,
	"mingo@redhat.com" <mingo@redhat.com>,
	"Weiny, Ira" <ira.weiny@intel.com>,
	"pbonzini@redhat.com" <pbonzini@redhat.com>,
	"Chatre, Reinette" <reinette.chatre@intel.com>,
	"Verma, Vishal L" <vishal.l.verma@intel.com>,
	"nik.borisov@suse.com" <nik.borisov@suse.com>,
	"seanjc@google.com" <seanjc@google.com>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"binbin.wu@linux.intel.com" <binbin.wu@linux.intel.com>,
	"Annapurve, Vishal" <vannapurve@google.com>,
	"hpa@zytor.com" <hpa@zytor.com>,
	"sagis@google.com" <sagis@google.com>,
	"tony.lindgren@linux.intel.com" <tony.lindgren@linux.intel.com>,
	"paulmck@kernel.org" <paulmck@kernel.org>,
	"tglx@kernel.org" <tglx@kernel.org>,
	"yilun.xu@linux.intel.com" <yilun.xu@linux.intel.com>,
	"dan.j.williams@intel.com" <dan.j.williams@intel.com>,
	"bp@alien8.de" <bp@alien8.de>
Subject: Re: [PATCH v7 08/22] x86/virt/seamldr: Allocate and populate a module update request
Date: Tue, 14 Apr 2026 17:37:40 +0000	[thread overview]
Message-ID: <1016261178d32a5c6f20d1507f28388dd01a15df.camel@intel.com> (raw)
In-Reply-To: <ad4MWR0DyOaI0C50@intel.com>

On Tue, 2026-04-14 at 17:43 +0800, Chao Gao wrote:
> On Sat, Apr 11, 2026 at 09:14:36AM +0800, Edgecombe, Rick P wrote:
> > On Tue, 2026-03-31 at 05:41 -0700, Chao Gao wrote:
> > > P-SEAMLDR uses the SEAMLDR_PARAMS structure to describe TDX module
> > > update requests. This structure contains physical addresses pointing to
> > > the module binary and its signature file (or sigstruct), along with an
> > > update scenario field.
> > > 
> > > TDX modules are distributed in the tdx_blob format defined in
> > > blob_structure.txt from the "Intel TDX module Binaries Repository". A
> > > tdx_blob contains a header, sigstruct, and module binary. This is also the
> > > format supplied by the userspace to the kernel.
> > > 
> > > Parse the tdx_blob format and populate a SEAMLDR_PARAMS structure
> > > accordingly. This structure will be passed to P-SEAMLDR to initiate the
> > > update.
> > 
> > The thing that confused me about this earlier was the exact reason why we are
> > checking all the fields. We discussed that we need to check the fields that
> > kernel processes, but we don't need to double check data that the TDX module
> > processes.
> > 
> > Should we explain it?
> 
> Yes. how about adding the following in the changelog:
> 
> Parse the tdx_blob format and populate a SEAMLDR_PARAMS structure. The
> header is consumed solely by the kernel to extract the sigstruct and
> module, so validate it before processing. The sigstruct and module are
> passed to and validated by P-SEAMLDR, so don't duplicate any validation
> in the kernel.

Looks good.

> 
> > And how it explains the checks below?
> 
> 
> > > +static void free_seamldr_params(struct seamldr_params *params)
> > > +{
> > > +	free_page((unsigned long)params);
> > > +}
> > 
> > Do we really need this helper? This doesn't work?
> 
> No. This works. Will do.
> 
> > 
> > DEFINE_FREE(free_seamldr_params, struct seamldr_params *,
> > 	    if (!IS_ERR_OR_NULL(_T)) free_page((unsigned long)_T))
> > 
> > 
> > > +
> > > +static struct seamldr_params *alloc_seamldr_params(const void *module, unsigned int module_size,
> > > +						   const void *sig, unsigned int sig_size)
> > > +{
> > > +	struct seamldr_params *params;
> > > +	const u8 *ptr;
> > > +	int i;
> > > +
> > > +	if (module_size > SEAMLDR_MAX_NR_MODULE_4KB_PAGES * SZ_4K)
> > > +		return ERR_PTR(-EINVAL);
> > > +
> > > +	if (sig_size > SEAMLDR_MAX_NR_SIG_4KB_PAGES * SZ_4K)
> > > +		return ERR_PTR(-EINVAL);
> > 
> > I don't know if it's worth that much, but we could do a MIN thing here to
> > protect the loop, and lose the conditionals. If userspace passes a blob that is
> > out of spec they can deal with the module error, no?
> 
> I think we all agree: we need to do something to protect the loop. So, the
> question is just how.
> 
> looks like you prefer:
> 
> 	module_size = MIN(module_size, SEAMLDR_MAX_NR_MODULE_4KB_PAGES * SZ_4K);
> 	sig_size = MIN(sig_size, SEAMLDR_MAX_NR_SIG_4KB_PAGES * SZ_4K);
> 
> But I think the MIN approach actually requires more justification than a plain
> bounds check.
> 
> With MIN, the reasoning chain is: we don't want conditionals -> userspace
> can deal with the module error -> and that error won't be fatal to the
> system (or even if it is, it's admin-initiated). That's a lot of assumptions
> to validate.
> 
> With a bounds check and early return, the reasoning is simply: the input is out
> of range -> reject it as invalid.

Hmm, I'm convinced. I think a lot of tip code elides conditionals. I'm not sure
which they would prefer.

I guess the problem I see is that all these conditionals seem like a lot for
something that is mostly just getting passed through. So they need to come
across better somehow.

> 
> > 
> > > +
> > > +	/*
> > > +	 * Check that input buffers satisfy P-SEAMLDR's size and alignment
> > > +	 * constraints so they can be passed directly to P-SEAMLDR without
> > > +	 * relocation or copy.
> > > +	 */
> > > +	if (!IS_ALIGNED(module_size, SZ_4K) || !IS_ALIGNED(sig_size, SZ_4K) ||
> > > +	    !IS_ALIGNED((unsigned long)module, SZ_4K) ||
> > > +	    !IS_ALIGNED((unsigned long)sig, SZ_4K))
> > > +		return ERR_PTR(-EINVAL);
> > 
> > I thought you are going to reduce this checking to just to reject invalid input
> > that the kernel processes.
> > 
> > What happens if we don't check this?
> 
> If the blob->offset_of_module or blob->size is misaligned, the loops
> silently drop the unaligned portion. P-SEAMLDR will then reject the update
> after module shutdown and TDs will be killed. Since this is admin-initiated
> with an intentionally invalid blob, the consequence is acceptable.

Seems like we could drop it then.

> 
> > The vmallocs are all going to be page
> > aligned anyway. But even still, does it mess up the below loops somehow in a way
> > that hurts anything?
> 
> I agree addresses/sizes are page-aligned for valid blobs, but they are not
> guaranteed (e.g., if offset_of_module is misaligned) for all inputs. I
> removed the check once in v6 and Sashiko questioned it, so I thought the
> assumption isn't obviously correct to everyone.

Haha, as impressed as I am with AI code review... are we already at the point of
adding comments to help the AI not get confused?

> 
> Without the check, we'd need something like:
> 
> 	/*
> 	 * Assume sig/module base addresses and sizes are page-aligned.
> 	 * If violated, P-SEAMLDR will reject the update.
> 	 */
> 
> It's a few lines of straightforward validation vs. a comment that requires
> readers to verify the assumption chain (vmalloc internals, userspace
> contract, P-SEAMLDR behavior). Not sure the trade is worth it.
> 
> If you think the comment is sufficient, I'm fine dropping the checks.

The checks seem like too much. Any ideas on how to contain it more? It seems
like you are making the case for each one. But if we delete them all... does it
seem like a better tradeoff?

> 
> > 
> > I might be confused, but it seems different then we discussed.
> > 
> > > +
> > > +	params = (struct seamldr_params *)get_zeroed_page(GFP_KERNEL);
> > > +	if (!params)
> > > +		return ERR_PTR(-ENOMEM);
> > > +
> > > +	/*
> > > +	 * Only use version 1 when required (sigstruct > 4KB) for backward
> > > +	 * compatibility with P-SEAMLDR that lacks version 1 support.
> > > +	 */
> > > +	if (sig_size > SZ_4K)
> > > +		params->version = 1;
> > > +	else
> > > +		params->version = 0;
> > 
> > I'm a bit confused by this part. What does it mean to support old P-SEAMLDRs?
> 
> All current P-SEAMLDRs only support version 0. Version 1 is a planned
> extension but not yet implemented by any P-SEAMLDR. Always requiring
> version 1 just saves us a conditional but disables updates for all existing
> P-SEAMLDRs for no reason. I think it is not worthwhile.

Sorry, I still don't understand. Why does the kernel need to set this bit? It's
an opt-in for a format change? How many old TDX modules are we talking?

I think, connecting to the discussion in the later patches, that we should try
to keep the initial implementation as small as possible. Everything we add makes
things take a little bit longer. And while we spin new versions the kernel has
zero support. So I see that this is another non-critical enhancement.

> 
> > But also could it be:
> > 
> > params->version = sig_size > SZ_4K;
> 
> ok with me. I just wanted to make it match with "version 1" in the
> comment right above.
> 
> > > +static struct seamldr_params *init_seamldr_params(const u8 *data, u32 size)
> > > +{
> > > +	const struct tdx_blob *blob = (const void *)data;
> > > +	int module_size, sig_size;
> > > +	const void *sig, *module;
> > > +
> > > +	/*
> > > +	 * Ensure the size is valid otherwise reading any field from the
> > > +	 * blob may overflow.
> > > +	 */
> > > +	if (size <= sizeof(struct tdx_blob) || size <= blob->offset_of_module)
> > > +		return ERR_PTR(-EINVAL);
> > > +
> > > +	if (blob->version != TDX_BLOB_VERSION_1)
> > > +		return ERR_PTR(-EINVAL);
> > > +
> > > +	if (blob->reserved0 || memchr_inv(blob->reserved1, 0, sizeof(blob->reserved1)))
> > > +		return ERR_PTR(-EINVAL);
> > > +
> > > +	/* Split the blob into a sigstruct and a module. */
> > > +	sig		= blob->data;
> > > +	sig_size	= blob->offset_of_module - sizeof(struct tdx_blob);
> > > +	module		= data + blob->offset_of_module;
> > > +	module_size	= size - blob->offset_of_module;
> > 
> > Did you consider just passing the tdx_blob into alloc_seamldr_params()?
> > Basically, this function checks the blob fields, then alloc_seamldr_params()
> > turns blob into  struct seamldr_params without checks. The way it is, the work
> > seems kind of spread around two functions with various checks.
> 
> Fine with merging them. 
> 

I wasn't suggesting to merge them. I was suggesting to have them each do a
dedicated thing.

> How about:
> 
> static struct seamldr_params *alloc_seamldr_params(const u8 *data, u32 size)
> {
> 	const struct tdx_blob *blob = (const void *)data;
> 	struct seamldr_params *params;
> 	int module_size, sig_size;
> 	const void *sig, *module;
> 	const u8 *ptr;
> 	int i;
> 
> 	/*
> 	 * Ensure the size is valid otherwise reading any field from the
> 	 * blob may overflow.
> 	 */
> 	if (size <= sizeof(struct tdx_blob))
> 		return ERR_PTR(-EINVAL);
> 
> 	if (blob->version != TDX_BLOB_VERSION_1)
> 		return ERR_PTR(-EINVAL);
> 	
> 	if (blob->length != size)
> 		return ERR_PTR(-EINVAL);
> 
> 	if (memcmp(blob->signature, "TDX-BLOB", 8))
> 		return ERR_PTR(-EINVAL);
> 
> 	if (blob->reserved0 || memchr_inv(blob->reserved1, 0, sizeof(blob->reserved1)))
> 		return ERR_PTR(-EINVAL);
> 
> 	/* Split the blob into a sigstruct and a module. */
> 	sig		= blob->data;
> 	sig_size	= blob->offset_of_module - sizeof(struct tdx_blob);
> 	module		= data + blob->offset_of_module;
> 	module_size	= size - blob->offset_of_module;
> 
> 	if (module_size > SEAMLDR_MAX_NR_MODULE_4KB_PAGES * SZ_4K || module_size <= 0)
> 		return ERR_PTR(-EINVAL);
> 
> 	if (sig_size > SEAMLDR_MAX_NR_SIG_4KB_PAGES * SZ_4K || sig_size <= 0)
> 		return ERR_PTR(-EINVAL);
> 
> 	params = (struct seamldr_params *)get_zeroed_page(GFP_KERNEL);
> 	if (!params)
> 		return ERR_PTR(-ENOMEM);
> 
> 	/*
> 	 * Only use version 1 when required (sigstruct > 4KB) for backward
> 	 * compatibility with P-SEAMLDR that lacks version 1 support.
> 	 */
> 	params->version = sig_size > SZ_4K;
> 	params->scenario = SEAMLDR_SCENARIO_UPDATE;
> 
> 	ptr = sig;
> 	/*
> 	 * Assume sig/module base addresses and sizes are page-aligned.
> 	 * If violated, P-SEAMLDR will reject the update.
> 	 */
> 	for (i = 0; i < sig_size / SZ_4K; i++) {
> 		params->sigstruct_pa[i] = vmalloc_to_pfn(ptr) << PAGE_SHIFT;
> 		ptr += SZ_4K;
> 	}
> 
> 	params->num_module_pages = module_size / SZ_4K;
> 
> 	ptr = module;
> 	for (i = 0; i < params->num_module_pages; i++) {
> 		params->mod_pages_pa_list[i] = vmalloc_to_pfn(ptr) << PAGE_SHIFT;
> 		ptr += SZ_4K;
> 	}
> 
> 	return params;
> }


  reply	other threads:[~2026-04-14 17:37 UTC|newest]

Thread overview: 77+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-31 12:41 [PATCH v7 00/22] Runtime TDX module update support Chao Gao
2026-03-31 12:41 ` [PATCH v7 01/22] x86/virt/tdx: Move low level SEAMCALL helpers out of <asm/tdx.h> Chao Gao
2026-04-10 23:42   ` Edgecombe, Rick P
2026-03-31 12:41 ` [PATCH v7 02/22] coco/tdx-host: Introduce a "tdx_host" device Chao Gao
2026-03-31 12:41 ` [PATCH v7 03/22] coco/tdx-host: Expose TDX module version Chao Gao
2026-03-31 12:41 ` [PATCH v7 04/22] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs Chao Gao
2026-04-10 23:58   ` Edgecombe, Rick P
2026-03-31 12:41 ` [PATCH v7 05/22] x86/virt/seamldr: Add a helper to retrieve P-SEAMLDR information Chao Gao
2026-04-11  0:13   ` Edgecombe, Rick P
2026-03-31 12:41 ` [PATCH v7 06/22] coco/tdx-host: Expose P-SEAMLDR information via sysfs Chao Gao
2026-03-31 14:58   ` Dave Hansen
2026-04-01  1:57     ` Chao Gao
2026-03-31 14:58   ` Dave Hansen
2026-04-01  2:25     ` Chao Gao
2026-04-13 19:08   ` Edgecombe, Rick P
2026-04-14 11:20     ` Chao Gao
2026-04-14 17:02       ` Edgecombe, Rick P
2026-03-31 12:41 ` [PATCH v7 07/22] coco/tdx-host: Implement firmware upload sysfs ABI for TDX module updates Chao Gao
2026-03-31 15:04   ` Dave Hansen
2026-04-01  3:10     ` Chao Gao
2026-03-31 15:11   ` Dave Hansen
2026-04-01  7:49     ` Chao Gao
2026-04-11  0:26   ` Edgecombe, Rick P
2026-04-14  9:50     ` Chao Gao
2026-04-14 17:04       ` Edgecombe, Rick P
2026-03-31 12:41 ` [PATCH v7 08/22] x86/virt/seamldr: Allocate and populate a module update request Chao Gao
2026-03-31 15:44   ` Dave Hansen
2026-04-01  8:27     ` Chao Gao
2026-04-11  0:33       ` Edgecombe, Rick P
2026-04-11  1:14   ` Edgecombe, Rick P
2026-04-14  9:43     ` Chao Gao
2026-04-14 17:37       ` Edgecombe, Rick P [this message]
2026-03-31 12:41 ` [PATCH v7 09/22] x86/virt/seamldr: Introduce skeleton for TDX module updates Chao Gao
2026-04-07 11:49   ` Chao Gao
2026-04-07 15:55     ` Dave Hansen
2026-04-11  1:23   ` Edgecombe, Rick P
2026-03-31 12:41 ` [PATCH v7 10/22] x86/virt/seamldr: Abort updates if errors occurred midway Chao Gao
2026-04-11  1:26   ` Edgecombe, Rick P
2026-04-14  9:59     ` Chao Gao
2026-04-14 17:41       ` Edgecombe, Rick P
2026-03-31 12:41 ` [PATCH v7 11/22] x86/virt/seamldr: Shut down the current TDX module Chao Gao
2026-04-07 11:51   ` Chao Gao
2026-04-11  1:35   ` Edgecombe, Rick P
2026-04-11  1:36     ` Edgecombe, Rick P
2026-04-14 10:09     ` Chao Gao
2026-04-14 17:34       ` Edgecombe, Rick P
2026-03-31 12:41 ` [PATCH v7 12/22] x86/virt/tdx: Reset software states during TDX module shutdown Chao Gao
2026-04-07 12:02   ` Chao Gao
2026-04-11  1:56   ` Edgecombe, Rick P
2026-03-31 12:41 ` [PATCH v7 13/22] x86/virt/seamldr: Install a new TDX module Chao Gao
2026-04-11  2:01   ` Edgecombe, Rick P
2026-04-14 10:19     ` Chao Gao
2026-04-14 17:35       ` Edgecombe, Rick P
2026-03-31 12:41 ` [PATCH v7 14/22] x86/virt/seamldr: Do TDX per-CPU initialization after updates Chao Gao
2026-04-11  2:03   ` Edgecombe, Rick P
2026-03-31 12:41 ` [PATCH v7 15/22] x86/virt/tdx: Restore TDX module state Chao Gao
2026-04-07 12:07   ` Chao Gao
2026-04-11  2:06     ` Edgecombe, Rick P
2026-03-31 12:41 ` [PATCH v7 16/22] x86/virt/tdx: Update tdx_sysinfo and check features post-update Chao Gao
2026-04-07 12:15   ` Chao Gao
2026-04-07 15:53     ` Dave Hansen
2026-04-08 12:16       ` Chao Gao
2026-03-31 12:41 ` [PATCH v7 17/22] x86/virt/tdx: Avoid updates during update-sensitive operations Chao Gao
2026-04-06 22:29   ` Sean Christopherson
2026-04-14 19:58   ` Edgecombe, Rick P
2026-04-14 21:43     ` Dan Williams
2026-03-31 12:41 ` [PATCH v7 18/22] coco/tdx-host: Don't expose P-SEAMLDR features on CPUs with erratum Chao Gao
2026-04-13 19:28   ` Edgecombe, Rick P
2026-03-31 12:41 ` [PATCH v7 19/22] x86/virt/tdx: Enable TDX module runtime updates Chao Gao
2026-04-13 19:40   ` Edgecombe, Rick P
2026-03-31 12:41 ` [PATCH v7 20/22] coco/tdx-host: Document TDX module update compatibility criteria Chao Gao
2026-03-31 12:41 ` [PATCH v7 21/22] x86/virt/tdx: Document TDX module update Chao Gao
2026-04-13 19:54   ` Edgecombe, Rick P
2026-03-31 12:41 ` [PATCH v7 22/22] x86/virt/seamldr: Log TDX module update failures Chao Gao
2026-04-13 20:04   ` Edgecombe, Rick P
2026-04-14 10:25     ` Chao Gao
2026-04-14 17:39       ` Edgecombe, Rick P

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1016261178d32a5c6f20d1507f28388dd01a15df.camel@intel.com \
    --to=rick.p.edgecombe@intel.com \
    --cc=binbin.wu@linux.intel.com \
    --cc=bp@alien8.de \
    --cc=chao.gao@intel.com \
    --cc=dan.j.williams@intel.com \
    --cc=dave.hansen@linux.intel.com \
    --cc=hpa@zytor.com \
    --cc=ira.weiny@intel.com \
    --cc=kai.huang@intel.com \
    --cc=kas@kernel.org \
    --cc=kvm@vger.kernel.org \
    --cc=linux-coco@lists.linux.dev \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=nik.borisov@suse.com \
    --cc=paulmck@kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=reinette.chatre@intel.com \
    --cc=sagis@google.com \
    --cc=seanjc@google.com \
    --cc=tglx@kernel.org \
    --cc=tony.lindgren@linux.intel.com \
    --cc=vannapurve@google.com \
    --cc=vishal.l.verma@intel.com \
    --cc=x86@kernel.org \
    --cc=xiaoyao.li@intel.com \
    --cc=yan.y.zhao@intel.com \
    --cc=yilun.xu@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox