Run-time library interposition for sleep() function in C - shared-libraries

I'm having a slight problem with interpositioning the sleep function at run time. I'm currently trying to test library interpositioning at runtime using a simple source code, "sleepdemo.c" and "wakeup.c".
The code(wakeup.c) I have wrote is as following:
1 #ifdef RUNTIME
2 #define _GNU_SOURCE
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <dlfcn.h>
6 #include <stdlib.h>
7
8 /* sleep wrapper function*/
9 unsigned int wakeup(unsigned int secs)
10 {
11 unsigned int (*wakeupp)(unsigned int secs);
12 char *error;
13
14 wakeupp = dlsym(RTLD_NEXT, "sleep"); //Get address of sleep
15 if((error = dlerror()) != NULL){
16 fputs(error, stderr);
17 exit(1);
18 }
19
20 unsigned int elapsed = sleep(secs);
21 printf("Woke up at %d secs.\n", secs - elapsed+1);
22 return elapsed;
23 }
24
25 #endif
And this is the code I'm trying to interpose:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4
5 int main()
6 {
7 int secs = 1;
8
9 printf("This is sleep demo program.\n");
10 sleep(secs);
11 return 0;
12 }
And I have given following instructions to my gcc to create an shared library:
gcc -DRUNTIME -shared -fpic -o mysleep.so wakeup.c -ldl
LD_PRELOAD="./mysleep.so" ./wakeup

Related

