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.)
Related
On linux and macOS, directories can be nested to seemingly arbitrary depth, as demonstrated by the following C program. However, on macOS but not on linux, there seems to be a hard limit on the nesting level returned by getcwd, specifically a nesting level of 256. When that limit is reached, getcwd returns ENOENT, a rather strange error code. Where does this limit come from? Is there a way around it?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
void fail(char *msg) { perror(msg); exit(1); }
void create_nested_dirs(int n) {
int i;
char name[10];
char cwd[10000];
if (chdir("/tmp") < 0) fail("chdir(\"/tmp\")");
for (i=2; i<=n; i++) {
sprintf(name, "%09d", i);
printf("%s\n",name);
if (mkdir(name, 0777) < 0 && errno != EEXIST) fail("mkdir");
if (chdir(name) < 0) fail("chdir(name)");
if (getcwd(cwd, sizeof(cwd)) == NULL) fail("getcwd");
printf("cwd = \"%s\" strlen(cwd)=%d\n", cwd, strlen(cwd));
}
}
int main() {
long ret = pathconf("/", _PC_PATH_MAX);
printf("PATH_MAX is %ld\n", ret);
create_nested_dirs(300);
return 0;
}
Update
The above program was updated to print the value returned by pathconf("/", _PC_PATH_MAX) and to print the length of the path returned by getcwd.
On my machine running macOS Mojave 10.14, the PATH_MAX is 1024 and the longest string correctly returned by getcwd is 2542 characters long. Then a 2552 character long directory of nesting depth 256 is created by mkdir and then after a successful chdir to that directory a getcwd fails with ENOENT.
If the sprintf(name, "%09d", i); is changed to sprintf(name, "%03d", i); the paths are considerably shorter but the getcwd still fails when the directory nesting depth reaches 256.
So the limiting factor here is the nesting depth, not PATH_MAX.
My understanding of the source code here is that the meat of the work is done by the call fcntl(fd, F_GETPATH, b) so the problem may be in fcntl.
I get bus error (core dumped) when trying to write to memory. I want to write to a binary file using mmap() and open() functions in Linux. I want to write integers from 1 to 100 in the binary file by mapping it to memory instead of writing to the file directly.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>
#define FILE_SIZE 0x100
int main(int argc,char *argv[])
{
int fd;
void *pmap;
printf("im here");
//fd=open(argv[1],O_RDWR|O_CREAT,S_IRUSR|S_IWUSR);
fd=open("numbers.raw",O_RDWR);
if(fd == -1)
{
perror("open");
exit(1);
}
lseek(fd,FILE_SIZE+1,SEEK_SET); //checking the file length
lseek(fd,0,SEEK_SET);//points to start of the file
//create the memory mapping
pmap = mmap(0,FILE_SIZE,PROT_WRITE,MAP_SHARED,fd,0);
if(pmap == MAP_FAILED)
{
perror("mmap") ;
close(fd);
exit(1);
}
close(fd);
for(int i=1;i<=100;i++)
sprintf(pmap,"%d",i);
return 0;
}
Your comment says you are "checking the file length" but you never check the return value of that call. I'd bet it is failing since your file is not large enough, hence the bus error later.
There are multiple other unrelated mistakes in your file as well, by
the way:
Your file size assumes 0x100 bytes are enough to store 100 integers in binary. This is not the case for 64 bit systems.
You aren't actually storing binary numbers - you are storing strings of the numbers.
You aren't advancing where you write, so you write all the numbers at the start of the file, one on top of the other.
I have configure.in script. I want to invoke configure ( after autoheader && autoconf ) and see value of PAGE_SHIFT macro from system header page_types.h. Something like this:
checking PAGE_SHIFT... 12
I've tried those:
1.
AC_CHECK_DECL([PAGE_SHIFT],[HAVE_PAGE_SHIFT=$PAGE_SHIFT],[],
[#include <linux/module.h>])
AC_MSG_NOTICE([${HAVE_PAGE_SHIFT}])
Result: macro PAGE_SHIFT was detected, but haven't been printed
checking whether PAGE_SHIFT is declared... yes
configure:
2.
HAVE_PAGE_SHIFT="Unknown"
AC_MSG_CHECKING([PAGE_SHIFT])
AC_COMPILE_IFELSE(
[
AC_LANG_PROGRAM([
#include <linux/module.h>
#include <stdio.h>
],
[
printf("%d\n", PAGE_SHIFT);
])],
[HAVE_PAGE_SHIFT="$PAGE_SHIFT"], [])
AC_MSG_RESULT([${HAVE_PAGE_SHIFT}])
Result: doesn't work
checking PAGE_SHIFT...
3.
AC_MSG_CHECKING(['PAGE_SHIFT' value])
AC_RUN_IFELSE(
[
#include <linux/module.h>
#include <stdio.h>
int
main ()
{
printf("%d\n", PAGE_SHIFT);
return 0;
}
]
)
Result: works, but can't be used with cross-compile
checking 'PAGE_SHIFT' value... 12
method was suggested by Brett Hale
Autoconf will generate something like this:
#include <linux/module.h>
static long int longval () { return PAGE_SHIFT; }
static unsigned long int ulongval () { return PAGE_SHIFT; }
#include <stdio.h>
#include <stdlib.h>
Result: doesn't work with kernel headers
In file included from /usr/include/stdlib.h:314:0,
from conftest.c:125:
/usr/include/x86_64-linux-gnu/sys/types.h:44:18: error: conflicting types for 'loff_t'
typedef __loff_t loff_t;
^
In file included from /lib/modules/4.2.0-18-generic/build/arch/x86/include/asm/page_types.h:5:0,
from [...],
from conftest.c:121:
/lib/modules/4.2.0-18-generic/build/include/linux/types.h:45:26: note: previous declaration of 'loff_t' was here
typedef __kernel_loff_t loff_t;
Autoconf version: autoconf (GNU Autoconf) 2.69
I would recommend using the AC_COMPUTE_INT macro. e.g.,
AC_MSG_CHECKING(['PAGE_SHIFT' value])
AC_COMPUTE_INT([PAGE_SHIFT_VAL], [PAGE_SHIFT], [[#include <linux/module.h>]],
AC_MSG_FAILURE([linux/module.h: could not determine 'PAGE_SHIFT' value]))
AC_MSG_RESULT([$PAGE_SHIFT_VAL])
Alternatively, you can replace the FAILURE macro with PAGE_SHIFT_VAL=0 and test that value for (0) if the error is recoverable.
Note that there's nothing magical about the variable name PAGE_SHIFT_VAL, in this context; you can use another name. You still need the AC_SUBST if you want this value substituted in generated files, like config.h, or those listed in AC_CONFIG_FILES.
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.
I want to create a file and map it into memory. I think that my code will work but when I run it I'm getting a "bus error". I searched google but I'm not sure how to fix the problem. Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
int main(void)
{
int file_fd,page_size;
char buffer[10]="perfect";
char *map;
file_fd=open("/tmp/test.txt",O_RDWR | O_CREAT | O_TRUNC ,(mode_t)0600);
if(file_fd == -1)
{
perror("open");
return 2;
}
page_size = getpagesize();
map = mmap(0,page_size,PROT_READ | PROT_WRITE,MAP_SHARED,file_fd,page_size);
if(map == MAP_FAILED)
{
perror("mmap");
return 3;
}
strcpy(map, buffer);
munmap(map, page_size);
close(file_fd);
return 0;
}
You are creating a new zero sized file, you can't extend the file size with mmap. You'll get a bus error when you try to write outside the content of the file.
Use e.g. fallocate() on the file descriptor to allocate room in the file.
Note that you're also passing the page_size as the offset to mmap, which doesn't seem to make much sense in your example, you'll have to first extend the file to pagesize + strlen(buffer) + 1 if you want to write buf at that location. More likely you want to start at the beginning of the file, so pass 0 as the last argument to mmap.