Storing an address into a function pointer - c

I was watching this video about calling the bootloader using software by assigning the address of the beginning of the system memory into a function pointer and then calling it, the expression for storing the address :
sysMemBootJump = (void(*)(void))(*(u32*)0x1fff0004);
"sysMemBootJump" is the function pointer.
But what I don't understand is, why did he dereference the address of the memory before casting it to void(*)(void) ?

Because the 'real' entry point is stored at that address. Think of it as being a pointer-to-pointer-to-function, by dereferencing you get just the pointer-to-function.

This is equivalent to:
u32 ad = *(u32*)0x1fff0004;
this is fetching a word located at address 0x1fff0004
then
sysMemBootJump = (void(*)(void))ad;
So 0x1fff0004 is the address of a word containing the routine's address.
And notice that the code is very unportable. A more portable integral type castable to/from addresses is uintptr_t from <stdint.h> ....
You can typedef function signatures, like here, to write more readable code.

Related

Why dereferencing user-space inside get_user is correct?

For example, in the function SYSCALL_DEFINE2 of linux kernel (https://elixir.bootlin.com/linux/v4.15.3/source/arch/alpha/kernel/osf_sys.c#L657):
SYSCALL_DEFINE2(osf_proplist_syscall, enum pl_code, code,
union pl_args __user *, args)
{
long error;
...
get_user(error, &args->set.nbytes)
...
}
Why it isn't need to use copy_from_user on args before using arrow and dot on it?
&args->set.nbytes is an address. It's allowed to compute the address of some member even if you couldn't actually read it — the compiler just adds the offset of the set.nbytes member of union pl_args to the address passed in args. Then it passes that address to get_user, which does the actual copying from userspace.
The get_user() function will do actual copying from user space, so it will take care of the dangerous part. Take a good look at this:
&args->set.nbytes
What this actually does it not dereference any pointer, but just calculate new pointer value. Pointers are really just unsigned integer values. So the line above says: give me address of part of data that is some offset from the start of structure. Start of structure is args and offset is set.nbytes. No actual accessing of user space memory is required to do this.

Following a pointer to a pointer

sqlite3_open takes a pointer to a pointer. Id like to trace the address of the second pointer.
E.g: p1(p2(obj))
https://www.sqlite.org/c3ref/open.html
int sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
What is the syntax to get the address of that pointer in DTrace?
Im using the pid$target::sqlite3_open:return probe to read from the arg1 that was set from the entry probe.
Im currently using:
// Copy pointer bytes from arg1 to kernel, cast to pointer.
(uintptr_t *)copyin(arg1, sizeof(uintptr_t))
Which results in: invalid kernel access in action.
Im on MacOS with SIP enabled, is this the issue?
I may be misunderstanding your question, but what I suspect is that you've misunderstood how sqlite3_open works.
To call sqlite3_open you should have a code that looks like this:
sqlite3 * pDB = NULL;
/* ... */
int result = sqlite3_open("file:database.db", &pDB);
As you see, there's no "pointer to pointer" variable in my code. Instead, sqlite3_ope takes the address of of a pointer variable I allocated on the stack.
To copy that pointer is as simple as:
sqlite3 * pDB2 = pDB
The reason for this is simple:
The sqlite3_open function wants to return two variable, which is impossible in C.
Instead of returning two variables, sqlite3_open returns only one variable directly and returns the second variable indirectly.
In order to return the second, it takes a pointer to a variable of the same type it wants to return. Then, by dereferencing the address and filling in the value, it provides you with the second variable's value.
However, the second variable sqlite3_open returns is a pointer. This is why, in order to return a pointer as a second variable, sqlite3_open requires a pointer to a pointer variable.
Reading the address
In the example above, the pDB variable holds the address for the sqlite3 object (the one allocated by sqlite3_open).
The address, as you know, is simply a number representing a location in the memory. To read the pointer value as a number, simply cast the pointer to a uintptr_t. i.e.:
uintptr_t db_mem_addr_value = (uintptr_t)pDB;
Of course, numbers (and memory addresses) can't be printed as hex strings directly, they need a function that will convert them into hex notation.
Consider that in C you would print the memory address in Hex notation by using printf i.e.,
fprintf(stderr, "%p\n", (void *)pDB);
Using dtrace would be the same. You might want to convert the pointer address to a number, for example, using the lltostr dtrace function:
lltostr((uintptr_t)*(void**)arg1, 16)
Not a dtrace pro, but here are some observations.
uintptr_t is defined to be large enough to hold any pointer converted to an integer. Note that this does not imply that sizeof(uintptr_t) == sizeof(void*). It is perfectly valid (and on some platforms, necessary) for uintptr_t to be strictly larger than a pointer. That means your copyin call might be copying more bytes than are actually there. Try using a size of sizeof(sqlite**) instead.
Also, it's possible that some of OSX's internal protection mechanisms are causing you problems. See the answer on this related question for a good explanation.

Trying to understand how *ramVectorTable gets to ramVectorTable[ ]

I'm trying to understand what this code actually does. Specifically the part after declaring and initializing the pointer ramVectorTable confuses me the most.
It is about function that sets the interrupt vector of the specified system interrupt number. It's for cypress's PsoC 5 that has ARM Cortex M3 if this helps somehow.
#define CY_INT_VECT_TABLE ((cyisraddress **) 0xe000ed08u)
typedef void (* cyisraddress)(void);
cyisraddress CyIntSetSysVector(uint8 number, cyisraddress address)
{
cyisraddress oldIsr;
cyisraddress *ramVectorTable = *CY_INT_VECT_TABLE;
/* Save old Interrupt service routine. */
oldIsr = ramVectorTable[number & CY_INT_SYS_NUMBER_MASK];
/* Set new Interrupt service routine. */
ramVectorTable[number & CY_INT_SYS_NUMBER_MASK] = address;
return (oldIsr);
}
It can be understood as follows:
cyisraddress is a function pointer (a pointer to a function). Here it has the form of a function taking no argument (void) and returning nothing (void). Since this is on ARM Cortex-M3, a pointer shall be a 4-byte value, e.g. 0x20010004. This 4-byte value is the location of the function in memory, i.e. the address of its first instruction. Here, oldIsrand address point to the existing and new ISRs (Interrupt Service Routine) respectively.
In this line #define CY_INT_VECT_TABLE ((cyisraddress **) 0xe000ed08u), 0xe000ed08u is specified to have the type of cyisraddress **, which means pointer to a pointer to a function pointer. Note that 0xe000ed08u is the address of the register VTOR (Vector Table Offset Register), which stores the offset of the vector table base address from memory address 0x00000000 (reference)
When they use *CY_INT_VECT_TABLE, it means the value stored at address 0xe000ed08, which effectively is the address of the vector table. This value has a type of pointer to a function pointer.
Now is the interesting part. For cyisraddress *ramVectorTable, the type of ramVectorTable is a pointer to a function pointer. When reading the code further, you will notice that they use ramVectorTable as an array, which is similar to this simpler version:
int a[10];
Then you can use either a[i] (a as an array of integers) or *(a+i) (a as a pointer to an integer) to access the array elements.
Therefore, ramVectorTable can be used as an array of function pointer, thus ramVectorTable[number & CY_INT_SYS_NUMBER_MASK] is just *(ramVectorTable + number & CY_INT_SYS_NUMBER_MASK), this value has the type of cyisraddress (function pointer).
Lastly, the vector table can be thought of as an array of function pointers, thus ramVectorTable is simply an array of pointers to an ISR.
As you have posted not enough code, I can only guess. The vector table was probably located in the RAM memory. The code just changes one of the addresses to point to the new interrupt handler.
Somewhere in the code the table is probably placed in the memory and it is aligned by 0x200. Another part of the code changes the value of the VTOR register to the address of this table.

Extern arrays usage causing access violation

I have a
LS_Led* LS_vol_leds[10];
declared in one C module, and the proper externs in the other modules that access it.
In func1() I have this line:
/* Debug */
LS_Led led = *(LS_vol_leds[0]);
And it does not cause an exception. Then
I call func2() in another C module (right after above line), and do the same line, namely:
/* Debug */
LS_Led led = *(LS_vol_leds[0]);`
first thing, and exception thrown!!!
I don't think I have the powers to debug this one on my own.
Before anything LS_vol_leds is initialized in func1() with:
LS_vol_leds[0] = &led3;
LS_vol_leds[1] = &led4;
LS_vol_leds[2] = &led5;
LS_vol_leds[3] = &led6;
LS_vol_leds[4] = &led7;
LS_vol_leds[5] = &led8;
LS_vol_leds[6] = &led9;
LS_vol_leds[7] = &led10;
LS_vol_leds[8] = &led11;
LS_vol_leds[9] = &led12;
My externs look like
extern LS_Led** LS_vol_leds;
So does that lead to disaster and I how do I prevent disaster?
Thanks.
This leads to disaster:
extern LS_Led** LS_vol_leds;
You should try this instead:
extern LS_Led *LS_vol_leds[];
If you really want to know why, you should read Expert C Programming - Deep C Secrets, by Peter Van Der Linden (amazing book!), especially chapter 4, but the quick answer is that this is one of those corner cases where pointers and arrays are not interchangeable: a pointer is a variable which holds the address of another one, whereas an array name is an address. extern LS_Led** LS_vol_leds; is lying to the compiler and generating the wrong code to access LS_vol_leds[i].
With this:
extern LS_Led** LS_vol_leds;
The compiler will believe that LS_vol_leds is a pointer, and thus, LS_vol_leds[i] involves reading the value stored in the memory location that is responsible for LS_vol_leds, use that as an address, and then scale i accordingly to get the offset.
However, since LS_vol_leds is an array and not a pointer, the compiler should instead pick the address of LS_vol_leds directly. In other words: what is happening is that your original extern causes the compiler to dereference LS_vol_leds[0] because it believes that LS_vol_leds[0] holds the address of the pointed-to object.
UPDATE: Fun fact - the back cover of the book talks about this specific case:
So that's why extern char *cp isn't the same as extern char cp[]. I
knew that it didn't work despite their superficial equivalence, but I
didn't know why. [...]
UPDATE2: Ok, since you asked, let's dig deeper. Consider a program split into two files, file1.c and file2.c. Its contents are:
file1.c
#define BUFFER_SIZE 1024
char cp[BUFFER_SIZE];
/* Lots of code using cp[i] */
file2.c
extern char *cp;
/* Code using cp[i] */
The moment you try to assing to cp[i] or use cp[i] in file2.c will most likely crash your code. This is deeply tight into the mechanics of C and the code that the compiler generates for array-based accesses and pointer-based accesses.
When you have a pointer, you must think of it as a variable. A pointer is a variable like an int, float or something similar, but instead of storing an integer or a float, it stores a memory address - the address of another object.
Note that variables have addresses. When you have something like:
int a;
Then you know that a is the name for an integer object. When you assign to a, the compiler emits code that writes into whatever address is associated with a.
Now consider you have:
char *p;
What happens when you access *p? Remember - a pointer is a variable. This means that the memory address associated with p holds an address - namely, an address holding a character. When you assign to p (i.e., make it point to somewhere else), then the compiler grabs the address of p and writes a new address (the one you provide it) into that location.
For example, if p lives at 0x27, it means that reading memory location 0x27 yields the address of the object pointed to by p. So, if you use *p in the right hand side of an assignment, the steps to get the value of *p are:
Read the contents of 0x27 - say it's 0x80 - this is the value of the pointer, or, equivalently, the address of the pointed-to object
Read the contents of 0x80 - this finally gives you *p.
What if p is an array? If p is an array, then the variable p itself represents the array. By convention, the address representing an array is the address of its first element. If the compiler chooses to store the array in address 0x59, it means that the first element of p lives at 0x59. So when you read p[0] (or *p), the generated code is simpler: the compiler knows that the variable p is an array, and the address of an array is the address of the first element, so p[0] is the same as reading 0x59. Compare this to the case for which p is a pointer.
If you lie to the compiler, and tell it you have a pointer instead of an array, the compiler will (wrongly) generate code that does what I showed for the pointer case. You're basically telling it that 0x59 is not the address of an array, it's the address of a pointer. So, reading p[i] will cause it to use the pointer version:
Read the contents of 0x59 - note that, in reality, this is p[0]
Use that as an address, and read its contents.
So, what happens is that the compiler thinks that p[0] is an address, and will try to use it as such.
Why is this a corner case? Why don't I have to worry about this when passing arrays to functions?
Because what is really happening is that the compiler manages it for you. Yes, when you pass an array to a function, a pointer to the first element is passed, and inside the called function you have no way to know if it is a "real" array or a pointer. However, the address passed into the function is different depending on whether you're passing a real array or a pointer. If you're passing a real array, the pointer you get is the address of the first element of the array (in other words: the compiler immediately grabs the address associated to the array variable from the symbol table). If you're passing a pointer, the compiler passes the address that is stored in the address associated with that variable (and that variable happens to be the pointer), that is, it does exactly those 2 steps mentioned before for pointer-based access. Again, note that we're discussing the value of the pointer here. You must keep this separated from the address of the pointer itself (the address where the address of the pointed-to object is stored).
That's why you don't see a difference. In most situations, arrays are passed around as function arguments, and this rarely raises problems. But sometimes, with some corner cases (like yours), if you don't really know what is happening down there, well.. then it will be a wild ride.
Personal advice: read the book, it's totally worth it.

C sizes of pointer and value being pointed mismatch

IAR Embedded Workbench for msp430. selected C standard 99
Hello, I am new to pointers and stuck in one place. Here is a part of code:
void read_SPI_CS_P2(uint8_t read_from, int save_to, uint8_t bytes_to_read)
{
uint8_t * ptr;
ptr = save_to;
...
From what I read about pointers I assume that:
uint8_t * ptr; - here I declare what type of data pointer points to (I wanna save uint8_t value)
ptr = save_to; - here I assign adress of memory I would like to write to (it's 0xF900 so int)
It gives me an Error[Pe513]: a value of type "int" cannot be assigned to an entity of type "uint8_t *"
The question is.. why? Size of data that will be saved (to save_to) and size of memory adress can't be different?
From a syntax point of view you can cast an int directly to a pointer changing its value. but is not probably a good idea or something that will help you in this case.
You've to use the compiler and the linker support to instruct them that you want some data at a specific location in memory. Usually you can do this (with IAR toolchains) with #pragma location syntax, using something like:
__no_init volatile uint8_t g_u8SavingLocation # 0xF900;
You cannot simply set the value of a pointer in memory and start to write at that location. The Linker is in charge to decide where stuffs goes in memory, and you can instruct with #pragma and linker setup files on what you want to achieve.
C language has no immediate feature that would allow you to create pointers to arbitrary numerical addresses. In C language pointers are obtained by taking addresses of existing objects (using unary & operator) or by receiving pointers from memory allocation functions like malloc. Additionally, you can create null pointers. In all such cases you never know and never need to know the actual numerical value of the pointer.
If you want to make your pointer to point to a specific address, then formally the abstract C language cannot help you with it. There's simply no such feature in the language. However, in the implementation-dependent portions of the language a specific compiler can guarantee, that if you forcefully convert an integral value (containing a numerical address) to pointer type, the resultant pointer will point to that address. So, if in your case the numerical address is stored in save_to variable, you can force it into a pointer by using an explicit cast
ptr = (unit8_t *) save_to;
The cast is required. Assigning integral values to pointers directly is not allowed in standard C. (It used to be allowed in pre-standard C though).
A better type to store integral addresses would be uintptr_t. int, or any other signed type, is certainly not a good choice for that purpose.
P.S. I'm not sure what point you are trying to make when you talk about sizes. There's no relation between the "size of data that will be saved" and size of memory address. Why?

Resources