0xDEADBEEF equivalent for 64-bit development?
Asked Answered
M

12

45

For C++ development for 32-bit systems (be it Linux, Mac OS or Windows, PowerPC or x86) I have initialised pointers that would otherwise be undefined (e.g. they can not immediately get a proper value) like so:

int *pInt = reinterpret_cast<int *>(0xDEADBEEF);

(To save typing and being DRY the right-hand side would normally be in a constant, e.g. BAD_PTR.)

If pInt is dereferenced before it gets a proper value then it will crash immediately on most systems (instead of crashing much later when some memory is overwritten or going into a very long loop).

Of course the behavior is dependent on the underlying hardware (getting a 4 byte integer from the odd address 0xDEADBEEF from a user process may be perfectly valid), but the crashing has been 100% reliable for all the systems I have developed for so far (Mac OS 68xxx, Mac OS PowerPC, Linux Redhat Pentium, Windows GUI Pentium, Windows console Pentium). For instance on PowerPC it is illegal (bus fault) to fetch a 4 byte integer from an odd address.

What is a good value for this on 64-bit systems?

Mature answered 11/8, 2009 at 1:24 Comment(9)
I've seen systems where the first 1K of memory is defined to be not valid. So if a NULL pointer is dereferenced, the process will die a quick death. 0xDEADBEEF could be a valid location.Demy
@Robert: I've seen systems where the interrupt vector starts at 0, so dereferencing a NULL function pointer just seems to reboot the system (but doesn't reinitialize the stacks, etc.). Any address could be a valid location for something.Reversioner
@bk1e: IVT should NEVER be accessible from usermode. But you are correct in that there's no reason why address 0 can't be mapped. In Linux, it's easy to map to address 0 by changing an option in the kernel. In any case, the lesson learned here is not to use stupid patterns to mark pointers as invalid, use null or a separate flag in the struct. Assuming it will just crash is completely irresponsible and ignorant, if you're lucky, you will only get a segfault, it's likely that this can lead to remote code execution, and already has many, many, many, times in the past.Outbuilding
This is why C should be banned. Nobody knows how to use it. On another note, you could just ensure that your program maps 0xdeadbeef to a guard page before running, for example, but not all OS have an equivalent, so you may still get the vuln on some OS. Also triggering a segfault itself doesn't necessarily stop remote code execution from happening.Outbuilding
@Longpoke: I agree, but not every CPU has an MMU. On some embedded systems, NULL points at something important and you can't do anything about it. :)Reversioner
@bk1e, but the C standard guarantees that NULL (and respectively 0 converted to a pointer) will be an invalid pointer which you can't dereference.Planer
@iconiK: What does "can't dereference" mean? You most certainly can dereference NULL, but the result is undefined behavior (according to C99 section 6.5.3.2). A null pointer is guaranteed to compare unequal to any object or function (according to C99 section 6.3.2.3), so if there is a C object or C function at address 0, the compiler ought to convert (void*)0 to point somewhere other than address 0. However, the interrupt vector table isn't a C object or C function, so I don't think compilers are obligated to guarantee that NULL doesn't point to the interrupt vector table.Reversioner
@bk1, well unless you explicitly want undefined behavior, you ought not to dereference NULL, so that is why it's the proper one to use for initialized but unused pointers. I didn't say it was address 0; the C standard guarantees that 0 converted to a pointer results in the NULL pointer. Whether an implementation changes that behavior, or defines dereferencing the NULL point is outside the scope of standard C (or C++ for that matter).Planer
@iconiK: Back to the original topic: You can accidentally dereference 0xDEADBEEF, which may or may not cause a crash. You can accidentally dereference NULL, which may or may not be address 0, and which may or may not cause a crash. Many platforms use memory protection hardware to detect when an invalid pointer is dereferenced, but the C specification does not require this. Therefore, initializing pointers to NULL is better than initializing them to 0xDEADBEEF, but it is not guaranteed to detect accidental dereferences on all platforms.Reversioner
C
25

Generally it doesn't matter exactly what pattern you write, it matters that you can identify the pattern in order to determine where problems are occurring. It just so happens that in the Linux kernel these are often chosen so that they can be trapped if the addresses are dereferenced.

Have a look in the Linux kernel at include/linux/poison.h. This file contains different poison values for many different kernel subsystems. There is no one poison value that is appropriate.

