linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Petr Tesarik <ptesarik@suse.com>
To: Catalin Marinas <catalin.marinas@arm.com>
Cc: Vlastimil Babka <vbabka@suse.cz>,
	Feng Tang <feng.tang@linux.alibaba.com>,
	Harry Yoo <harry.yoo@oracle.com>, Peng Fan <peng.fan@nxp.com>,
	Hyeonggon Yoo <42.hyeyoo@gmail.com>,
	David Rientjes <rientjes@google.com>,
	Christoph Lameter <cl@linux.com>,
	"linux-mm@kvack.org" <linux-mm@kvack.org>,
	Robin Murphy <robin.murphy@arm.com>,
	Sean Christopherson <seanjc@google.com>,
	Halil Pasic <pasic@linux.ibm.com>
Subject: Re: slub - extended kmalloc redzone and dma alignment
Date: Wed, 9 Apr 2025 10:39:04 +0200	[thread overview]
Message-ID: <20250409103904.54a19faa@mordecai> (raw)
In-Reply-To: <Z_U7p78VCoazBIOi@arm.com>

On Tue, 8 Apr 2025 16:07:19 +0100
Catalin Marinas <catalin.marinas@arm.com> wrote:

> On Tue, Apr 08, 2025 at 07:27:32AM +0200, Petr Tesarik wrote:
> > On Mon, 7 Apr 2025 18:12:09 +0100
> > Catalin Marinas <catalin.marinas@arm.com> wrote:  
> > > Thanks for looping me in. I'm just catching up with this thread.
> > > 
> > > On Mon, Apr 07, 2025 at 09:54:41AM +0200, Vlastimil Babka wrote:  
> > > > On 4/7/25 09:21, Feng Tang wrote:    
> > > > > On Sun, Apr 06, 2025 at 10:02:40PM +0800, Feng Tang wrote:
> > > > > [...]    
> > > > >> > I can remember this series, as well as my confusion why
> > > > >> > 192-byte kmalloc caches were missing on arm64.
> > > > >> > 
> > > > >> > Nevertheless, I believe ARCH_DMA_MINALIGN is required to avoid
> > > > >> > putting a DMA buffer on the same cache line as some other data
> > > > >> > that might be _written_ by the CPU while the corresponding
> > > > >> > main memory is modified by another bus-mastering device.
> > > > >> > 
> > > > >> > Consider this layout:
> > > > >> > 
> > > > >> >  ... | DMA buffer | other data | ...
> > > > >> >      ^                         ^
> > > > >> >      +-------------------------+-- cache line boundaries
> > > > >> > 
> > > > >> > When you prepare for DMA, you make sure that the DMA buffer is
> > > > >> > not cached by the CPU, so you flush the cache line (from all
> > > > >> > levels). Then you tell the device to write into the DMA
> > > > >> > buffer. However, before the device finishes the DMA
> > > > >> > transaction, the CPU accesses "other data", loading this cache
> > > > >> > line from main memory with partial results. Worse, if the CPU
> > > > >> > writes to "other data", it may write the cache line back into
> > > > >> > main memory, racing with the device writing to DMA buffer, and
> > > > >> > you end up with corrupted data in DMA buffer.    
> > > 
> > > Yes, cache evictions from 'other data; can override the DMA. Another
> > > problem, when the DMA completed, the kernel does a cache invalidation
> > > to remove any speculatively loaded cache lines from the DMA buffer
> > > but that would also invalidate 'other data', potentially corrupting
> > > it if it was dirty.
> > > 
> > > So it's not safe to have DMA into buffers less than ARCH_DMA_MINALIGN
> > > (and unaligned).  
> > 
> > It's not safe to DMA into buffers that share a CPU cache line with other
> > data, which could be before or after the DMA buffer, of course.  
>[...]
> While I think we are ok for arm64, other architectures may invalidate
> the caches in the arch_sync_dma_for_device() which could discard the red
> zone data. A quick grep for arch_sync_dma_for_device() shows several
> architectures invalidating the caches in the FROM_DEVICE case.

Wait. This sounds broken for partial writes into the DMA buffer, i.e.
where only part of the buffer is updated by a bus-mastering device.
When I worked on swiotlb, I was told that such partial updates must
be supported, and that's why the initial swiotlb_bounce() cannot be
removed from swiotlb_tbl_map_single(). In fact, the comment says:

	/*
	 * When the device is writing memory, i.e. dir == DMA_FROM_DEVICE, copy
	 * the original buffer to the TLB buffer before initiating DMA in order
	 * to preserve the original's data if the device does a partial write,
	 * i.e. if the device doesn't overwrite the entire buffer.  Preserving
	 * the original data, even if it's garbage, is necessary to match
	 * hardware behavior.  Use of swiotlb is supposed to be transparent,
	 * i.e. swiotlb must not corrupt memory by clobbering unwritten bytes.
	 */

