mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Sergey Senozhatsky <senozhatsky@chromium.org>
To: Yosry Ahmed <yosry@kernel.org>
Cc: Sergey Senozhatsky <senozhatsky@chromium.org>,
	 Andrew Morton <akpm@linux-foundation.org>,
	Nhat Pham <nphamcs@gmail.com>,
	 Yosry Ahmed <yosry.ahmed@linux.dev>,
	Johannes Weiner <hannes@cmpxchg.org>,
	 Brian Geffon <bgeffon@google.com>,
	Minchan Kim <minchan@kernel.org>,
	 Richard Chang <richardycc@google.com>,
	linux-kernel@vger.kernel.org, linux-block@vger.kernel.org,
	 linux-mm@kvack.org
Subject: Re: [PATCH 5/7] zsmalloc: embed struct zs_handle into zram and zswap entries
Date: Tue, 10 Nov 2026 11:51:21 +0900	[thread overview]
Message-ID: <avKFc82JS4R9yU-N@google.com> (raw)
In-Reply-To: <auy22TkX0ADxP9WR@google.com>

On (26/11/05 17:19), Yosry Ahmed wrote:
[..]
> >  Additionally, zs_malloc() does not return a dereferenceable pointer.
> > -Instead, it returns an opaque handle (unsigned long) which encodes actual
> > -location of the allocated object. The reason for this indirection is that
> > +Instead, it stores the encoded location of the allocated object in the
> > +provided ``struct zs_handle``. The reason for this indirection is that
> 
> Should we explicitly call out that zsmalloc will keep a back pointer to
> the handle and update it asynchronously, so the owner shouldn't modify
> it, and should keep it allocated until zs_free() (or rebind)?
> 
> Probably somewhere in the code comments too?

Yeah, perhaps.