Also, you might check per-architecture include files in the Linux kernel source tree for info on what is used on specific architectures.

Chock answered 2/8, 2010 at 15:20 Comment(0)
I
73

0xBADC0FFEE0DDF00D

Ilona answered 11/8, 2009 at 1:27 Comment(3)
This particular one has the advantage that you need yottabytes of memory to actually make this a sane value as kernel heap grows down while user heap grows up.Plagal
@Joshua: 1. I can map my pages wherever I like. 2. That's a very dangerous assumption to make (perhaps its true with your current os on an x86 setup, but this is implementation dependent), what if the stack starts at 0xBADCOFFEE0DFOOD-0x1000? The stack starts at random places already, it does this to try and make exploitation harder and for just technical reasons aside from that.Outbuilding
How did you arrive at this number?Formicary
D
55

According to Wikipedia, BADC0FFEE0DDF00D is used on IBM RS/6000 64-bit systems to indicate uninitialized CPU registers.

Daron answered 11/8, 2009 at 1:28 Comment(0)
L
27

Most current 64-bit systems let you use only the lowest 248–252 bits of the address space; higher bits of the address must be all-zero. Some chips (e.g. amd64) also let you use the highest 248–252. Addresses outside these ranges cannot ever be mapped to accessible memory; the hardware simply won't allow it.

I therefore recommend you use a value close to 263, which is nowhere near either of the possibly-usable spaces. If the leading four hex digits are 7ff8, the value will be a double precision floating-point NaN, which is convenient. So my suggested cute hexadecimal phrase is 0x7FF8BADFBADFBADF.

By the way, you really don't want to use a value close to 0, because that makes it hard to tell an offset dereference of NULL — a structure member access, for instance — from a dereference of the poison pattern.

Loudermilk answered 2/8, 2010 at 20:40 Comment(3)
That «most current 64-bit system let you use only the lowest 48-52 bits of the address space» and that «the hardware simply won't allow it».Michi
The architecture manual for each CPU of interest will tell you how many bits of the address space are usable. For instance, the AMD64 Architecture Programmer's Manual, Volume 2 (System Programming) says in section 1.1.3 that not all 64 bits of the address space are necessarily usable and that unusable high bits must be all-zero or all-one, and then in section 5.3.3 shows you that current implementations only allow use of the low 48 bits.Loudermilk
I'm not aware of any overview that lists CPUs with 64-bit addressing and their usable address ranges, but the only exception to my original assertion that I can find is PowerPC in hashed page table mode. With tree-structured page tables, every additional six to eight bits of virtual address space adds a tree level and makes TLB misses slower, so architecture designers are reluctant to make more space usable than people actually need, which right now is 48-52 bits (except for exotic single address space operating systems).Loudermilk
C
25

Generally it doesn't matter exactly what pattern you write, it matters that you can identify the pattern in order to determine where problems are occurring. It just so happens that in the Linux kernel these are often chosen so that they can be trapped if the addresses are dereferenced.

Have a look in the Linux kernel at include/linux/poison.h. This file contains different poison values for many different kernel subsystems. There is no one poison value that is appropriate.

Also, you might check per-architecture include files in the Linux kernel source tree for info on what is used on specific architectures.

Chock answered 2/8, 2010 at 15:20 Comment(0)
T
15

I'm assuming you've already discounted NULL (i.e. 0 without the typecast). It's definitely the safest choice, as, in theory, a valid pointer could point to the memory address 0xDEADBEEF (Or any other non-NULL memory address).