I'm trying to create a string with n characters by allocating memories with malloc, but I have a problem

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int n;
printf("Length? ");
scanf("%d", &n);
getchar();
char* str = (char*)malloc(sizeof(char) * (n+1));
fgets(str,sizeof(str),stdin);
for (int i = 0; i < n; i++)
printf("%c\n", str[i]);
free(str);
}
Process results like this!
Length? 5
abcde
a
b
c
?
(I wanted to upload the result image, but I got rejected since I didn't have 10 reputations)
I can't figure out why 'd' and 'e' won't be showing in the results.
What is the problem with my code??
(wellcome to stackoverflow :) (update #1)
str is a pointer to char instead of a character array therefore sizeof(str) is always 8 on 64-bit or 4 on 32-bit machines, no matter how much space you have allocated.
Demo (compilation succeeds only if X in static_assert(X) holds):
#include <assert.h>
#include <stdlib.h>
int main(void){
// Pointer to char
char *str=(char*)malloc(1024);
#if defined _WIN64 || defined __x86_64__ || defined _____LP64_____
static_assert(sizeof(str)==8);
#else
static_assert(sizeof(str)==4);
#endif
free(str);
// Character array
char arr[1024];
static_assert(sizeof(arr)==1024);
return 0;
}
fgets(char *str, int num, FILE *stream) reads until (num-1) characters have been read
Instead of fgets(str,sizeof(str),stdin) please fgets(str,n+1,stdin)
Fixed version:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
int main(void){
int n=0;
printf("Length? ");
scanf("%d",&n);
getchar();
char *str=(char*)calloc((n+1),sizeof(char));
static_assert(
sizeof(str)==sizeof(char*) && (
sizeof(str)==4 || // 32-bit machine
sizeof(str)==8 // 64-bit machine
)
);
fgets(str,n+1,stdin);
for(int i=0;i<n;++i)
printf("%c\n",str[i]);
free(str);
str=NULL;
}
Length? 5
abcde
a
b
c
d
e

Attaching eBPF to KPROBE?

I wrote a simple program to attach to execve system call with a kprobe, but I am unable to see the relevant output.
Here is my one.c (BPF program):
#include <errno.h>
#include <bpf/bpf.h>
#include <stdio.h>
#include <string.h>
#include "bpf_load.h"
#include "bpf_util.h"
#include "libbpf.h"
#define SEC(NAME) __attribute__((section(NAME), used))
SEC("kprobe/execve")
int bpf_prog1(struct pt_regs *ctx)
{
char m[]="hello world";
bpf_trace_printk(m,sizeof(m));
return 0;
}
char _license[] SEC("license") = "GPL";
bpf_load.c (user space loader):
#include "bpf_load.h"
#include <stdio.h>
#include <linux/bpf.h>
#include <sys/resource.h>
int main(int argc, char **argv) {
if (load_bpf_file("one.o")) {
printf("%s", bpf_log_buf);
return 1;
}
return 0;
}
And the Makefile:
CLANG = clang
EXECABLE = monitor-exec
BPFCODE = one
BPFTOOLS = /kernel-src/samples/bpf
BPFLOADER = $(BPFTOOLS)/bpf_load.c
INCLUDE += -I/kernel-src/samples/bpf
INCLUDE += -I/kernel-src/tools/lib
CCINCLUDE += -I/kernel-src/tools/testing/selftests/bpf
CCINCLUDE += -I/kernel-src/tools/lib/bpf
CCINCLUDE += ${INCLUDE}
LOADINCLUDE += -I/kernel-src/tools/include
LOADINCLUDE += -I/kernel-src/tools/perf
LOADINCLUDE += ${INCLUDE}
LIBRARY_PATH = -L/usr/local/lib64
BPFSO = -lbpf
.PHONY: clean bpfload build
clean:
rm -f *.o *.so $(EXECABLE)
build: ${BPFCODE.c} ${BPFLOADER}
$(CLANG) -O2 -DHAVE_ATTR_TEST=0 -target bpf -c $(BPFCODE:=.c) $(CCINCLUDE) -o ${BPFCODE:=.o}
bpfload: build
clang -o $(EXECABLE) -DHAVE_ATTR_TEST=0 -lelf $(LOADINCLUDE) $(LIBRARY_PATH) $(BPFSO) \
$(BPFLOADER) loader.c
$(EXECABLE): bpfload
.DEFAULT_GOAL := $(EXECABLE)
As of now I don't get any errors from the Makefile.
I am getting the following output when I execute ./monitor-exec
invalid relo for insn[6].code 0x85
bpf_load_program() err=22
last insn is not an exit or jmp
processed 0 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
last insn is not an exit or jmp
processed 0 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
I am unable to understand what I am doing wrong. I am just attaching a kprobe and that should print hello world when that system call occurs.
In your eBPF program:
#include <errno.h>
#include <bpf/bpf.h>
#include <stdio.h>
#include <string.h>
#include "bpf_load.h"
#include "bpf_util.h"
#include "libbpf.h"
#define SEC(NAME) __attribute__((section(NAME), used))
SEC("kprobe/execve")
int bpf_prog1(struct pt_regs *ctx)
{
char m[]="hello world";
bpf_trace_printk(m,sizeof(m));
return 0;
}
You use bpf_trace_printk() correctly (although you might want to add a \n at the end of your message or your output will be messy), but it turns out none of the files you include contains the definition for this helper.
bpf_trace_printk() is compiled as part of the kernel and won't ever be compiled into your BPF object file. When trying to load your program, the function load_bpf_file() does a relocation step where it places the number associated to bpf_trace_printk() (in user API) in the relevant instruction of the eBPF bytecode.
But it needs to find this number somewhere. It is defined in header linux/bpf.h (pulled from several of your includes) as FN(trace_printk) (some macro magic going on), resulting de facto in a #define BPF_FUNC_trace_prink 6. But you need to tell your loading function that it corresponds to the bpf_trace_prink() you're calling!
Two solutions:
Manually declare it:
static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) =
(void *) BPF_FUNC_trace_printk;
Or add a header that contains it, e.g. tools/lib/bpf/bpf_helpers.h in kernel repo. In your case:
#include <bpf/bpf_helpers.h>
(Note that this header is generated when compiling libbpf, it is not present in the repository by default.)

Multithreaded program segfaults with OpenSSL and OpenMP

I am using OpenSSL in a multithreaded program in C and having issues. So I wrote a small program to try to narrow down what the problem is. The functions besides the main function were copy pasted from https://github.com/plenluno/openssl/blob/master/openssl/crypto/threads/mttest.c
My program is as follows.
#include<stdio.h>
#include<stdlib.h>
#include<stdarg.h>
#include <strings.h>
#include <string.h>
#include <math.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include<omp.h>
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/crypto.h>
#include <pthread.h>
#include <openssl/lhash.h>
#include <openssl/buffer.h>
#include <openssl/x509.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
static pthread_mutex_t *lock_cs;
static long *lock_count;
void pthreads_locking_callback(int mode, int type, char *file,
int line)
{
#if 0
fprintf(stderr,"thread=%4d mode=%s lock=%s %s:%d\n",
CRYPTO_thread_id(),
(mode&CRYPTO_LOCK)?"l":"u",
(type&CRYPTO_READ)?"r":"w",file,line);
#endif
#if 0
if (CRYPTO_LOCK_SSL_CERT == type)
fprintf(stderr,"(t,m,f,l) %ld %d %s %d\n",
CRYPTO_thread_id(),
mode,file,line);
#endif
if (mode & CRYPTO_LOCK)
{
pthread_mutex_lock(&(lock_cs[type]));
lock_count[type]++;
}
else
{
pthread_mutex_unlock(&(lock_cs[type]));
}
}
unsigned long pthreads_thread_id(void)
{
unsigned long ret;
ret=(unsigned long)pthread_self();
return(ret);
}
void CRYPTO_thread_setup(void)
{
int i;
lock_cs=OPENSSL_malloc(CRYPTO_num_locks() *
sizeof(pthread_mutex_t));
lock_count=OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));
for (i=0; i<CRYPTO_num_locks(); i++)
{
lock_count[i]=0;
pthread_mutex_init(&(lock_cs[i]),NULL);
}
CRYPTO_set_id_callback((unsigned long (*)())pthreads_thread_id);
CRYPTO_set_locking_callback((void (*)())pthreads_locking_callback);
}
void thread_cleanup(void)
{
int i;
CRYPTO_set_locking_callback(NULL);
for (i=0; i<CRYPTO_num_locks(); i++)
{
pthread_mutex_destroy(&(lock_cs[i]));
}
OPENSSL_free(lock_cs);
OPENSSL_free(lock_count);
}
int main(){
BN_CTX *ctx;
ctx = BN_CTX_new();
omp_set_num_threads(158);
#pragma omp parallel
{
int ID = omp_get_thread_num();
BIGNUM *b,*e,*r,*m;
b = BN_new();
e = BN_new();
r = BN_new();
m = BN_new();
BN_set_word(b, 9);
BN_set_word(e, 3);
BN_set_word(m, 5);
BN_mod_exp(r,b,e,m,ctx);
char* result = BN_bn2dec(r);
printf("\n thread = %d result = %s", ID, result); fflush(stdout);
}
thread_cleanup();
}
I get the following error and backtrace, which tells me that BN_mod_exp(r,b,e,m,ctx) is the problem.
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffa9f69700 (LWP 151994)]
0x00007ffff7a97bb6 in BN_CTX_end () from /lib/x86_64-linux-
gnu/libcrypto.so.1.0.0
(gdb) bt
#0 0x00007ffff7a97bb6 in BN_CTX_end () from /lib/x86_64-linux-
gnu/libcrypto.so.1.0.0
#1 0x00007ffff7a940cd in BN_div () from /lib/x86_64-linux-
gnu/libcrypto.so.1.0.0
#2 0x00007ffff7aa3dff in BN_MONT_CTX_set () from /lib/x86_64-
linux-gnu/libcrypto.so.1.0.0
#3 0x00007ffff7a963e5 in BN_mod_exp_mont_word () from /lib/x86_64-
linux-gnu/libcrypto.so.1.0.0
#4 0x0000000000400fef in main._omp_fn.0 () at
debuggingsession.c:106
#5 0x00007ffff77f734a in ?? () from /usr/lib/x86_64-linux-
gnu/libgomp.so.1
#6 0x00007ffff75d9184 in start_thread (arg=0x7fffa9f69700) at
pthread_create.c:312
#7 0x00007ffff730603d in clone () at
../sysdeps/unix/sysv/linux/x86_64/clone.S:111
(gdb) frame 4
#4 0x0000000000400fef in main._omp_fn.0 () at
debuggingsession.c:106
106 BN_mod_exp(r,b,e,m,ctx);
(gdb) print r
$1 = (BIGNUM *) 0x7fff8c000900
(gdb) x 0x7fff8c000900
0x7fff8c000900: 0x00000000
(gdb) print b
$2 = (BIGNUM *) 0x7fff8c0008c0
(gdb) x 0x7fff8c0008c0
0x7fff8c0008c0: 0x8c000940
(gdb) x 0x8c000940
0x8c000940: Cannot access memory at address 0x8c000940
(gdb) print b
$3 = (BIGNUM *) 0x7fff8c0008c0
(gdb) print e
$4 = (BIGNUM *) 0x7fff8c0008e0
(gdb) print m
$5 = (BIGNUM *) 0x7fff8c000920
(gdb) x
Update: I am using OpenSSL and OpenMP in a larger program, the above was just for debugging. In the larger program, I set up multiple threads and each is supposed to write to its own file (not the same file). From here: https://en.wikibooks.org/wiki/OpenSSL/Initialization they say that thread callbacks have to be set up before the initialization functions. I am assuming what this means is that first we call CRYPTO_thread_setup(), and then the OpenSSL library initialization functions. Where does CRYPTO_thread_setup() have to be called from, is it immediately after the first #pragma omp parallel and before the opening brace? When I put it there, along with the library initialization functions, I still get segmentation faults, this time relating to using fclose() within the threads. Any ideas on why this could be happening?

