mm/slub: Fix incorrect checkings of s->offset
Subsystems (2)
PATCH 1/1 mm/slub: Fix incorrect checkings of s->offset
In a couple of places in the slub memory allocator, the code uses "s->offset" as a check to see if the free pointer is put right after the object. That check is no longer true with commit 3202fa62fb43 ("slub:
relocate freelist pointer to middle of object").
As a result, echoing "1" into the validate sysfs file, e.g. of dentry, may cause a bunch of "Freepointer corrupt" error reports to appear with the system in panic afterwards.
To fix it, use the check "s->offset == s->inuse" instead.
--- mm/slub.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-)
mm/slub.c +7 -11
@@ -556,10 +556,8 @@ static struct track *get_track(struct kmem_cache *s, void *object, {struct track *p; -if (s->offset) - p = object + s->offset +sizeof (void *); -else - p = object + s->inuse; + p = object + s->inuse + + ((s->offset == s->inuse) ?sizeof (void *) :0 );return p + alloc; }
@@ -693,10 +691,8 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p)print_section (KERN_ERR ,"Redzone " , p + s->object_size, s->inuse - s->object_size); -if (s->offset) - off = s->offset +sizeof (void *); -else - off = s->inuse; + off = s->inuse + + ((s->offset == s->inuse) ?sizeof (void *) :0 );if (s->flags &SLAB_STORE_USER ) off +=2 *sizeof (struct track );
@@ -790,7 +786,7 @@ static int check_bytes_and_report(struct kmem_cache *s, struct page *page,* object address * Bytes of the object to be managed. * If the freepointer may overlay the object then the free -* pointer is the first word of the object. +* pointer is at the middle of the object. * * Poisoning uses 0x6b (POISON_FREE) and the last byte is * 0xa5 (POISON_END)
@@ -826,7 +822,7 @@ static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p) {unsigned long off = s->inuse;/* The end of info */ -if (s->offset) +if (s->offset == s->inuse)/* Freepointer is placed after the object. */ off +=sizeof (void *);
@@ -915,7 +911,7 @@ static int check_object(struct kmem_cache *s, struct page *page,check_pad_bytes (s, page, p); } -if (!s->offset && val ==SLUB_RED_ACTIVE ) +if ((s->offset != s->inuse) && val ==SLUB_RED_ACTIVE )/* * Object and freepointer overlap. Cannot check * freepointer while object is allocated.
Signature · 1 line
2.18.1
Quoted 10 lines · Waiman Long
In a couple of places in the slub memory allocator, the code uses "
s->offset" as a check to see if the free pointer is put right after the object. That check is no longer true with commit3202fa62fb43("slub:
relocate freelist pointer to middle of object").As a result, echoing "1" into the validate sysfs file, e.g. of dentry, may cause a bunch of "Freepointer corrupt" error reports to appear with the system in panic afterwards.
To fix it, use the check "
s->offset==s->inuse" instead.
I think a little refactoring would make this more clear.
unsigned int track_offset(const struct kmem_cache *s)
{
return s->inuse + (s->offset == s->inuse) ? sizeof(void *) : 0;
}mm/slub.c static struct track *get_track(struct kmem_cache *s, void *object, · line 560
Quoted 10 lines
mm/slub.c +2
-4@@ -556,10 +556,8 @@ static struct track *get_track(struct kmem_cache *s, void *object, {struct track *p; -if (s->offset) - p = object + s->offset +sizeof (void *); -else - p = object + s->inuse; + p = object + s->inuse + + ((s->offset == s->inuse) ?sizeof (void *) :0 );
p = object + track_offset(s);
mm/slub.c static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p) · line 695
Quoted 12 lines
mm/slub.c +2
-4return p + alloc; }@@ -693,10 +691,8 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p)print_section (KERN_ERR ,"Redzone " , p + s->object_size, s->inuse - s->object_size); -if (s->offset) - off = s->offset +sizeof (void *); -else - off = s->inuse; + off = s->inuse + + ((s->offset == s->inuse) ?sizeof (void *) :0 );
off = track_offset(s);
mm/slub.c static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p) · line 827
Quoted 8 lines
mm/slub.c +1
-1@@ -826,7 +822,7 @@ static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p) {unsigned long off = s->inuse;/* The end of info */ -if (s->offset) +if (s->offset == s->inuse)/* Freepointer is placed after the object. */ off +=sizeof (void *);
unsigned long off = track_offset(s);
Quoted 10 lines · Matthew Wilcox
Quoted 9 lines · Waiman Long
In a couple of places in the slub memory allocator, the code uses "
s->offset" as a check to see if the free pointer is put right after the object. That check is no longer true with commit3202fa62fb43("slub:
relocate freelist pointer to middle of object").As a result, echoing "1" into the validate sysfs file, e.g. of dentry, may cause a bunch of "Freepointer corrupt" error reports to appear with the system in panic afterwards.
Quoted 7 lines
Quoted 1 line
To fix it, use the check "
s->offset==s->inuse" instead.I think a little refactoring would make this more clear.
unsigned int
track_offset(const struct kmem_cache *s){ return s->inuse + (s->offset == s->inuse) ? sizeof(void *) : 0; }
Yes, that was what I am thinking of doing in v2.
Thanks,
Longman
Quoted 12 lines · Waiman Long
Quoted 11 lines · Matthew Wilcox
Quoted 10 lines · Waiman Long
In a couple of places in the slub memory allocator, the code uses "
s->offset" as a check to see if the free pointer is put right after the object. That check is no longer true with commit3202fa62fb43("slub:
relocate freelist pointer to middle of object").As a result, echoing "1" into the validate sysfs file, e.g. of dentry, may cause a bunch of "Freepointer corrupt" error reports to appear with the system in panic afterwards.
To fix it, use the check "
s->offset==s->inuse" instead.
Quoted 8 lines
Quoted 6 lines
I think a little refactoring would make this more clear.
unsigned int
track_offset(const struct kmem_cache *s)
{
returns->inuse+ (s->offset==s->inuse) ?sizeof(void *): 0; }Yes, that was what I am thinking of doing in v2.
BTW, "+" has a higher priority than "?:". So we need a parenthesis around "?:".
Cheers,
Longman
Quoted 21 lines · Waiman Long
Quoted 20 lines · Waiman Long
Quoted 18 lines · Matthew Wilcox
Quoted 11 lines · Waiman Long
In a couple of places in the slub memory allocator, the code uses "
s->offset" as a check to see if the free pointer is put right after the
object. That check is no longer true with commit3202fa62fb43("slub:
relocate freelist pointer to middle of object").As a result, echoing "1" into the validate sysfs file, e.g. of dentry, may cause a bunch of "Freepointer corrupt" error reports to appear with the system in panic afterwards.
To fix it, use the check "
s->offset==s->inuse" instead.I think a little refactoring would make this more clear.
unsigned int
track_offset(const struct kmem_cache *s)
{
returns->inuse+ (s->offset==s->inuse) ?sizeof(void *): 0; }
Quoted 4 lines
Quoted 1 line
Yes, that was what I am thinking of doing in v2.
BTW, "+" has a higher priority than "?:". So we need a parenthesis around "?:".
That seems like a good reason to not use ?:
unsigned int track_offset(const struct kmem_cache *s)
{
if (s->offset != s->inuse)
return s->inuse;
return s->inuse + sizeof(void *);
}Also this needs a comment about why we're doing this ... something about the freelist pointer, I think?
Quoted 27 lines · Matthew Wilcox
Quoted 16 lines · Waiman Long
Quoted 15 lines · Waiman Long
Quoted 14 lines · Matthew Wilcox
Quoted 11 lines · Waiman Long
In a couple of places in the slub memory allocator, the code uses "
s->offset" as a check to see if the free pointer is put right after the
object. That check is no longer true with commit3202fa62fb43("slub:
relocate freelist pointer to middle of object").As a result, echoing "1" into the validate sysfs file, e.g. of dentry, may cause a bunch of "Freepointer corrupt" error reports to appear with the system in panic afterwards.
To fix it, use the check "
s->offset==s->inuse" instead.I think a little refactoring would make this more clear.
Quoted 7 lines
Quoted 5 lines
Quoted 4 lines
unsigned int
track_offset(const struct kmem_cache *s)
{
returns->inuse+ (s->offset==s->inuse) ?sizeof(void *): 0;
}Yes, that was what I am thinking of doing in v2.
BTW, "+" has a higher priority than "?:". So we need a parenthesis around "?:".
That seems like a good reason to not use ?:
unsigned int
track_offset(const struct kmem_cache *s)
Quoted 9 lines
{ if (s->offset != s->inuse) return s->inuse; return s->inuse + sizeof(void *); }Also this needs a comment about why we're doing this ... something about the freelist pointer, I think?
I can see a simple if-else to make it easier to read.
Thanks,
Longman