XDP program ip link error: Prog section rejected: Operation not permitted - linux

I try to get into XDP, for this I have this very small program:
// SPDX-License-Identifier: GPL-2.0
#include <linux/bpf.h>
#include "bpf/bpf_helpers.h"
#include "xdpsock.h"
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, MAX_SOCKS);
__uint(key_size, sizeof(int));
__uint(value_size, sizeof(int));
} xsks_map SEC(".maps");
SEC("xdp_sock") int xdp_sock_prog(struct xdp_md *ctx) {
return XDP_DROP;
}
But if I try to load it into a virtual interface veth-basic02, I get this error:
$ sudo ip -force link set dev veth-basic02 xdp object xdpsock_kern.o
section xdp_sock
Prog section 'xdp_sock' rejected: Operation not permitted (1)!
- Type: 6
- Instructions: 2 (0 over limit)
- License:
Verifier analysis:
Error fetching program/map!
Kernel-Version: 5.3.0-28-generic
This is the Makefile I am using:
OBJS = xdpsock_kern.o
LLC ?= llc
CLANG ?= clang
INC_FLAGS = -nostdinc -isystem `$(CLANG) -print-file-name=include`
EXTRA_CFLAGS ?= -O2 -emit-llvm
# In case up-to-date headers are not installed locally in /usr/include,
# use source build.
linuxhdrs ?= /usr/src/linux-headers-5.1.0-050100
LINUXINCLUDE = -I$(linuxhdrs)/arch/x86/include/uapi \
-I$(linuxhdrs)/arch/x86/include/generated/uapi \
-I$(linuxhdrs)/include/generated/uapi \
-I$(linuxhdrs)/include/uapi \
-I$(linuxhdrs)/include \
-I/bpf
prefix ?= /usr/local
INSTALLPATH = $(prefix)/lib/bpf
install_PROGRAM = install
install_DIR = install -dv
all: $(OBJS)
.PHONY: clean
clean:
rm -f $(OBJS)
INC_FLAGS = -nostdinc -isystem `$(CLANG) -print-file-name=include`
$(OBJS): %.o:%.c
$(CLANG) $(INC_FLAGS) \
-D__KERNEL__ -D__ASM_SYSREG_H \
-Wno-unused-value -Wno-pointer-sign \
-Wno-compare-distinct-pointer-types \
-Wno-gnu-variable-sized-type-not-at-end \
-Wno-address-of-packed-member -Wno-tautological-compare \
-Wno-unknown-warning-option \
-I../include $(LINUXINCLUDE) \
$(EXTRA_CFLAGS) -c $< -o -| $(LLC) -march=bpf -filetype=obj -o $#
install: $(OBJS)
$(install_DIR) -d $(INSTALLPATH) ; \
$(install_PROGRAM) $^ -t $(INSTALLPATH)
uninstall: $(OBJS)
rm -rf $(INSTALLPATH)
Lockdown:
$ dmesg | grep Lockdown
[ 1.283355] Lockdown: swapper/0: Hibernation is restricted; see man kernel_lockdown.7
[ 11.313219] Lockdown: systemd: /dev/mem,kmem,port is restricted; see man kernel_lockdown.7
[ 11.337794] Lockdown: systemd: BPF is restricted; see man kernel_lockdown.7
[ 17.147844] Lockdown: Xorg: ioperm is restricted; see man kernel_lockdown.7
Edit:
echo 1 > /proc/sys/kernel/sysrq + echo x > /proc/sysrq-trigger + Alt+SysRq+x indeed solves the problem - I can finally load the XDP-Program! Funny easter egg though. Thank you #Qeole!