Why thread_id creates not in order?

I tried to create 10 threads, and output each tread index. My code is shown as below, I am wondering why they are repeating instead of arranging in order?
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "util.h"
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
pthread_mutex_t request_buf_lock = PTHREAD_MUTEX_INITIALIZER;
void * worker(void *arg)
{
int thread_id = *(int*)arg;
// int requests_handled = 0;
//requests_handled = requests_handled + 1;
printf("%d\n",thread_id);
}
int main(int argc, char** argv)
{
pthread_t dispatchers[100];
pthread_t workers[100];
int i;
int * thread_id = malloc(sizeof(int));
for (i = 0; i < 10; i++) {
*thread_id = i;
pthread_create(&workers[i], NULL, worker, (void*)thread_id);
}
for (i = 0; i < 10; i++) {
pthread_join(workers[i], NULL);
}
return 0;
}
And the output result is:
4
5
5
6
6
6
7
8
9
9
But I expected it as:
0
1
2
3
4
5
6
7
8
9
Anyone has any idea or advice?
All 10 threads execute in parallel, and they all share a single int object, the one created by the call to malloc.
By the time your first thread executes its printf call, the value of *thread_id has been set to 4. Your second and third threads execute their printf calls when *thread_id has been set to 5. And so on.
If you allocate a separate int object for each thread (either by moving the malloc call inside the loop or just by declaring an array of ints), you'll get a unique thread id in each thread. But they're still likely to be printed in arbitrary order, since there's no synchronization among the threads.