> >  zsmalloc does not keep zspages permanently mapped since that would cause
> >  issues on 32-bit systems where the VA region for kernel space mappings
> >  is very small. So, using the allocated memory should be done through the
> > diff --git a/include/linux/zsmalloc.h b/include/linux/zsmalloc.h
> > index 693c9484b638..6c76fd10344e 100644
> > --- a/include/linux/zsmalloc.h
> > +++ b/include/linux/zsmalloc.h
> > @@ -14,6 +14,7 @@
> >  #ifndef _ZS_MALLOC_H_
> >  #define _ZS_MALLOC_H_
> >  
> > +#include <linux/compiler.h>
> >  #include <linux/types.h>
> >  
> >  struct zs_pool_stats {
> > @@ -21,16 +22,39 @@ struct zs_pool_stats {
> >  	atomic_long_t pages_compacted;
> >  };
> >  
> > +/*
> > + * zsmalloc writes object location into the handle and updates it when
> > + * the object moves (compaction, page migration), so the handle must not
> > + * be on the stack and must not be copied.  Use zs_rebind_handle() to
> > + * move an object to another handle.
> > + */
> > +struct zs_handle {
> > +	unsigned long __private obj;
> > +} __aligned(sizeof(unsigned long));
> 
> Is alignment guaranteed even if this is embedded in a packed struct? I
> wonder if we should have an explicit alignment check in
> zs_malloc()/zs_store(), and probably rebind too?

I guess only run-time check will work.  I can add those.  I wonder
if we actually need to worry about this, neither zram nor zswap use
packed entries, but I think it's cheap enough to make sure in run-time.

> > +
> > +static inline void zs_handle_init(struct zs_handle *handle)
> > +{
> > +	ACCESS_PRIVATE(handle, obj) = 0;
> > +}
> > +
> > +static inline bool zs_handle_is_allocated(const struct zs_handle *handle)
> > +{
> > +	return READ_ONCE(ACCESS_PRIVATE(handle, obj)) != 0;
> > +}
> 
> Can this ever give a false negative?

That's a very good question.

> I believe that's only possible with pfn=0, I don't know if this can be the
> case on any architecture. Should we use something like OBJ_ALLOCATED_TAG?

Yeah, I don't know, I guess would be better to not rely on "pfn cannot be
0".  Let me look into this.


> > -struct zs_handle *zs_malloc(struct zs_pool *pool, size_t size, gfp_t flags,
> > -			    const int nid);
> > +int zs_malloc(struct zs_pool *pool, struct zs_handle *handle, size_t size,
> > +	      gfp_t flags, const int nid);
> >  void zs_free(struct zs_pool *pool, struct zs_handle *handle);
> > +#ifdef CONFIG_ZSMALLOC_REBIND_HANDLE
> 
> FWIW, I don't think this is buying as much. It's one function that is
> only called by zram anyway.

Ack.

> > +void zs_rebind_handle(struct zs_pool *pool, struct zs_handle *dst,
> > +		      struct zs_handle *src);
> 
> A few comments in zsmalloc.c mention zs_free() reading the handle
> locklessly, do these apply to rebinding as well?

Let me take a look.

> > +#endif
> >  
> >  size_t zs_huge_class_size(struct zs_pool *pool);
> 
> [..]
> > diff --git a/mm/zswap.c b/mm/zswap.c
> > index 397b06c9f33b..f28a46cae1e1 100644
> > --- a/mm/zswap.c
> > +++ b/mm/zswap.c
> > @@ -215,7 +215,7 @@ struct zswap_entry {
> >  	unsigned int length;
> >  	bool referenced;
> >  	u8 pool_idx;
> > -	struct zs_handle *handle;
> > +	struct zs_handle handle;
> >  	struct obj_cgroup *objcg;
> >  	struct list_head lru;
> >  };
> > @@ -769,6 +769,7 @@ static struct zswap_entry *zswap_entry_cache_alloc(gfp_t gfp, int nid)
> >  	entry = kmem_cache_alloc_node(zswap_entry_cache, gfp, nid);
> >  	if (!entry)
> >  		return NULL;
> > +	zs_handle_init(&entry->handle);
> >  	return entry;
> >  }
> >  
> > @@ -787,7 +788,7 @@ static void zswap_entry_free(struct zswap_entry *entry)
> >  
> >  	zswap_lru_del(entry);
> >  	if (!WARN_ON_ONCE(!pool)) {
> 
> This check is mostly defensive, and if the pool was ever NULL it
> prevented a NULL deref, and potentially leaked the underlying zsmalloc
> object, which is mostly fine as the pool being NULL points to a larger
> problem (e.g. corruption).
> 
> However, if that happens now, the handle pointer in zsmalloc would point
> at the zswap entry after it's freed by zswap_entry_cache_free() below,
> potentially causing a UAF. It's arguably fine as it's just a cascade of
> corruptions, but I wonder if we should just bail early and skip all
> cleanups below if the pool is NULL.
> 
> We'll leak the cgroup charge, stats, and the zswap entry itself -- but
> that's arguably the safer option if we already have a corruption
> problem.
> 
> We can also just delete the NULL check, but it's cheap to keep and I'd
> rather have it tbh.

Sounds good, let me reshuffle the code a bit.

  reply	other threads:[~2026-11-10  2:51 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-05  4:47 [PATCH 0/7] zsmalloc: redesign object alloc API Sergey Senozhatsky
2026-11-05  4:47 ` [PATCH 1/7] zram: drop stale comment in write_incompressible_page() Sergey Senozhatsky
2026-11-05  4:47 ` [PATCH 2/7] zram: drop get_slot_handle() and set_slot_handle() Sergey Senozhatsky
2026-11-05  4:47 ` [PATCH 3/7] zsmalloc: switch handle type to struct zs_handle Sergey Senozhatsky
2026-11-05 17:03   ` Yosry Ahmed
2026-11-10  2:42     ` Sergey Senozhatsky
2026-11-05  4:47 ` [PATCH 4/7] zram: allocate zsmalloc object under slot lock Sergey Senozhatsky
2026-11-05  4:47 ` [PATCH 5/7] zsmalloc: embed struct zs_handle into zram and zswap entries Sergey Senozhatsky
2026-11-05 17:19   ` Yosry Ahmed
2026-11-10  2:51     ` Sergey Senozhatsky [this message]
2026-11-10  3:12       ` Sergey Senozhatsky
2026-11-05 17:30   ` Yosry Ahmed
2026-11-10  2:44     ` Sergey Senozhatsky
2026-11-05  4:47 ` [PATCH 6/7] zsmalloc: fold zs_obj_write() into zs_store() Sergey Senozhatsky
2026-11-05 17:29   ` Yosry Ahmed
2026-11-10  2:45     ` Sergey Senozhatsky
2026-11-05  4:47 ` [PATCH 7/7] zsmalloc: constify struct zs_handle pointer in read-only functions Sergey Senozhatsky
2026-11-05 17:31 ` [PATCH 0/7] zsmalloc: redesign object alloc API Yosry Ahmed
2026-11-05 17:36   ` Nhat Pham
2026-11-05 17:39     ` Yosry Ahmed

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=avKFc82JS4R9yU-N@google.com \
    --to=senozhatsky@chromium.org \
    --cc=akpm@linux-foundation.org \
    --cc=bgeffon@google.com \
    --cc=hannes@cmpxchg.org \
    --cc=linux-block@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=minchan@kernel.org \
    --cc=nphamcs@gmail.com \
    --cc=richardycc@google.com \
    --cc=yosry.ahmed@linux.dev \
    --cc=yosry@kernel.org \
    /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

all inboxes | Powered by JetHome®