Linux: brk() error 'Cannot allocate memory' - c

I'm trying to use the brk() function in a C program. My goal is to use it directly (as part of a larger test) by checking the current program break (pb) with
void *current_break = sbrk(0);
executing a malloc (for testing as malloc should sometimes execute brk if the allocated space is large enough)
void* mallow_return = malloc(1);
and than directly executing brk() by using the current address + an increment (and check if this increase the pb):
int increase = 0x01;
void * newbreak = current_break + increase;
int return_value = brk(&newbreak);
My problem is, that neither with a large malloc (malloc(5000;)) nor with (aligned or unaligned) brk() call the pb is changed. When checking the errno I get a
Cannot allocate memory!error (as given bystrerror(errno)
Can anybody see why I'm not able to increase the program break in anyway?
Thanks for any hints!
(System is: Debian 10 (buster) with kernel 4.19)
Edit: As requested this is the main function with includes:
#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
void main(int argc, char **argv)
{
printf("[+] Get current program break\n");
void *current_break = sbrk(0);
printf("\t[+] Current break point=\t%#x\n", current_break);
printf("[+] Malloc should call brk as well\n");
void* mallow_return = malloc(1);
printf("[+] Check if malloc changes PB\n");
void *after_break = sbrk(0);
printf("\t[+] After malloc pbreak=\t%#x\n", after_break);
int increase = 0x01;
printf("\t[+] Increasing p-break direclyby %d\n", increase);
void * newbreak = current_break + increase;
printf("\t[+] Setting break point to=\t%#x\n", newbreak);
int return_value = brk(&newbreak);
//check if error was thrown
int errornumber = errno;
if (errornumber != 0)
{
printf("\t[+] Error: %s!\n", strerror(errornumber));
return -1;
}
//check if pb was set now
printf("\t[?] New program break value?\t%#x\n", sbrk(0));
printf("[?] Return value of brk: %d\n", return_value);
return;
}

(Thanks to #Antii Haapala, who posted this as a comment.)
We need to remove the ampersand here:
int return_value = brk(&newbreak);
That line should be simply
int return_value = brk(newbreak);

Related

fopen() in c : segmentation fault

I'm trying to wrap the C library functions malloc and free to detect whether there is memory leakage in my code. I extend the malloc/free functions by adding to them an fprintf to write to a file the address of the malloc/free and the size.
Compiling this code with gcc or clang gives a segmentation fault in the fopen() line.
Here is the command:
gcc -o mainapp main.c -Wall -Wextra
I placed the fopen inside the malloc and free function but also get the same issue: Segmentation fault (core dumped)
I can't find an explanation for the issue.
Here is my complete code:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define __USE_GNU
#include <dlfcn.h>
#define TEST_MEM_LEAK 1 // a value of 1 means to join the memory leak detection, and a value of 0 means not to join
#if TEST_MEM_LEAK
typedef void *(*malloc_t)(size_t size);
malloc_t malloc_f = NULL;
typedef void (*free_t)(void *p);
free_t free_f = NULL;
int malloc_flag = 1; // It is used to prevent repeated recursion and cannot exit because the printf function will call malloc for memory allocation
int free_flag = 1;
const char* logFileName = "/home/hammamiw/Documents/HeapMonitor/allocs.log";
FILE* fp = NULL;
void initCheck()
{
fp = fopen("/home/hammamiw/Documents/HeapMonitor/allocs.log", "w");
}
void *malloc(size_t size)
{
if(malloc_flag) {
initCheck();
malloc_flag = 0; // Used to prevent printf from causing an error when calling malloc recursively
void *p = malloc_f(size);
fprintf(fp, "malloc, %lx, %lu\n", (uintptr_t)p, size);
//printf("m\n");
malloc_flag = 1; // It is used to ensure that the initial value of flag flag is consistent when malloc in this file is called again
return p;
}
else {
return malloc_f(size); // Here, the malloc function in the system library obtained by dlsym is called
}
}
void free(void *p)
{
initCheck();
if(free_flag) {
//initCheck();
free_flag = 0;
fprintf(fp, "F, %lx\n", (uintptr_t)p);
//printf("f\n");
free_f(p);
free_flag = 1;
} else {
free_f(p);
}
}
#endif
int main()
{
#if TEST_MEM_LEAK // the part from if to endif can be divided into function calls
malloc_f = dlsym(RTLD_NEXT, "malloc");
if(!malloc_f) {
printf("load malloc failed: %s\n", dlerror());
return 1;
}
free_f = dlsym(RTLD_NEXT, "free");
if(!free_f) {
printf("load free failed: %s\n", dlerror());
return 1;
}
#endif
void *p1 = malloc(10); //The malloc function in this article will be called first
void *p2 = malloc(20);
//Here, p2 is not released and there is a memory leak. Judge by checking whether the number of malloc and free times printed is the same
free(p2);
free(p1);
return 0;
}
NOTE: the code works well if I use printf instead of fprintf -> prints "f" and "m" at each free and malloc call.
Environment: Ubuntu 22.04, C language, GCC compiler version 11.3.0
You need to set malloc_flag before calling fopen(). Then you will protect against recursion not only via fprintf() but also via fopen().

Logging memory allocation functions using DLL injection

I have a simple program let's call it a victim:
#include <stdio.h>
#include <stdlib.h>
int
main(void)
{
int *a = malloc(200);
printf("%p\n", a);
}
And I want to inject a shared object into this program that will log all the calls to the malloc function. So it will works like a memory logger:
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
void *
malloc(size_t n)
{
static void * (*real_malloc)(size_t) = NULL;
if (real_malloc == NULL) {
real_malloc = dlsym(RTLD_NEXT, "malloc");
if (real_malloc == NULL) {
#if 0
printf("MEMORY FILTER: can't find the real malloc() function: %s\n", dlerror());
#endif
exit(EXIT_FAILURE);
}
}
void *result = real_malloc(n);
#if 0
if (result != NULL)
printf("MEMORY FILTER: allocated %zu bytes at address %p.\n", n, result);
else
printf("MEMORY FILTER: failed to allocate %zu bytes.\n", n);
#endif
return result;
}
And then I run the victim as follows:
$ LD_LIBRARY_PATH=. LD_PRELOAD=libmemlog.so ./victim
0x55e0747792a0
It works fine but when I uncomment #if 0 ... #endif blocks when the printf function is called then I get a segmentation fault. This is happens because printf calls malloc inside itself and we got an endless recursion which eventually crushes.
How can I get logging work in this case?

Error reading returned value from passing struct pointer to pthread_exit() in C

I'm trying to pass pointers to struct lower_hyper_id from a thread to the main thread, by the means of pthread_exit() function, that would compare and output the value in the struct. However, i receive an error (Segmentation fault) when i am trying to use the returned value and cast it to the struct.
thread that creates and returns the struct:
void *compute(void *arg){
lower_hyper_id *data = (lower_hyper_id *)malloc(sizeof(lower_hyper_id));
//some code
//i debug the program, and at this point, the struct i want
//to return has the values i want.
pthread_exit((void *)data);
}
in the main:
lower_hyper_id l_hyper_id;
int main(){
void *ap_state;
lower_hyper_id values;
void *ret;
//some code
for (int i = 0; i < NUMBER_OF_FILTERING_THREADS; i++)
{
s = pthread_join(filtering_threads[i], (void *)&ret);
//some error checking
values = *((lower_hyper_id *)ret); //this is where i receive the error
if (values.lowest_cost <= l_hyper_id.lowest_cost)
{
l_hyper_id.hyper_id = values.hyper_id;
l_hyper_id.lowest_cost = values.lowest_cost;
}
free(ret);
}
I have already looked at answers in the stackoverflow such as this question, but it hasn't helped me resolving this. I actually changed the code to be exactly equal to the code in this answer, but still it gives me an error.
You're not testing if malloc returned NULL. That could be an issue if you're allocing a large chunk and the allocation can fail.
Other than that, I don't think the problem is in the return value passing.
pthread_exit()ing with a mallocd pointer should work just fine.
A minimial working example:
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void *compute (void *arg)
{
printf("thread=%llx\n", (unsigned long long)pthread_self());
size_t sz = strlen("hello world")+1;
char *ret = malloc(sz+1);
if(ret) memcpy(ret, "hello world", sz+1);
return ret;
}
int main()
{
printf("thread=%llx\n", (unsigned long long)pthread_self());
pthread_t ptid;
int er;
if((er=pthread_create(&ptid,0,compute,0))) return errno=er,perror(0),1;
void *retval;
if((er=pthread_join(ptid,&retval))) return errno=er,perror(0),1;
printf("thread returned: %s\n", (char*)retval);
free(retval);
}

Linux shared memory segfault

I have been having difficulties getting a useable shared memory region in a sample C program (RHEL 6). It should be quite basic so I'm not sure what I'm doing wrong but when I allocate the memory region it appears to be accessible initially. However, when I return from an initialization function the memory region is no longer accessible and I get a segfault when I try to access the memory region.
I have tried running it through GDB and all I see is a segfault on the line where I try to do this memcpy:
memcpy(ptr, &x, sizeof(x));
It's probably something minor that I just cannot see for some reason! Thanks.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <errno.h>
void* shared_mem[2];
int init(int *memAddress);
int main() {
if(init((int*)&shared_mem[0]) < 0) {
printf("Error initializing, exiting\n");
exit(1);
}
int *ptr=shared_mem[0];
int x=278;
memcpy(ptr, &x, sizeof(x));
printf("data written to memAddress: %d\n", shared_mem[0]);
}
// Initialize shared memory region and insert test data
int init(int *memAddress) {
key_t key = 234324;
int size = sizeof(int);
static const unsigned int flags = S_IRUSR | S_IWUSR | S_IRGRP |
S_IWGRP | S_IROTH | S_IWOTH | IPC_CREAT;
int id = shmget(key, size, flags);
if (id < 0)
{
return(-3);
}
*memAddress = shmat(id,0,0);
if ((int)memAddress == -1)
{
return(-4);
}
int z=123;
memcpy(memAddress, &z, sizeof(z));
printf("data written to memAddress: %d\n", memAddress[0]);
return(0);
}
Something is completely wrong here and it begins with the following line:
int init(int *memAddress)
You pass a pointer to shared_mem to the function "init". Therefore memAddress will point to the 8- or 16-byte (depending on the CPU type) array shared_mem.
*memAddress = shmat(id,0,0);
If sizeof(void *) == sizeof(int) this would work however then you'd have to do other pointer casts. shared_mem[0] will contain a pointer to the memory, casted to int.
If sizeof(void *) != sizeof(int) you'll already have problems here.
(int)memAddress == -1
This will not work in any case:
(int)memAddress is the address of the array shared_mem and not the value returned by shmat.
memcpy(memAddress, &z, sizeof(z));
This will write the value 123 into shared_mem[0]. Therefore the following instruction:
memcpy(ptr, &x, sizeof(x));
... will be equal to:
memcpy((void *)123, &x, sizeof(x));
... which will cause the error.
The correct function would look like this:
int init(void **memAddress) { // void **
...
*memAddress = shmat(id,0,0); // This was correct!
if ((int)(*memAddress) == -1) // Note the "*"
...
memcpy(*memAddress, &z, sizeof(z)); // Note the "*"
}
Your init function isn't modifiying shared_mem with the allocated memory address - the parameter to init() needs to be declared as int **memaddress for example look at your line *memaddress=shmget(...) with parameter defined as int *memaddress this is storing the result of shmget as an integer, that isn't right. You need to check all the related uses of memaddress are correct. You can check this in gdb, look at the result of shmget, make sure that is being stored in shared_mem[0].

Is there a way to print something in case of a segfault? C

For example, If my program segaults, instead of gcc printing to the console "Segmentation Fault" can I have it print "Ya dun goofed"?
Segfaults are generally caused by dereferencing a garbage pointer. Therefore, while the literal answer to what you asked is that, as kaylum said, you can catch SIGSEGV in a signal handler, the better answer is that, before you use a pointer, you should ask yourself, “How do I know that this pointer is valid and that I am staying within the bounds of my array?"
If you don’t know that, your program has a bug. If you think you do, you can turn the assumption into an assertion which, since your pointer is valid, will always pass. For example:
void fill_array( unsigned fill_this_many,
size_t array_size,
int a[array_size] )
{
assert(a);
assert( array_size >= fill_this_many );
for ( unsigned i = 0; i < fill_this_many; ++i )
a[i] = f(i);
return;
}
You’ll now get a detailed message when you’re about to dereference a null pointer or write past the end of your array, which will contain more useful information for debugging than, "There was a segfault somewhere," and it might even save you from silent memory corruption too.
If you want to write your own message, you can define a wrapper such as:
#include <stdio.h>
#include <stdlib.h>
void fatal_error_helper( const char* file, int line, const char* restrict message )
{
fflush(stdout); // Don’t cross the streams!
fprintf( stderr, "\nError in %s, line %d: %s\n", file, line, message );
exit(EXIT_FAILURE);
}
#define fatal_error(message) fatal_error_helper( __FILE__, __LINE__, (message) )
int main(void)
{
int *big_array = calloc( 1073741824UL, sizeof(int) );
if (!big_array)
fatal_error("Not enough memory.");
return EXIT_SUCCESS;
}
And a contrived example of how to do bounds-checking at compile time, so as to fail gracefully if your constants change:
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#define LENGTH 14U
#define M 5U
int main(void)
{
char message[LENGTH] = "hello, world!";
static_assert( M < LENGTH, "Tried to capitalize more letters than the array can hold." );
for ( unsigned i = 0; i < M; ++i )
message[i] = toupper(message[i]);
printf( "%s\n", message );
return EXIT_SUCCESS;
}
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
void segv_handler(int sig)
{
(void)sig;
const char *msg = "Hello signal handler!";
size_t len = strlen(msg);
write(STDERR_FILENO, msg, len);
abort();
}
int main()
{
struct sigaction act;
act.sa_handler = segv_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGSEGV, &act, NULL);
int *nullint = 0;
*nullint = 4;
return 0;
}
EDIT: I tough code is pretty much explanation how to do it. Of course there is a lot details that needs to be taken into account when writing signal handlers.
Basic limitation is that signal handler can't access any variable/structure that isn't written to atomically because handler could be called between any two instructions in your program. That means no calls to heap memory management, buffered io like printf, etc.
More details what the code does can be found from man pages stdout, sigaction and write.

Resources