You may want to check commit ddbd89deb7d3 ("swiotlb: fix info leak with
DMA_FROM_DEVICE"), commit aa6f8dcbab47 ("swiotlb: rework "fix info leak
with DMA_FROM_DEVICE") and commit 1132a1dc053e ("swiotlb: rewrite
comment explaining why the source is preserved on DMA_FROM_DEVICE").

I believe there is potential for a nasty race condition, and maybe even
info leak. Consider this:

1. DMA buffer is allocated by kmalloc(). The memory area previously
   contained sensitive information, which had been written to main
   memory.
2. The DMA buffer is initialized with zeroes, but this new content
   stays in a CPU cache (because this is kernel memory with a write
   behind cache policy).
3. DMA is set up, but nothing is written to main memory by the
   bus-mastering device.
4. The CPU cache line is now discarded in arch_sync_dma_for_cpu().

IIUC the zeroes were never written to main memory, and previous content
can now be read by the CPU through the DMA buffer.

I haven't checked if any architecture is affected, but I strongly
believe that the CPU cache MUST be flushed both before and after the
DMA transfer. Any architecture which does not do it that way should be
fixed.

Or did I miss a crucial detail (again)?

> > > What I did with reducing the minimum kmalloc()
> > > alignment was to force bouncing via swiotlb if the size passed to
> > > the DMA API is small. It may end up bouncing buffers that did not
> > > originate from kmalloc() or have proper alignment (with padding)
> > > but that's some heuristics we were willing to accept to be able
> > > to use small kmalloc() caches on arm64 - see
> > > dma_kmalloc_needs_bounce().
> > > 
> > > Does redzoning apply to kmalloc() or kmem_cache_create() (or
> > > both)? I haven't checked yet but if the red zone is within
> > > ARCH_DMA_MINALIGN (or rather dma_get_cache_alignment()), we could
> > > have issues with either corrupting the DMA buffer or the red
> > > zone. [...]  
> > 
> > I'm sorry if I'm being thick, but IIUC the red zone does not have
> > to be protected. Yes, we might miss red zone corruption if it
> > happens to race with a DMA transaction, but I have assumed that
> > this is permissible. I regard the red zone as a useful debugging
> > tool, not a safety measure that is guaranteed to detect any write
> > beyond the buffer end.  
> 
> Yeah, it's debugging, but too many false positives make the feature
> pretty useless.

Agreed. I was defending only sporadic false negatives. If there is room
for false positives, that's a no-go.

> > > > > I'm not familiar with DMA stuff, but Vlastimil's idea does make it
> > > > > easier for driver developer to write a driver to be used on
> > > > > different ARCHs, which have different DMA alignment requirement.
> > > > > Say if the minimal safe size is 8 bytes, the driver can just
> > > > > request 8 bytes and ARCH_DMA_MINALIGN will automatically chose
> > > > > the right size for it, which can save memory for ARCHs with
> > > > > smaller alignment requirement. Meanwhile it does sacrifice part
> > > > > of the redzone check ability, so I don't have preference here :)    
> > > > 
> > > > Let's clarify first who's expected to ensure the word alignment for
> > > > DMA, if it's not kmalloc() then I'd rather resist moving it there
> > > > :)    
> > > 
> > > In theory, the DMA API should handle the alignment as I tried to
> > > remove it from the kmalloc() code.  
> > 
> > Are we talking about the alignment of the starting address, or buffer
> > size, or both?  
> 
> The DMA API bouncing logic only checks the buffer size and assumes
> start/end would be aligned to kmalloc_size_roundup() with no valid data
> between them (FROM_DEVICE).

If that's correct behavior, then it must be documented, because other
places seem to disagree on the assumptions about prior content of a
DMA buffer (FROM_DEVICE). See the swiotlb comment above.

Petr T


  reply	other threads:[~2025-04-09  8:39 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-04-04  9:30 slub - extended kmalloc redzone and dma alignment Vlastimil Babka
2025-04-04 10:30 ` Harry Yoo
2025-04-04 11:12   ` Petr Tesarik
2025-04-04 12:45     ` Vlastimil Babka
2025-04-04 13:53       ` Petr Tesarik
2025-04-06 14:02         ` Feng Tang
2025-04-07  7:21           ` Feng Tang
2025-04-07  7:54             ` Vlastimil Babka
2025-04-07  9:50               ` Petr Tesarik
2025-04-07 17:12               ` Catalin Marinas
2025-04-08  5:27                 ` Petr Tesarik
2025-04-08 15:07                   ` Catalin Marinas
2025-04-09  8:39                     ` Petr Tesarik [this message]
2025-04-09  9:05                       ` Petr Tesarik
2025-04-09  9:47                         ` Catalin Marinas
2025-04-09 12:18                           ` Petr Tesarik
2025-04-09 12:49                             ` Catalin Marinas
2025-04-09 13:41                               ` Petr Tesarik
2025-04-09  8:51                     ` Vlastimil Babka
2025-04-09 11:11                       ` Catalin Marinas
2025-04-09 12:22                         ` Vlastimil Babka
2025-04-09 14:30                           ` Catalin Marinas
2025-04-10  1:54                             ` Feng Tang
2025-04-07  7:45         ` Vlastimil Babka

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=20250409103904.54a19faa@mordecai \
    --to=ptesarik@suse.com \
    --cc=42.hyeyoo@gmail.com \
    --cc=catalin.marinas@arm.com \
    --cc=cl@linux.com \
    --cc=feng.tang@linux.alibaba.com \
    --cc=harry.yoo@oracle.com \
    --cc=linux-mm@kvack.org \
    --cc=pasic@linux.ibm.com \
    --cc=peng.fan@nxp.com \
    --cc=rientjes@google.com \
    --cc=robin.murphy@arm.com \
    --cc=seanjc@google.com \
    --cc=vbabka@suse.cz \
    /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;
as well as URLs for NNTP newsgroup(s).