Kernel make generates “ld: arch/x86/entry/syscall_64.o:(.rodata+0xdc0): undefined reference to `__x64_sys_s_enable'” - linux

OS is Ubuntu 20.10 Kernel Source is linux_5.8.0-59.66
I am porting kernel modifications from Centos 7 Rhel 7.9 to Ubuntu.
The original unmodified Ubuntu kernel source compiles and runs cleanly on this machine. The compiler set up seems to be functioning properly.
My current problem is related to a system call I've added. The error generated is -
LD .tmp_vmlinux.btf
ld: arch/x86/entry/syscall_64.o:(.rodata+0xdc0): undefined reference to `__x64_sys_s_enable'
BTF .btf.vmlinux.bin.o
Segmentation fault (core dumped)
LD .tmp_vmlinux.kallsyms1
.btf.vmlinux.bin.o: file not recognized: file format not recognized
make: *** [Makefile:1163: vmlinux] Error 1
I have searched and googled this original error "undefined reference", found possible fixes which have not worked.
Here are the steps I used to add the system call, which originally worked on Centos 7 and RHEL 7.9.
Modified /SOURCE-DIRECTORY/include/linux/syscalls.h commentng out the original line and adding the reference to __64 (including a blank line above it)-
asmlinkage long __64_sys_s_enable(int s_enable_flag);
//asmlinkage long sys_s_enable(int s_enable_flag);
Modified /SOURCE-DIRECTORY/arch/x86/include/asm/syscalls.h adding -
440 64 s_enable sys_s_enable
The fields are delimited by TAB, and I did not add any blank lines.
Created the source directory and files - /SOURCE-DIRECTORY/s_enable containing s_enable.c. s_enable.c in it's entirety is
#include <linux/kernel.h>
extern int s_enable_flag;
asmlinkage long sys_s_enable(int i)
{
// printk(KERN_INFO "In ORIGINAL SYSCALL s_enable\n");
s_enable_flag = i;
return 0;
}
And added the appropriate syscall directory to the Makefile.
core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ s_enable/
And ran "sudo make".
I'm not sure what I might be doing wrong in that the "make" works with the original kernel source, and the system call I am trying to add has worked on the other mentioned distros.
Thanks for any input you can provide.
UPDATE 07-18-2021
I made the following changes on 07-17-2021 in order to use SYSCALL_DEFINE1.
SOURCEDIR/include/linux/syscalls.h
The reference to sys_s_enable has been commented out.
//asmlinkage long sys_s_enable(int s_enable_flag);
SOURCEDIR/arch/x86/entry/syscalls/syscall_64.tbl
"64" changed to "common"
440 common s_enable sys_s_enable
SOURCEDIR/Makefile has been edited to remove SOURCEDIR/s_enable from core-y
core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/
#core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ s_enable/
Copied/edited the original s_enable.c into SOURCEDIR/kernel/sys.c using SYSCALL_DEFINE1
SYSCALL_DEFINE1(su_enable, int, i)
{
extern int s_enable_flag;
s_enable_flag = i;
return 0;
}
The compile command was sudo make -j4 and took 12-15 hours which is somewhat normal.
The error was
LD .tmp_vmlinux.btf
ld: arch/x86/entry/syscall_64.o:(.rodata+0xdc0): undefined reference to `__x64_sys_s_enable'
Thanks - Roger

If we want to create our own system call a newer version of Linux __x64_sys_
Here is the comment from arch/x86/entry/syscalls/syscall_64.tbl in the begin
The x64_sys*() stubs are created on-the-fly for sys*() system calls
so that our system call function name might start the prefix with __x64_sys_, here is the sample code for your own function.
asmlinkage long __x64_sys_s_enable(int i)
{
// printk(KERN_INFO "In ORIGINAL SYSCALL s_enable\n");
s_enable_flag = i;
return 0;
}
Then the include/linux/syscalls.h file might need to add this prefix name which aligns with the function name
asmlinkage long __x64_sys_s_enable(int i);
the system-call entry we can just use your expectation function name arch/x86/entry/syscalls/syscall_64.tbl
440 common s_enable sys_s_enable
We can recompile your kernel if we follow those steps, and we might get a successful build.

Related

Issue: Virtio rpmsg bus virtio0: msg received with no recipient - in Yocto Hardknott - imx7d-pico

I’m correctly generating my image Yocto-hardknott-technexion with this:
$ mkdir tn-imx-yocto
$ cd tn-imx-yocto
$ repo init -u https://github.com/TechNexion/tn-imx-yocto-manifest.git -b hardknott_5.10.y-next -m imx-5.10.52-2.1.0.xml
$ repo sync -j8
$ DISTRO=fsl-imx-x11 MACHINE=pico-imx7 BASEBOARD=pi source tn-setup-release.sh -b build-x11-pico-imx7
$ bitbake core-image-base
Then after I run modprobe imx_rpmsg_tty I have issue: virtio_rpmsg_bus virtio0: msg received with no recipient
I tried this: https://community.toradex.com/t/rpmsg-error-virtio-rpmsg-bus-virtio0-msg-received-with-no-recipient/12701
But not solved yet
When I change lines 83 and 102 from src to dst I got the error below(also look at the last photo):
/home/neuberfran/freertos-tn/examples/imx7d_pico_m4/demo_apps/rpmsg/str_echo_freertos/str_echo_freertos.c: In function 'StrEchoTask':
/home/neuberfran/freertos-tn/examples/imx7d_pico_m4/demo_apps/rpmsg/str_echo_freertos/str_echo_freertos.c:83:75: error: 'dst' undeclared (first use in this function)
result = rpmsg_rtos_recv_nocopy(app_chnl->rp_ept, &rx_buf, &len, &dst, 0xFFFFFFFF);
^
/home/neuberfran/freertos-tn/examples/imx7d_pico_m4/demo_apps/rpmsg/str_echo_freertos/str_echo_freertos.c:83:75: note: each undeclared identifier is reported only once for each function it appears in
/home/neuberfran/freertos-tn/examples/imx7d_pico_m4/demo_apps/rpmsg/str_echo_freertos/str_echo_freertos.c:63:19: warning: unused variable 'src' [-Wunused-variable]
unsigned long src;
^
make[2]: *** [CMakeFiles/rpmsg_str_echo_freertos_example.dir/build.make:94: CMakeFiles/rpmsg_str_echo_freertos_example.dir/home/neuberfran/freertos-tn/examples/imx7d_pico_m4/demo_apps/rpmsg/str_echo_freertos/str_echo_freertos.c.obj] Erro 1
make[2]: ** Esperando que outros processos terminem.
make[1]: *** [CMakeFiles/Makefile2:76: CMakeFiles/rpmsg_str_echo_freertos_example.dir/all] Erro 2
The error is being printed on line 761:
https://elixir.bootlin.com/linux/latest/source/drivers/rpmsg/virtio_rpmsg_bus.c#L761
How to solve?
edited: I think the problem can be stay in Vring[0] Vring1. Link below. Because I can put
#define VRING0_BASE 0xBFFF0000
#define VRING1_BASE 0xBFFF8000
in platform_info.c But I can't do changes in imx_rpmsg.c
https://imxdev.gitlab.io/tutorial/Multicore_communication_on_WaRP7_using_Remote_Processor_Messaging_bus_(RPMsg)/
Good morning,
We got the same problem in our project when there was no destination address set in message coming from the real-time controller (M7 in our case; Before we had M4. both in imx8-derivates).
Attached you see the tx-no copy call of our implementation. First try in my case was to extract the messages from downstream message and swap the addresses.
the call; Here we use the addresses stored in the bwloe stated list
The list with our channels (we build the kernel-module separately to add those cahnnel names
For a first try, send a message from Linux to sub-core, take the sender's address and set it as destination in the answer.
Hopefully you can get it running with this information. Please let me know.
I started to resolve my issue after on 04/13/2022 When I edited this post/issue and put this link: https://imxdev.gitlab.io/tutorial/Multicore_communication_on_WaRP7_using_Remote_Processor_Messaging_bus_(RPMsg)/
In freertos-tn/middleware/multicore/open-amp/porting/imx7d-m4/platform_info.c file #define VRING1_BASE correct is 0x9FFF8000
But in my platform_info.c was 0x9FFF0000
Now, I can run RPMsg with str_echo_freertos script/example:

Error 'Unknown symbol __copy_to_user' during module load

I have NAS Terramaster F4-210 based on arm64 Realtek RTD1296 CPU. It has custom OpenWrt 15.05.1 based firmware with 4.4.18 linux kernel. I want to create kernel module to use my zigbee stick (cdc-acm - USB Modem (CDC ACM) support) and run homeassistant on it.
# uname -a
Linux TNAS-BA68 4.4.18-g8bcbd8a-dirty #1327 SMP Mon Aug 31 11:55:52 CST 2020 aarch64 GNU/Linux
I downloaded appropriate kernel, created some config and after installing my newly compiled module I get the following errors in kernel log:
# modprobe cdc-acm
1 module could not be probed
- cdc-acm
# dmesg
...
cdc_acm: Unknown symbol __copy_to_user (err 0)
cdc_acm: Unknown symbol __copy_from_user (err 0)
cdc_acm: Unknown symbol _mcount (err 0)
As far as I understand that means module expects copy_to_user, copy_from_user, mcount to be part of the kernel (or other loaded module). But kernel doesn't export these symbols:
# cat /proc/kallsyms | grep copy_to_user
ffffff80082923f0 T copy_to_user_page
ffffff80087d2600 T __arch_copy_to_user
ffffff80087e67b0 t kfifo_copy_to_user
ffffff8008871854 T my_copy_to_user
File arch/arm64/include/asm/uaccess.h has definition of copy_to_user:
extern unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n);
...
static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n)
File arch/arm64/lib/copy_to_user.S contains source code of __copy_to_user:
ENTRY(__copy_to_user)
ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_HAS_PAN, CONFIG_ARM64_PAN)
...
ENDPROC(__copy_to_user)
My initial idea was I have bad kernel configuration or bad toolchain. So I used toolchain and OpenWrt+kernel configuration from banana pi W2 board which has the same CPU. Without any luck but compile warning had disappeared.
So can somebody please confirm that the problem can't be solved by applying some different kernel configuration or proper toolchain. Instead kernel source code must be modified. E.g. instead of __copy_to_user one of __arch_copy_to_user or my_copy_to_user must be used.
So my assumption is: Terramaster took kernel sources, modified (probably used __arch_copy_to_user instead of __copy_to_user) and then compiled sources.
BTW: I also checked kernel sources and didn't find __arch_copy_to_user. Does that mean it was introduced by kernel sources modifications or it still can be present thereby usage of some nasty defs.

File capabilities do not transfer to process once executed

I'm trying to write a program which requires elevated capabilities (rather than simply run it with sudo). However, none of the capabilities I set using setcap seem to transfer into the process once executed. This problem occurs across multiple executables and using different capabilities.
This code uses cap_set_file() to give the CAP_NET_RAW capability to a file passed as a CLA. (Don't ask me why I need this.)
#include <stdio.h>
#include <stdlib.h>
#include <sys/prctl.h>
#include <sys/capability.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#define handle_error(msg) \
do { printf("%s: %s\n", msg, strerror(errno)); exit(EXIT_FAILURE); } while (0)
void print_cap_buf(cap_t cur) {
char *buf;
buf = cap_to_text(cur, NULL);
printf("%s\n", buf);
cap_free(buf);
}
void get_and_print_cap_buf() {
cap_t cur = cap_get_proc();
print_cap_buf(cur);
cap_free(cur);
}
int main(int argc, char *argv[]) {
cap_t file_cap;
printf("Process capabilities: ");
get_and_print_cap_buf(); // Print the current process capability list.
file_cap = cap_from_text("cap_net_raw=ep");
if (file_cap == NULL) handle_error("cap_from_text");
printf("Capabilities to set in file: "); print_cap_buf(file_cap);
if (argc == 2) {
if ( cap_set_file(argv[1], file_cap) != 0) handle_error("cap_set_file");
} else printf("No file specified.\n");
cap_free(file_cap);
return 0;
}
After compiling with gcc:
gcc -Wall -pedantic -std=gnu99 test.c -o tt -lcap
I give it the capabilities with:
sudo setcap "cap_setfcap,cap_fowner,cap_net_raw=eip" tt
and using getcap tt, the output is:
$ getcap tt
tt = cap_fowner,cap_net_raw,cap_setfcap+eip
However, when I run the program, I get the following output (test-client is an executable which creates a raw Ethernet socket):
$ ./tt test-client
Process capabilities: =
Capabilities to set in file: = cap_net_raw+ep
cap_set_file: Operation not permitted
HOWEVER... when I run the program with sudo, all process capabilities come through just fine.
$ sudo ./tt test-client
Process capabilities: = cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,37+ep
Capabilities to set in file: = cap_net_raw+ep
and the target file "test-client" gets its capabilities set properly.
However, even with CAP_NET_RAW, the client fails on its socket() call with EPERM. I've tried setting CAP_NET_ADMIN in case it needed that as well; same issue. I've tried using CAP_SETPCAP on the program above; no dice. I'm fairly sure I've narrowed it down to some disconnect where the executable file's capabilities aren't getting into the running process.
What am I missing here?
EDIT, the next morning:
Okay, so I've done some more testing and it turns out this code works just fine on a Raspberry Pi. I'm running Lubuntu 16.04 with LXTerminal on my primary machine and that's the one that's failing. It fails inside LXTerminal and also in a text-only shell. Maybe it's an OS bug?
The Lubuntu machine (cat /proc/version):
Linux version 4.4.0-34-generic (buildd#lgw01-20) (gcc version 5.3.1 20160413 (Ubuntu 5.3.1-14ubuntu2.1) ) #53-Ubuntu SMP Wed Jul 27 16:06:39 UTC 2016
The pi:
Linux version 4.4.11-v7+ (dc4#dc4-XPS13-9333) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611) ) #888 SMP Mon May 23 20:10:33 BST 2016
EDIT AGAIN: --
Tested on a different machine with the same USB key I used to install. Slightly different /proc/version:
Linux version 4.4.0-31-generic (buildd#lgw01-16) (gcc version 5.3.1 20160413 (Ubuntu 5.3.1-14ubuntu2.1) ) #50-Ubuntu SMP Wed Jul 13 00:07:12 UTC 2016
Works fine. I'm so confused.
I finally got this to work, thanks to the information found here:
https://superuser.com/questions/865310/file-capabilities-setcap-not-being-applied-in-linux-mint-17-1
It turns out that my home directory is being mounted as nosuid, which disables all capability flags.
When running the program on a filesystem without nosuid, it works as expected.
For future readers: if you encounter this issue, make sure your filesystem is not mounted as nosuid. Using the mount command, check for the filesystem that matches where you're storing the data (in my case /home/user) and see if the nosuid flag is set.
$ mount
...
/home/.ecryptfs/user/.Private on /home/user type ecryptfs (rw,nosuid,nodev,relatime,ecryptfs_fnek_sig=***,ecryptfs_sig=***,ecryptfs_cipher=aes,ecryptfs_key_bytes=16,ecryptfs_unlink_sigs)
(It's an ecryptfs system, so if you selected "Encrypt my home directory" on the Ubuntu install you'll probably have this problem. I couldn't figure out a way to mount this as suid, and probably wouldn't want to anyway.)
I ended up making a new directory /code (it's my filesystem, I can do what I want) which is mounted on a different partition without nosuid.
It would be nice if the man pages for capabilities referenced this fact... (edit: patch submitted, it does now :) )
Just a data point: your code works here on an older LTS machine:
$ uname -vr
3.13.0-63-generic #103-Ubuntu SMP Fri Aug 14 21:42:59 UTC 2015
$ ./tt test-client
Process capabilities: = cap_fowner,cap_net_raw,cap_setfcap+ep
Capabilities to set in file: = cap_net_raw+ep
$ cat /etc/debian_version
jessie/sid
Maybe perhaps it might have something to do with the capabilities of the user's process (invoking ./tt)? As it says in capabilities(7), Capabilities are a
per-thread attribute.

TCP sendto (C++) fails on Linux but not OSX. Errno: EINVAL 22 Invalid argument

On the client side of my application, the following runs fine on OSX. But when compiled/run on Linux (Ubuntu 12 or Raspbian) sendto() always fails with a EINVAL/22/invalid argument. How do I run it on Linux?
std::vector<uint8_t> rawVect;
// rawVect.push_back()...a bunch of bytes
const uint8_t* sendBytes = &rawVect[0]; // or rawVect.data();
size_t sendSize = rawVect.size();
if(sendSize > 0){
long numBytes = sendto(control_fd, sendBytes, sendSize, 0, res->ai_addr, _res->ai_addrlen);
}
I suspect C++ 11 libraries and std::vectors on Linux. My makefile looks similar to this.
mac:
g++ -std=c++0x myprogram.cpp
# (w/ llvm libc++)
ubuntu:
clang++-3.5 -g -std=c++11 -stdlib=libc++ myprogram.cpp
# couldn't use g++ 4.8 or prior because it didn't support std::vector::insert as I was using it elsewhere. 4.9 not avail for Ubuntu 12.
pi:
g++-4.9 -std=c++0x myprogram.cpp
man 3 sendto says that EINVAL may be returned if "The dest_len argument is not a valid length for the address family", perhaps despite the fact that the address argument is ignored for connected-mode sockets. Given that you mention TCP in the title, I assume that control_fd is a connected-mode socket. Try simply using send(control_fd, sendBytes, sendSize, 0) or even write(control_fd, sendBytes, SendSize) instead.
There's not enough to go on. Add print statements to reveal the values of all the parameters passed to sendto. Then print out the relevant members of res->ai_addr after casting back to sockaddr_in.
One hypothesis. The value of ai_addrlen should exactly equal sizeof(struct sockaddr_in) assuming ipv4. Or sizeof(sockaddr_in6) if the socket is ipv6. Some operating systems are less forgiving if you pass in a value that's bigger than the actual size expected for that socket type. Such would be the case with assigning the ai_addrlen to be sizeof(sockaddr_storage).

clang memory sanitizer; how to make it print source line numbers

I'm compiling my program with clang++ -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -g -O0 and when I run it, the output is:
matiu#matiu-laptop:~/projects/json++11/build$ ./tests
.......==10534== WARNING: MemorySanitizer: use-of-uninitialized-value
#0 0x7fe7602d4a51 (/home/matiu/projects/json++11/build/tests+0x106a51)
#1 0x7fe7602dfca6 (/home/matiu/projects/json++11/build/tests+0x111ca6)
...
#31 0x7fe75edbaec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
#32 0x7fe7602808dc (/home/matiu/projects/json++11/build/tests+0xb28dc)
Uninitialized value was created by a heap allocation
#0 0x7fe76026e7b3 (/home/matiu/projects/json++11/build/tests+0xa07b3)
#1 0x7fe7602ee7da (/home/matiu/projects/json++11/build/tests+0x1207da)
...
#18 0x7fe7602c1c4c (/home/matiu/projects/json++11/build/tests+0xf3c4c)
#19 0x7fe7602873fa (/home/matiu/projects/json++11/build/tests+0xb93fa)
SUMMARY: MemorySanitizer: use-of-uninitialized-value ??:0 ??
Exiting
How can I make it show line numbers like in the beautiful examples: http://clang.llvm.org/docs/MemorySanitizer.html
I'm suspecting it might not be possible, due to my pragram being one giant nested bunch of lambdas: https://github.com/matiu2/json--11/blob/master/tests.cpp
With the address sanitizer I noticed that I needed to have these environment variables defined:
ASAN_OPTIONS=symbolize=1 (only needed when compiled with GCC > 4.8) and
ASAN_SYMBOLIZER_PATH=$(which llvm-symbolizer) I think the symbolizer is what you're looking for. It transforms symbols to file names with line numbers and columns.
On the memory sanitizer project website it reads:
Symbolization
Set MSAN_SYMBOLIZER_PATH environment variable to the path to
llvm-symbolizer binary (normally built with LLVM). MemorySanitizer
will use it to symbolize reports on-the-fly.
So you need MSAN_SYMBOLIZER_PATH to be set analogous to ASAN_SYMBOLIZER_PATH.

Resources