I am trying to write some uprobes for tracing nginx and am struggling to build the bpf program. More specifically, when including nginx header files in order to parse data, the build does not register my 64-bit architecture and wants to include gnu/stubs-32.h. Building without ngx_http.h works fine. This may not be specifically a libbpf issue, however I do not have the same problems with bpftrace or BCC where inclusion works without problems.
Any suggestions as to how to fix this is greatly appreciated.
Code
nginx.bpf.c
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include "ngx_http.h"
char LICENSE[] SEC("license") = "Dual BSD/GPL";
SEC("uprobe//usr/sbin/nginx:ngx_http_finalize_request")
int handle_ngx_http_finalize_request(struct pt_regs* ctx)
{
int pid = bpf_get_current_pid_tgid() >> 32;
bpf_printk("Is this getting triggered? %d.\n", pid);
return 0;
}
nginx.c
#include <stdio.h>
#include <unistd.h>
#include <sys/resource.h>
#include <bpf/libbpf.h>
#include "nginx.skel.h"
static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
{
return vfprintf(stderr, format, args);
}
int main(int argc, char **argv)
{
struct nginx_bpf *skel;
int err;
libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
libbpf_set_print(libbpf_print_fn);
skel = nginx_bpf__open_and_load();
if (!skel) {
fprintf(stderr, "Failed to open and load BPF skeleton\n");
return 1;
}
err = nginx_bpf__attach(skel);
if (err) {
fprintf(stderr, "Failed to auto-attach BPF skeleton: %d\n", err);
goto cleanup;
}
printf("Successfully started!\n");
for (;;) {
sleep(1);
}
cleanup:
nginx_bpf__destroy(skel);
return -err;
}
error message
❯ make
BPF .output/nginx.bpf.o
In file included from nginx.bpf.c:4:
In file included from /home/nela/master/nginx-1.18.0/src/http/ngx_http.h:12:
In file included from /home/nela/master/nginx-1.18.0/src/core/ngx_config.h:26:
In file included from /home/nela/master/nginx-1.18.0/src/os/unix/ngx_linux_config.h:18:
In file included from /usr/include/x86_64-linux-gnu/sys/types.h:25:
In file included from /usr/include/features.h:510:
/usr/include/x86_64-linux-gnu/gnu/stubs.h:7:12: fatal error: 'gnu/stubs-32.h' file not found
# include <gnu/stubs-32.h>
^~~~~~~~~~~~~~~~
1 error generated.
make: *** [Makefile:106: .output/nginx.bpf.o] Error 1
System Information
❯ echo $CPATH
/home/nela/master/nginx-1.18.0/src/http/modules:/home/nela/master/nginx-1.18.0/src/http/v2:/home/nela/master/nginx-1.18.0/src/http:/home/nela/master/nginx-1.18.0/src/event:/home/nela/master/nginx-1.18.0/src/core:/home/nela/master/nginx-1.18.0/src:/home/nela/master/nginx-1.18.0/src/os/unix:/home/nela/master/nginx-1.18.0/objs:/home/nela/master/nginx-1.18.0:/usr/src/linux-headers-5.15.0-56-generic/include:/usr/src/linux-headers-5.15.0-56/include:/usr/include
❯ uname -a
Linux nelasus 5.15.0-53-generic #59-Ubuntu SMP Mon Oct 17 18:53:30 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
❯ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 22.04.1 LTS
Release: 22.04
Codename: jammy
Related
I'm new to PlatformIo, Unity and Arduino/Esp32. I'm following this tutorial. When I run the build via Code, I get this message:
Processing native (platform: native)
--------------------------------------------------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
LDF: Library Dependency Finder -> <redacted>
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 2 compatible libraries
Scanning dependencies...
Dependency Graph
|-- Unity # 2.5.2
Building in release mode
Compiling .pio/build/native/src/main.o
Compiling .pio/build/native/lib9be/Unity/unity.o
In file included from .pio/libdeps/native/Unity/src/unity.c:7:
In file included from .pio/libdeps/native/Unity/src/unity.h:21:
.pio/libdeps/native/Unity/src/unity_internals.h:11:10: fatal error: 'unity_config.h' file not found
#include "unity_config.h"
^~~~~~~~~~~~~~~~
1 error generated.
*** [.pio/build/native/lib9be/Unity/unity.o] Error 1
=============================================== [FAILED] Took 0.71 seconds ===============================================
I don't see the missing file mentioned in the tutorial. And I'm unclear on my path forward. Here is my code (basically right from the tutorial):
/test/test_circular_buffer.c
#include <unity.h>
#include "cbuffer.h"
void setUp(void) {
// set stuff up here
}
void tearDown(void) {
// clean stuff up here
}
void test_circular_buffer_empty_after_init() {
cbuffer_t buff;
cbuffer_init(&buff);
TEST_ASSERT_TRUE(cbuffer_empty(&buff));
}
void test_circular_buffer_not_empty_after_new_element_added() {
cbuffer_t buff;
cbuffer_init(&buff);
cbuffer_add(&buff, 100);
TEST_ASSERT_FALSE(cbuffer_empty(&buff));
}
int main( int argc, char **argv) {
UNITY_BEGIN();
RUN_TEST(test_circular_buffer_empty_after_init);
UNITY_END();
}
/src/main.c
#include <stdio.h>
int main()
{
printf("Hello World from PlatformIO!\n");
return 0;
}
/platformio.ini
[env:native]
platform = native
lib_deps = throwtheswitch/Unity#^2.5.2
I am trying to list custom chains in netfilter, but following code is giving me only the default chains in filter table when ran on Debian 11. On Ubuntu 20.04 it's listing other chains as well. Can anyone tell me what I am doing wrong? Thank you in advance.
Shell:
Debian 11, kernel 5.10.0-8-amd64, iptables 1.8.7-1
iptables -N TEST
./listchains
Chain name is INPUT
Chain name is FORWARD
Chain name is OUTPUT
Ubuntu 20.04, kernel 5.4.0-40-generic, iptables 1.8.4-3ubuntu2
iptables -N TEST
./listchains
Chain name is INPUT
Chain name is FORWARD
Chain name is OUTPUT
Chain name is TEST
C code:
// compile with gcc -Wall -o listchains listchains.c -lip4tc
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/errno.h>
#include <libiptc/libiptc.h>
int main(void) {
struct xtc_handle *h;
const char *chain = NULL;
const char *tablename = "filter";
h = iptc_init(tablename);
if (!h) {
printf("Error initializing: %s\n", iptc_strerror(errno));
exit(errno);
}
chain = iptc_first_chain(h);
while (chain) {
printf("Chain name is %s\n", chain);
chain = iptc_next_chain(h);
}
}
I am unable to compile to c program for 32bit machine from 64bit linux machine using command gcc -m32 -Werror a.c -o a
It shows me the error
In file included from a.c:1:
/usr/include/stdio.h:27:10: fatal error: bits/libc-header-start.h: No such file or directory
#include <bits/libc-header-start.h>
^~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
I check the stdio.h in /usr/include/stdio.h
here in my machineLinux kali 4.19.0-kali4-amd64 #1 SMP Debian 4.19.28-2kali1 (2019-03-18) x86_64 GNU/Linux the line #include <bits/libc-header-start.h> is included while in other ubuntu 64 bit this line is not included
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int functionFunction(char *param)
{
char *localString = "Conjunction Function";
int localInt = 0xdeadbeef;
char localString2[10];
strcpy(localString2,param);
return 1;
}
int main(int argc, char *argv[])
{
char *localString = "Main Function";
int localInt = 0x11223344;
functionFunction(argv[1]);
return 0;
}
Try with Installing gcc-multilib:
this might (not 100% sure) work:, but in my scenario it did work;
sudo apt-get install gcc-multilib
I am trying to perform a hook to the function 'do_execve()' on Linux kernel using Jprobes, but I'm having issues with certain systems. I tried using this code I found online on an Ubuntu 12, 64 bit (Kernel Version 3.11):
Hook.c:
/* Trace do_execv. Taken basically from Documentation/kprobes.txt */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kprobes.h>
#include <linux/kallsyms.h>
/*
* Pre-entry point for do_execve.
*/
static int my_do_execve(char * filename,
char __user *__user *argv,
char __user *__user *envp,
struct pt_regs * regs)
{
printk("do_execve for %s from %s\n", filename, current->comm);
/* Always end with a call to jprobe_return(). */
jprobe_return();
/*NOTREACHED*/
return 0;
}
static struct jprobe my_jprobe = {
.entry = (kprobe_opcode_t *) my_do_execve
};
int init_module(void)
{
int ret;
my_jprobe.kp.addr =
(kprobe_opcode_t *) kallsyms_lookup_name("do_execve");
if (!my_jprobe.kp.addr) {
printk("Couldn't find %s to plant jprobe\n", "do_execve");
return -1;
}
if ((ret = register_jprobe(&my_jprobe)) <0) {
printk("register_jprobe failed, returned %d\n", ret);
return -1;
}
printk("Planted jprobe at %p, handler addr %p\n",
my_jprobe.kp.addr, my_jprobe.entry);
return 0;
}
void cleanup_module(void)
{
unregister_jprobe(&my_jprobe);
printk("jprobe unregistered\n");
}
MODULE_LICENSE("GPL");
Makefile:
# This is taken straight from Documentation/kprobes.txt
obj-m := trace-exec.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
rm -f *.mod.c *.ko *.o
The module worked as expected. It was first compiled correctly on the system, and then inserted with the function 'insmod' (with ROOT privileges). Running dmesg shows the correct output:
Planted Jprobes at [ADDRESS HERE], handler addr [ADDRESS HERE]
do_execve for /bin/sh from wcstatusd [PRINTED FOR ANY EXECUTED PROCESS]
The problem occurred when I tried the same code on Ubuntu 14, 64 bit (kernel version 3.13) system. I recompiled it on the system and inserted it just as I did on the previous system, however it didn't work this time. I don't get any errors, and the success message ("Planted jprobe at [ADDRESS WAS HERE], handler addr [ADDRESS WAS HERE]") is printed, but the 'do_execve' line isn't printed. I scanned Google but couldn't find an explanation or a solution. Any ideas?
NOTE: I also tried hooking 'do_fork()' on Ubuntu 14 and it worked! It's just something with 'do_execve()' and I can't figure what!
Definition for do_execve() is in exec.c
http://lxr.free-electrons.com/source/fs/exec.c?v=3.11#L1584
Here is the code for do_execve(). Just add a line after
int do_execve(struct filename *filename,const char __user *const __user *__argv,const char __user *const __user *__envp)
{
struct user_arg_ptr argv = { .ptr.native = __argv };
struct user_arg_ptr envp = { .ptr.native = __envp };
return do_execveat_common(AT_FDCWD, filename, argv, envp, 0);
}
EXPORT_SYMBOL(do_execve); // Add this line.
This file will be in linux/fs/exec.c. Add the EXPORT_SYMBOL() line after the fuction.And after that do make, make install, and reboot.
Its almost like the hooking because we have to build and install the kernel again. Given that you are not intercepting the call by modifying the systemcall address at runtime.
I set up Allegro 5, and could compile the following code with success:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <allegro5/allegro.h>
void error(char *msg)
{
fprintf(stderr,"%s : %s\n", msg, strerror(errno));
exit(1);
}
int main(int argc, char **argv)
{
ALLEGRO_DISPLAY *display = NULL;
if(!al_init())
error("Could not initailize allegro");
display = al_create_display(640, 480);
if(!display)
error("fail to display");
al_clear_to_color(al_map_rgb(0,0,0));
al_flip_display();
al_rest(10.0);
al_destroy_display(display);
return 0;
}
But after running it, it failed with the error message:
Could not initailize allegro : No such file or directory.
I don't know what is wrong. My OS is Ubuntu, I'd compiled the code successfully with:
gcc try.c -lallegro
But could not run it with:
./a.out
Allegro needs a configuration file and possibly other files to operate. From your comment, that is probably why it is not working. From the readme:
"
Normally the setup program and allegro.cfg will go in the same directory as the Allegro program they are controlling. This is fine for the end user, but it can be a pain for a programmer using Allegro because you may have several programs in different directories and want to use a single allegro.cfg for all of them. If this is the case you can set the environment variable ALLEGRO to the directory containing your allegro.cfg, and Allegro will look there if there is no allegro.cfg in the current directory.
...
Under Unix, BeOS and MacOS X, the config file routines also check for ~/allegro.cfg, ~/.allegrorc, /etc/allegro.cfg, and /etc/allegrorc, in that order, and the keyboard and language files can be stored in your home directory or in /etc/.
See more:
http://alleg.sourceforge.net/stabledocs/en/readme.html#configuration