lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Wed, 16 Jan 2008 15:16:45 -0800 (PST)
From:	Linus Torvalds <torvalds@...ux-foundation.org>
To:	Johannes Weiner <hannes@...urebad.de>
cc:	Linux Kernel Mailing List <linux-kernel@...r.kernel.org>,
	clameter@....com, penberg@...helsinki.fi
Subject: Re: Why is the kfree() argument const?



On Wed, 16 Jan 2008, Johannes Weiner wrote:
> 
> Okay, I understood that now.  A const qualifier just forbids modifying
> the underlying memory _through this particular pointer_, right?

Yes, exactly.

> In the case of slub's kfree(), which takes a const pointer, you pass it
> on to slab_free() which actually _DOES_ modification of the underlying
> memory when linking the object to the freelist (as far as I understood
> the code).

First off, the whole concept of "underlying memory" is all about the fact 
that pointers point not to separate objects with its own existence, but 
point to a shared resource ("memory") that can be accessed many different 
ways.

So immediately when you talk about "underlying memory", you need to 
realize that now you're not talking about "that pointer" any more, but you 
are talking about the stuff that *other* pointers can access.

And the whole (and *only*) point of a memory allocator is turning that 
amorphous notion of "infinitely aliasable underlying memory" model into 
more of a "C pointer to separate objects" model.

That *is* what a memory allocator does.

> So if I got it right and you actually modify the memory you only got a
> const pointer to

No. YOU DO NOT.

You *invalidate* the pointer. Then, the memory allocator releases that 
portion of the "infinitely aliasable underlying memory", but that means 
that THAT POINTER NO LONGER EXISTS ON A C LEVEL.

So no, you don't "modify the memory you only got a const pointer to".

What you do is that the memory allocator 

 - keeps track of the NON-const memory that it always had
 - it sees the const pointer you gave it, and uses that pointer to look up 
   ITS OWN DATA STRUCTURES.
 - it then accesses those memory locations using its own pointers.

The "const pointer" you passed to kfree() simply no longer exists. The 
object it pointed to has gone away. That particular pointer simply isn't 
valid any more.

But the memory management code, which maintains its own structures for 
what it has allocated and not allocated, can (and will) generally use the 
knowledge *it* has about its own pointers to modify its own data 
structures.

The fact that they (obviously) alias in memory is irrelevant. It has no 
meaning for the "const void *" you passed in. That pointer is not usable 
for the caller any more.

And no, this is not just a semantic argument. It's a real issue. The 
pointer you pass in to kfree() is obviously used to *find* the data 
structures that the memory allocator maintains, and there is almost 
inevitably a rather direct mapping between the passed-in pointers and the 
data structures that a memory manager maintains itself, but they really 
are different. 

So to take a kfree() a pointer, the memory manager will use the "binary 
value" of that pointer to find its own data structures, and sometimes the 
values are so closely related that it ends up being a direct cast 
(possibly with an offset), but the end result of that direct cast really 
is now the memory management internal data, not the original pointer.

A real example of this is the actual kfree() implementation in the kernel 
(let's take the one from SLAB):

	struct kmem_cache *c;
	..
	c = virt_to_cache(objp);

which then actually ends up doing a 

	struct page *page = virt_to_head_page(obj);
	return page_get_cache(page);

which literally does math on the binary representation of the pointer to 
look up the backing store values (because the memory manager by definition 
is the thing that knows how the low-level representation of pointers 
actually works).

So now the kernel has turned that user-supplied pointer into ITS OWN data 
structures, that contain the NON-CONST aliases for the data.

(It will actually use the const pointer to further get offsets into those 
things, of course, so it's several levels of indirection off that pointer)

And yes, then it will write to those non-const aliases, but that's really 
no different from the same old thing: the pointer *you* passed kmalloc() 
may be "const",  but the memory manager itself has its own data structures 
to keep track of *its* aliases to the same memory, and those are the ones 
that are actually used to re-use the memory for others (and poison it 
etc).

So the particular pointer you passed in is "const". But that never *ever* 
guarantees that there aren't other non-const pointers around to be used 
that can modify the memory. And the memory manegement definitely has all 
those aliased pointers around - it's the whole *point* of memory 
management.

			Linus
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