Thiourea answered 11/8, 2009 at 1:27 Comment(9)
I think one of the points of using 0xDEADBEEF or some other known-bad value is that it's quite obvious when debugging the resultant core file (ore equivalent) that you're dealing with an uninitialised pointer, rather than garbage/invalid/incorrect data. I'd suggest the chances of 0xDEADBEEF actually pointing to a valid memory location are small enough to be greatly outweighed by the benefits.Firm
For Pointers, Always NULL/0 should be used. 0xDEADBEEF and other hex-values are used to fill recently-allocated-but-not-initialized , recently-freed-should-not-be-accessed-any-more memory regions handled by the heap-manager functions (this may also be true for the stack)...Casanova
What you've never seen a memory mapping at NULL?Plagal
No one has ever seen a memory mapping at NULL as the compiler guarantees that the NULL memory location is never used: "...a null pointer points definitively nowhere; it is not the address of any object or function." See: c-faq.com/null/null1.htmlThiourea
@Mike Koval, well that's just simply not true. I've mapped memory at NULL. In fact it's not that uncommon, a quick Googling of "null pointer dereference exploit" should give you lots of examples. This looks like it probably has some high-level information: blog.cr0.org/2009/06/bypassing-linux-null-pointer.htmlAdiell
@Mike: That is true, however the C specification does not define the behavior of an attempt to dereference a NULL pointer. Thus it is legal (though atypical) for a platform to accept reads from and writes to *NULL.Bourse
The NULL/0 pointer is not necessarily represented as 0-bytes in memory. Although I wouldn't know of any system where it is anything different.Sextan
@Adiell So qualify it a little - as long as you stay in userland, you're guaranteed that NULL is absolutely invalid.Chemotropism
Just so you know, mmap() will map NULL if explicitly told to do so (passed flag for exact address with NULL as the address). and in gcc compiling with -fno-delete-null-pointer-checks tells the compiler not to assume that dereferencing NULL is invalid.Plagal
P
13

0xDEADBEEFBAADF00D might work.

Plagal answered 11/8, 2009 at 1:26 Comment(0)
P
8

I don't have a good choice for you, but here's a list of hex words that you can use to make your phrase.

Pericynthion answered 11/8, 2009 at 1:29 Comment(0)
A
5

Two 0xDEADBEEFs should be enough, I think..

Anemoscope answered 2/8, 2010 at 15:2 Comment(0)
H
3

I see several answers claiming NULL is a good choice, but I disagree.

NULL is often used as a valid return value from functions. It indicates a failure return or an unknown value. This is a different meaning than "uninitialized pointer."

Using a debugger on the code and seeing NULL would then leave two possibilities: the pointer was never initialized or it had failed a memory allocation.

Setting the uninitialized pointer to 0xDEADBEEF or the 64-bit equivalent means that a NULL pointer indicates an intentional value.

Hiltan answered 11/8, 2009 at 2:50 Comment(2)
This is only true if you need an uninitialized pointer. And that's where I disagree: Unless you do embedded stuff or other things that are so performance-sensitive, that initializing a pointer to NULL is not possible, in the very rare cases where you need a pointer without being able to initialize it to something sensible, initializing it to NULL gets you rid of the problem. I don't think I needed an uninitialized pointer in years.Unknowable
"That was never initialized" values are very useful when debugging - one doesn't explicitly initialize any given memory location this way, one fills entire memory blocks with it (on malloc() and again, with a different pattern, on free()) so as to detect places where the program should have initialized a variable but didn't.Loudermilk
R
2

It depends on the OS and the environment, of course. I don't think 0xDEADBEEF is necessarily a bad pointer in an arbitrary 32-bit system, either.

Realistically, any modern OS should be access-protecting the first few pages of process memory, so NULL should be a good invalid pointer value. Conveniently enough, it's already pre-defined for you.

Rouvin answered 11/8, 2009 at 1:31 Comment(2)
Agree that NULL is a very useful choice. 0xDEADBEEF isn't an invalid pointer, but not only is it awfully unlikely in practice, but it's not aligned on a 4- or 2-byte boundary. Except as a char* or possibly bool*, it won't occur naturally unless you've got some seriously messed-up memory semantics.Mexican
It's almost always in kernel memory mapping area anyway.Plagal
A
2

As the system I worked on basically runs on x86_64 platform, the value I use is:

0xDEADBEEFDEADBEEF

Reasons are:

  • On x86_64 platform, only the low-order 48 bits are used for virtual memory address in current implementation, meaning any value > 2^48 should work: https://en.wikipedia.org/wiki/X86-64
  • As 0xDEADBEEF is already very well known for this purpose in 32bit, 0xDEADBEEFDEADBEEF in 64bit is just more 'backward compatible'
Amylo answered 28/5, 2019 at 13:45 Comment(0)
D
1

0x42 could work on both 32bit and 64bit ? (It should still trigger a crash since it is close enough to the NULL pointer, and given that it's rather large, chances are you would not have it within a regular dereference of a structure field with the structure pointer being NULL).

Disvalue answered 11/8, 2009 at 1:29 Comment(1)
It's not really that large... there are plenty of structures greater than 66 bytes long.Detoxify

© 2022 - 2024 — McMap. All rights reserved.