eBPF: Operation not permitted
There are several possible causes for a permission error (-EPERM returned by bpf(), which you can observe with strace -e bpf <command>) when working with eBPF. But no so many. Usually, they fall under one of the following items:
User does not have the required capabilities (CAP_SYS_ADMIN, CAP_NET_ADMIN, ... typically depending on the types of the programs being used). This is usually solved by running as root, who has all necessary capabilities. In your case you run with sudo, so you are covered.
Creating the BPF object (new map, or loading a program) would exceed the limit for the amount of memory that can be locked in the kernel by the user. This is usually solved (for root) by using ulimit -l <something_big> in the terminal, or setrlimit() in a C program. Very unlikely in your case, your program is very small and you did not mention having a lot of BPF objects loaded on your system.
There are a few more possibilies, like trying to write on maps that are “frozen” or read-only etc., or trying to use function calls for non-root users. These are usually for more advanced use cases and should not be hit with a program as simple as yours.
Lockdown, Secure Boot, EFI and (unfortunate) backports for bpf() restrictions
But the problem that you seem to be hitting could be related to something else. “Lockdown” is a security module that was merged into Linux 5.5 kernel. It aims at preventing users to modify the running Linux image. It turns out that several distributions decided to backport Lockdown to their kernels, and sometimes they picked patches that predated the final version that was merged to mainline Linux.
Ubuntu and Fedora, for example, have a bunch of custom patches to backport that feature to the kernels used in Disco/19.04 and Eoan/19.10 (kernel 5.3 for the latter, I don't remember for Disco). It includes a patch that completely disables the bpf() system call when Lockdown is activated, meaning that creating maps or loading BPF programs is not possible. Also, they enabled Lockdown by default when Secure Boot is activated, which, I think, is the default for machines booting with EFI.
See also this blog post: a good way to check if Lockdown is affecting your BPF usage is to try and load minimal programs, or to run dmesg | grep Lockdown to see if it says something like:
Lockdown: systemd: BPF is restricted; see man kernel_lockdown.7
So for Ubuntu 19.04 and 19.10, for example, you have to disable Lockdown to work with eBPF. This may be done with a physical stroke of the SysRq key + x (I have not tested), but NOT by writing to /proc/sysrq-trigger (Ubuntu disabled it for this operation). Alternatively, you can disable Secure Boot (in the BIOS or with mokutil, search for the relevant options on the Internet, and do not forget to check the security implications).
Note that Linux kernel 5.4 or newest has the mainline restrictions for bpf(), which do not deactivate the system call, so Focal/20.04 and newest will not be affected. Upgrading to a new kernel might thus be another workaround. I filed a ticket a few days ago to ask for this change to be backported (instead of deactivating bpf()) and the work is in progress, so by the time new readers look at the answer Lockdown impact on eBPF might well be mitigated (Edit: Should be fixed on Ubuntu 19.10 with kernel 5.3.0-43). Not sure how other distros handle this. And it will still have strong implications for tracing with eBPF, though.

Related

AF_XDP not working on Kernel `4.18.0-25-generic` [duplicate]

I try to get into XDP, for this I have this very small program:
// SPDX-License-Identifier: GPL-2.0
#include <linux/bpf.h>
#include "bpf/bpf_helpers.h"
#include "xdpsock.h"
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, MAX_SOCKS);
__uint(key_size, sizeof(int));
__uint(value_size, sizeof(int));
} xsks_map SEC(".maps");
SEC("xdp_sock") int xdp_sock_prog(struct xdp_md *ctx) {
return XDP_DROP;
}
But if I try to load it into a virtual interface veth-basic02, I get this error:
$ sudo ip -force link set dev veth-basic02 xdp object xdpsock_kern.o
section xdp_sock
Prog section 'xdp_sock' rejected: Operation not permitted (1)!
- Type: 6
- Instructions: 2 (0 over limit)
- License:
Verifier analysis:
Error fetching program/map!
Kernel-Version: 5.3.0-28-generic
This is the Makefile I am using:
OBJS = xdpsock_kern.o
LLC ?= llc
CLANG ?= clang
INC_FLAGS = -nostdinc -isystem `$(CLANG) -print-file-name=include`
EXTRA_CFLAGS ?= -O2 -emit-llvm
# In case up-to-date headers are not installed locally in /usr/include,
# use source build.
linuxhdrs ?= /usr/src/linux-headers-5.1.0-050100
LINUXINCLUDE = -I$(linuxhdrs)/arch/x86/include/uapi \
-I$(linuxhdrs)/arch/x86/include/generated/uapi \
-I$(linuxhdrs)/include/generated/uapi \
-I$(linuxhdrs)/include/uapi \
-I$(linuxhdrs)/include \
-I/bpf
prefix ?= /usr/local
INSTALLPATH = $(prefix)/lib/bpf
install_PROGRAM = install
install_DIR = install -dv
all: $(OBJS)
.PHONY: clean
clean:
rm -f $(OBJS)
INC_FLAGS = -nostdinc -isystem `$(CLANG) -print-file-name=include`
$(OBJS): %.o:%.c
$(CLANG) $(INC_FLAGS) \
-D__KERNEL__ -D__ASM_SYSREG_H \
-Wno-unused-value -Wno-pointer-sign \
-Wno-compare-distinct-pointer-types \
-Wno-gnu-variable-sized-type-not-at-end \
-Wno-address-of-packed-member -Wno-tautological-compare \
-Wno-unknown-warning-option \
-I../include $(LINUXINCLUDE) \
$(EXTRA_CFLAGS) -c $< -o -| $(LLC) -march=bpf -filetype=obj -o $#
install: $(OBJS)
$(install_DIR) -d $(INSTALLPATH) ; \
$(install_PROGRAM) $^ -t $(INSTALLPATH)
uninstall: $(OBJS)
rm -rf $(INSTALLPATH)
Lockdown:
$ dmesg | grep Lockdown
[ 1.283355] Lockdown: swapper/0: Hibernation is restricted; see man kernel_lockdown.7
[ 11.313219] Lockdown: systemd: /dev/mem,kmem,port is restricted; see man kernel_lockdown.7
[ 11.337794] Lockdown: systemd: BPF is restricted; see man kernel_lockdown.7
[ 17.147844] Lockdown: Xorg: ioperm is restricted; see man kernel_lockdown.7
Edit:
echo 1 > /proc/sys/kernel/sysrq + echo x > /proc/sysrq-trigger + Alt+SysRq+x indeed solves the problem - I can finally load the XDP-Program! Funny easter egg though. Thank you #Qeole!
eBPF: Operation not permitted
There are several possible causes for a permission error (-EPERM returned by bpf(), which you can observe with strace -e bpf <command>) when working with eBPF. But no so many. Usually, they fall under one of the following items:
User does not have the required capabilities (CAP_SYS_ADMIN, CAP_NET_ADMIN, ... typically depending on the types of the programs being used). This is usually solved by running as root, who has all necessary capabilities. In your case you run with sudo, so you are covered.
Creating the BPF object (new map, or loading a program) would exceed the limit for the amount of memory that can be locked in the kernel by the user. This is usually solved (for root) by using ulimit -l <something_big> in the terminal, or setrlimit() in a C program. Very unlikely in your case, your program is very small and you did not mention having a lot of BPF objects loaded on your system.
There are a few more possibilies, like trying to write on maps that are “frozen” or read-only etc., or trying to use function calls for non-root users. These are usually for more advanced use cases and should not be hit with a program as simple as yours.
Lockdown, Secure Boot, EFI and (unfortunate) backports for bpf() restrictions
But the problem that you seem to be hitting could be related to something else. “Lockdown” is a security module that was merged into Linux 5.5 kernel. It aims at preventing users to modify the running Linux image. It turns out that several distributions decided to backport Lockdown to their kernels, and sometimes they picked patches that predated the final version that was merged to mainline Linux.
Ubuntu and Fedora, for example, have a bunch of custom patches to backport that feature to the kernels used in Disco/19.04 and Eoan/19.10 (kernel 5.3 for the latter, I don't remember for Disco). It includes a patch that completely disables the bpf() system call when Lockdown is activated, meaning that creating maps or loading BPF programs is not possible. Also, they enabled Lockdown by default when Secure Boot is activated, which, I think, is the default for machines booting with EFI.
See also this blog post: a good way to check if Lockdown is affecting your BPF usage is to try and load minimal programs, or to run dmesg | grep Lockdown to see if it says something like:
Lockdown: systemd: BPF is restricted; see man kernel_lockdown.7
So for Ubuntu 19.04 and 19.10, for example, you have to disable Lockdown to work with eBPF. This may be done with a physical stroke of the SysRq key + x (I have not tested), but NOT by writing to /proc/sysrq-trigger (Ubuntu disabled it for this operation). Alternatively, you can disable Secure Boot (in the BIOS or with mokutil, search for the relevant options on the Internet, and do not forget to check the security implications).
Note that Linux kernel 5.4 or newest has the mainline restrictions for bpf(), which do not deactivate the system call, so Focal/20.04 and newest will not be affected. Upgrading to a new kernel might thus be another workaround. I filed a ticket a few days ago to ask for this change to be backported (instead of deactivating bpf()) and the work is in progress, so by the time new readers look at the answer Lockdown impact on eBPF might well be mitigated (Edit: Should be fixed on Ubuntu 19.10 with kernel 5.3.0-43). Not sure how other distros handle this. And it will still have strong implications for tracing with eBPF, though.

FIPS Capable OpenSSL cross-compiled: incore fingerprint issue

I'm having an issue trying to use the OpenSSL shared library (libcrypto) compiled to be FIPS capable on a MIPS device.
I cross-compiled the FIPS Object Module and then the OpenSSL library in the following way (summarizing):
export FIPS_SIG=<my_path>/incore
./config fips --with-fipsdir=<my_path>/fips-2.0
make depend
make
make install
I did all the needed steps, so I'm able to compile and install the library.
The issue appears when I try to run the FIPS_mod_set(1) API from an application linking the OpenSSL library.
The FIPS mode initialization fails receiving this error:
2010346568:error:2D06B06F:lib(45):func(107):reason(111):NA:0:
Debugging the FIPS code, I found that the issue is inside the FIPS_check_incore_fingerprint(void) function:
the check memcmp(FIPS_signature,sig,sizeof(FIPS_signature)) fails.
Going deeper in the debug I discovered that the FIPS_signature value remains the default one, so I have the doubt that the incore script, called by the fipsld utility, is not embedding properly the fingerprint inside the OpenSSL shared object.
How can I check if the incore script embedded the fingerprint inside the shared object?
How can I print the expected fingerprint?
Do I need to adapt the incore script? (I suppose it's not allowed)
Do you have any suggestion?
Thanks a lot!
P.S.: I'm cross-compiling using an x86 Linux machine.
I found the issue! I'll try to explain the whole debugging process and the solution.
INTRODUCTION:
When OpenSSL is configured to be FIPS capable, during the compilation the Makefile calls a utility, fipsld, which both performs the check of the FIPS
Object Module and generates the new HMAC-SHA-1 digest for the application executable (as explained in the official OpenSSL user guide https://www.openssl.org/docs/fips/UserGuide-2.0.pdf)
The fipsld command requires that the CC and FIPSLD_CC environment variables be set,
with the latter taking precedence.
In the Makefile you will find something like this:
libcrypto$(SHLIB_EXT): libcrypto.a fips_premain_dso$(EXE_EXT)
#if [ "$(SHLIB_TARGET)" != "" ]; then \
if [ "$(FIPSCANLIB)" = "libcrypto" ]; then \
FIPSLD_LIBCRYPTO=libcrypto.a ; \
FIPSLD_CC="$(CC)"; CC=$(FIPSDIR)/bin/fipsld; \
export CC FIPSLD_CC FIPSLD_LIBCRYPTO; \
fi; \
$(MAKE) -e SHLIBDIRS=crypto CC="$${CC:-$(CC)}" build-shared && \
(touch -c fips_premain_dso$(EXE_EXT) || :); \
else \
echo "There's no support for shared libraries on this platform" >&2; \
exit 1; \
fi
Then, the fipsld utility invokes a shell script, incore, used to embed the FIPS Object Module's expected fingerprint in the OpenSSL shared object. It's important to specify the incore path via FIPS_SIG env variable, e.g.:
export FIPS_SIG=$PWD/openssl­fips­2.0/util/incore
DEBUGGING:
Debugging the incore script, I could see that the script tried to embed the signature into the shared object at the offset 0x001EE6B0 while the FIPS_signature symbol inside the shared object was located at a different offset, to be more specific at 0x001F0630:
objdump -t libcrypto.so.1.0.0 | grep FIPS_signature
001f0630 g O .data 00000014 FIPS_signature
readelf -a libcrypto.so.1.0.0 | grep FIPS_signature
870: 001f0630 20 OBJECT GLOBAL DEFAULT 18 FIPS_signature
3925: 001f0630 20 OBJECT GLOBAL DEFAULT 18 FIPS_signature
Furthermore dumping the shared object I wasn't able to find the generated signature at the offset 0x001EE6B0 so I reached the conclusion that the shared object was edited after the signature embedding procedure by some other process.
SOLUTION:
I was using a package Makefile for the OpenSSL packet formatted in the following way:
$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)
<options>
all
$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)
<options>
build-shared
rm $(PKG_BUILD_DIR)/libssl.so.*.*.*
$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)
<options>
do_linux-shared
$(MAKE) -C $(PKG_BUILD_DIR)
<options>
install
As suspected, make build-shared and make do_linux-shared commands were responsible for changing the shared object in the wrong way.
NOTICE that make build-shared was called without using the proper environment variables.
I changed the package Makefile:
$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)
<options>
all
$(MAKE) -C $(PKG_BUILD_DIR)
<options>
install
Now the FIPS_check_incore_fingerprint(void) function returns with success and everything is working fine!
NOTE:
The following guide for Android devices has been very useful to find the proper solution.
https://wiki.openssl.org/index.php/FIPS_Library_and_Android