LINUX msgget and queue

I have simple code:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <errno.h>
4 #include <string.h>
5 #include <sys/types.h>
6 #include <sys/ipc.h>
7 #include <sys/msg.h>
8
9 struct my_msgbuf {
10 long mtype;
11 char mtext[200];
12 };
13
14 int main(void){
15 struct my_msgbuf buf;
16 int msqid;
17 key_t key;
18
19 if((key = ftok("main.c", 'B')) == -1) {
20 perror("ftok"); exit(1);
21 }
22
23 if( (msqid = msgget(key, 0644 | IPC_CREAT)) == -1){
24 perror("msgget");
25 exit(1);
26 }
27
28 printf("Enter lines of text, ^D to quit:\n");
29 buf.mtype = 1;
30 while(fgets(buf.mtext, sizeof(buf.mtext), stdin) != NULL){
31 int len = strlen(buf.mtext);
32 if(buf.mtext[len-1] == '\n') buf.mtext[len-1] = '\0';
33 if(msgsnd(msqid, &buf, len+1,0) == -1){
34 perror("msgsnd");
35 }
36
37 }
38
39 if(msgctl(msqid, IPC_RMID, NULL) == -1){
40 perror("msgctl");
41 exit(1);
42 }
43
44 return 0;
45 }
and next step what i do:
gcc -o main main.c
next step run:
./main
and results:
msgget: no space left on device
how can I repair it? I'm working on university server (connecting by putty), it can be answer about this problem?
According to the man page, ENOSPC is the error for:
A message queue has to be created but the system limit for the maximum number of message queues (MSGMNI) would be exceeded.
If it's a server, it means there's too many message queues created by other users (not unlikely if this is some homework assignment and other students also work on the server). You can see the MSGMNI value with cat /proc/sys/kernel/msgmni. Only the admin can change it however.

Resources