ghc 8.0 cabal build error "ld: -r and -pie may not be used together" known?

After upgrading to ghc 8.0 on a RECENT ubuntu machine, I got the following build error:
/usr/bin/ld: -r and -pie may not be used together
A different error message for the same problem is:
relocation R_X86_64_32 against `.rodata' can not be used when making a > shared object; recompile with -fPIC
Is this a known bug? Are there other solutions?
The solution is to use the linker flag "-no-pie":
cabal -v --ghc-option="-optl-no-pie" install cabal-install
Is suspect it is perhaps an implicit LD flag that is set on ubuntu that is conflicting somehow.
Okay, this is an incredibly! hacky solution, but it did get me past the immediate problem of not being able to build grub. It should work for any other app, but it's so! hacky, I wouldn't leave this in place for very long.
I realize the poster's question is about cabal, not grub. But the problem affects multiple programs and the "correct" solution of using the -fno-pie compiler flag doesn't actually work. Apparently the latest version of gcc sets "pie" on by default, and this takes precedence over the -fno-pie flag. Or at least sometimes.
Here is my working hack for gcc version 6.2.0-5ubuntu12, lubuntu 16.10 (yakkety), linux kernel 4.8.0-22... to build grub 2.02~beta3:
# TO HACK
sudo cp /usr/bin/gcc /usr/bin/gcc.orig
sudo cp /usr/bin/gcc /usr/bin/gcc.patch
sudo rm /usr/bin/gcc
sudo ln -s /usr/bin/gcc.patch /usr/bin/gcc
sudo bless /usr/bin/gcc.patch
# search and replace "-pie -z now" with "-v -z now" (see below)
# save changes and exit 'bless'
That is, use the 'bless' hex editor to search for the text string -pie -z now and change that string to read -v -z now making sure to replace "pie" with "v space space" so it takes up the EXACT same number of characters.
What this does is hack the compiler into sending -v to the linker instead of -pie. If you want to see for yourself what the compiler's doing, just include -Q -v in your compiler's CFLAGS list, and read closely. Even if you specify -fno-pie, the dang thing will still toss out a -pie option to the linker. Anyway, be sure to put everything back when you're done.
# UNDO THE HACK
sudo ln -f -s /usr/bin/gcc.orig /usr/bin/gcc
.
# REDO THE HACK
sudo ln -f -s /usr/bin/gcc.patch /usr/bin/gcc

How to find a base architecture inside Makefile?

I want to find inside a Makefile, whether I'm running on a 32-bit or 64-bit machine.
Is there any macro or environment variables that can be simply accessed from within Makefile?
I found this related answer on-line:
LBITS := $(shell getconf LONG_BIT)
ifeq ($(LBITS),64)
# do 64 bit stuff here, like set some CFLAGS
else
# do 32 bit stuff here
endif
However, I doubt in all system getconf tool would be available or not.
tl;dr;
If all you need is to get the number of bits in long type in C in a portable way, it's ok to use getconf LONG_BIT.
Otherwise:
to detect host architecture, use config.guess shell script
to detect target architecture, use gcc -dumpmachine or gcc --help=target
Detecting host architecture
1) getconf
As mentioned by #Dummy00001, getconf is part of POSIX and is widely available, but it doesn't provide enough information.
Note that getconf LONG_BIT is just the number of bits in long type in C. E.g., it may be 32 on 16-bit or 64-bit machines. It's quite useless for determining host architecture.
2) uname
uname is part of POSIX as well, and it doesn't provide enough information too.
For example, it doesn't distinguish between hardfloat and softfloat ARM on Linux. Also, its architecture naming is not really portable.
3) /proc
You can use /proc to gather architecture info, e.g. /proc/cpuinfo on Linux. However, it's not portable and hard to parse.
4) config.guess
Finally, I recommend GNU config.guess script (source code). It is a standalone script that you can copy to your project. It is written in portable shell and should work on any UNIX.
$ sh config.guess
x86_64-pc-linux-gnu
This script is used in autotools, but you can use it without autotools too.
Detecting default target architecture of your toolchain
It usually makes sense to detect target architecture of toolchain being used. It's different from host architecture when cross-compiling.
1) gcc -E
You can parse gcc -E output to get toolchain tuple for target architecture of gcc:
$ gcc -v -E - </dev/null |& grep Target:
Target: x86_64-linux-gnu
This should work on any UNIX if you use GCC or clang.
Notes:
It prints the value of --target option passed to configure script when GCC was built. It's not affected by current compilations flags passed to GCC, like -m32 or -march.
Unlike config.guess, this toolchain tuple is distro-specific. E.g., different schemes are used in prebuilt toolchains in Debian and Gentoo.
2) gcc -dumpmachine
It seems that gcc -dumpmachine prints the same value as previous recipe:
$ gcc -dumpmachine
x86_64-linux-gnu
It works with GCC and clang.
3) gcc -print-multiarch
Another way to get toolchain tuple:
$ gcc -print-multiarch
x86_64-linux-gnu
It works with GCC, but not clang. Also, this option is known not to work in various cases:
on Debian, it's empty if multilib is disabled
on Gentoo, it's always empty
as mentioned by #Dummy00001, it may be empty for cross-compilation toolchains (I guess it depends on how toolchain was built)
Detecting target architecture depending on current flags
Some GCC options like -m32 or -march can affect target architecture.
1) gcc --help=target
This will print value of -march option deduced from default target architecture (configured when GCC was built) and current compilation options.
$ gcc -Q --help=target |& grep -e -march | awk '{print $2}'
x86-64
$ gcc -m32 -Q --help=target |& grep -e -march | awk '{print $2}'
i686
$ gcc -march=i386 -Q --help=target |& grep -e -march | awk '{print $2}'
i386
It doesn't work with clang.
The getconf is a POSIX tool, it should be available on all unix-like systems. But uname -m would be more portable and more traditional way to find the type of the system.
Otherwise, with high probability, you are looking in the wrong direction: the bit-ness of the host system doesn't necessarily match the bit-ness of the tool-chain. Tool-chain (compiler, linker) define what bit-ness the result would be. And the tool-chain could be customized by the user to accommodate for the local needs (e.g. compiling as 32-bit on a 64-bit OS), or even cross-compilation.
To find the bit-ness of the GCC (or clang) in your tool-chain, you can use that:
LBITS := $(shell $(CC) $(CFLAGS) -dM -E - </dev/null | grep -q "__LP64__" && echo 64 || echo 32)
Effectively, it queries what bit-ness the application is going to be compiled with, without doing actual compilation, but peeking at the compiler defines for the LP parameter, which denotes the "data model" of the architecture (LP64 means "long and pointer are 64-bit" (and, by omission, int is 32 bit); ILP32 means "int, long and pointer are 32-bit").
As long as you stay on the Linux, that would work. (You need to use the CFLAGS in the compiler invocation, since CFLAGS overridden by the user could use the -m32 or -m64 options to change the bit-ness of the output code.)

How to add my own software to a Buildroot Linux package?

I am trying to add my own program to a small linux, created with Buildroot.
What I've done so far:
I've created a new directory inside my 'buildroot/package/' called 'HelloWorld'.
Inside 'buildroot/package/HelloWorld' I have : a Config.in, HelloWorld.mk and HelloWorld directory.
Config.in holds this:
config BR2_PACKAGE_HELLOWORLD
bool "helloworld"
default y
help
Hello world component.
HelloWorld.mk holds this:
HELLOWORLD_VERSION:= 1.0.0
HELLOWORLD_SITE:= /home/userpc/Downloads/helloworld/
HELLOWORLD_SITE_METHOD:=local
HELLOWORLD_INSTALL_TARGET:=YES
define HELLOWORLD_BUILD_CMDS
$(MAKE) CC="$(TARGET_CC)" LD="$(TARGET_LD)" -C $(#D) all
endef
define HELLOWORLD_INSTALL_TARGET_CMDS
$(INSTALL) -D -m 0755 $(#D)/helloworld $(TARGET_DIR)/bin
endef
define HELLOWORLD_PERMISSIONS
/bin/helloworld f 4755 0 0 - - - - -
endef
$(eval $(generic-package))
(inspiration source)
The HelloWorld directory contains: main.c & Makefile:
main.c :
#include <stdio.h>
int main()
{
printf("\nMain entry.\n");
return 0;
}
Makefile:
CC=gcc
CFLAGS=-I.
all: *.c
$(CC) -Os -Wall *.c -o helloworld
# $(STRIP) helloworld
clean:
rm -f a.out helloworld
rm -f *.o
Edit: And I have also added source "package/HelloWorld/Config.in" to 'package/Config.in'
But when I mount my rootfs.ext2 partition I can't find my HelloWorld executable inside /usr/bin .., I am really new to this and don't have any prior knowledge, so could you please explain to me, what am I missing from this, because I'm sure I'm doing something wrong.
UPDATE: The program builds and install at the desired location but when I try to run it like so: ./helloworld, I get: bash: ./helloworld: No such file or directory It has execution rights. What is the matter with it? (I try to run it after I mount the rootfs.ext2 into a ubuntu directory, the target arch for buildroot is i386, so it should be ok, right?)
After building and installing the HelloWorld program, and eventually running it, I'd like to add to init.d so it starts after booting, and replace the HelloWorld with a Qt Window that doesn't need a X server, like this thing here.
The main source of inspiration here.
Minimal tested example on top of 2016.05
GitHub upstream:
https://github.com/cirosantilli/buildroot/tree/in-tree-package-2016.05
This example adds the package source in-tree, which is simple for educational purposes and the way to go if you want to merge back (kudos!),
If you do not intend on merging back (booooh!), it is more likely that you will want to use Buildroot as a git submodule and either:
an out of tree package with BR2_EXTERNAL as shown at: https://github.com/cirosantilli/buildroot/tree/out-of-tree-2016.05
*_OVERRIDE_SRCDIR + other git submodules as explained at: How to modify the source of Buildroot packages for package development?
Files modified:
package/Config.in
menu "Misc"
source "package/hello/Config.in"
endmenu
package/hello/Config.in
config BR2_PACKAGE_HELLO
bool "hello"
help
Hello world package.
http://example.com
package/hello/hello.mk
################################################################################
#
# hello
#
################################################################################
HELLO_VERSION = 1.0
HELLO_SITE = ./package/hello/src
HELLO_SITE_METHOD = local
define HELLO_BUILD_CMDS
$(MAKE) CC="$(TARGET_CC)" LD="$(TARGET_LD)" -C $(#D)
endef
define HELLO_INSTALL_TARGET_CMDS
$(INSTALL) -D -m 0755 $(#D)/hello $(TARGET_DIR)/usr/bin
endef
$(eval $(generic-package))
package/hello/src/.gitignore
hello
package/hello/src/Makefile
CC = gcc
.PHONY: clean
hello: hello.c
$(CC) -o '$#' '$<'
clean:
rm hello
package/hello/src/hello.c
#include <stdio.h>
int main(void) {
puts("hello");
}
Usage:
make qemu_x86_64_defconfig
echo 'BR2_PACKAGE_HELLO=y' >> .config
make BR2_JLEVEL=2
qemu-system-x86_64 -M pc -kernel output/images/bzImage -drive file=output/images/rootfs.ext2,if=virtio,format=raw -append root=/dev/vda -net nic,model=virtio -net user
From inside qemu:
hello
Expected output:
hello
Tested in Ubuntu 16.04.
In general, the sources for buildroot packages are taken from a (downloaded) tarball. What you are doing right now (placing the sources inside package/HelloWorld) is not the right way to proceed.
Buildroot does have provisions for 'local' package sources, which you could use if you really need to. You'll need the HELLOWORLD_SITE_METHOD variable for that.
Please refer to http://buildroot.uclibc.org/downloads/manual/manual.html#adding-packages for more information.
Also, you don't need to define HELLOWORLD_DIR, HELLOWORLD_BINARY, HELLOWORLD_TARGET_BINARY.
Update: regarding your additional question:
UPDATE: The program builds and install at the desired location but when I try to run it
like so: ./helloworld, I get: bash: ./helloworld: No such file or directory, it has
execution rights.. what is the matter with it? (I try to run it after I mount the
rootfs.ext2 into a ubuntu directory, the target arch for buildroot is i368, so it should
be ok, right?)
No, it does not work like that. You can't just mount rootfs.ext2 and expect to run programs from it. This is, among others, because the programs inside rootfs.ext2 are compiled against the libraries also inside rootfs.ext2, but if you run it like that it will use the libraries in /usr/lib. You either have to boot your system entirely with the rootfs.ext2, use qemu, or use a chroot environment. For chroot, you should use the 'tar' filesystem format, not ext2. See also here:
http://buildroot.uclibc.org/downloads/manual/manual.html#_chroot

Resources