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.
I can't run node.js on PowerPC 440EP, I get only error "Illegal instruction".
Hardware info:
cat /proc/cpuinfo
processor : 0
cpu : 440EP Rev. C
clock : 533.333332MHz
revision : 24.212 (pvr 4222 18d4)
bogomips : 1066.66
timebase : 533333332
platform : CPU440EP
model : micran,cpu440
Memory : 128 MB
LD_SHOW_AUXV=1 /bin/true
AT_DCACHEBSIZE: 0x20
AT_ICACHEBSIZE: 0x20
AT_UCACHEBSIZE: 0x0
AT_SYSINFO_EHDR: 0x100000
AT_HWCAP: booke mmu fpu ppc32
AT_PAGESZ: 4096
AT_CLKTCK: 100
AT_PHDR: 0x10000034
AT_PHENT: 32
AT_PHNUM: 8
AT_BASE: 0x48000000
AT_FLAGS: 0x0
AT_ENTRY: 0x1000446c
AT_UID: 0
AT_EUID: 0
AT_GID: 0
AT_EGID: 0
AT_SECURE: 0
AT_RANDOM: 0xbf8c04f2
AT_EXECFN: /bin/true
AT_PLATFORM: ppc440
AT_BASE_PLATFORM:ppc440
Software info:
I'm using powerpc-440-linux-gnu compiler (version 5.2.0) and Linux v3.6.7.
I tried to use different versions of sources:
*node-0.10-ppc* from https://github.com/ibmruntimes/node
*node-4.x-port* from https://github.com/ibmruntimes/node
*node-v4.4.7* from https://nodejs.org/dist/v4.4.7/node-v4.4.7.tar.gz
*node-6.x* from https://github.com/nodejs/node
I'm using the following script for build of node.js:
#!/bin/bash
CROSS_COMPILER=powerpc-440-linux-gnu
HOST=powerpc-linux
ENDIAN=big
BUILD_PATH=/home/user/node
CFLAGS=-Os
JOBS=4
export ARCH=ppc
export CC=${CROSS_COMPILER}-gcc
export CXX=${CROSS_COMPILER}-g++
export CFLAG=${CFLAGS}
export AR=${CROSS_COMPILER}-ar r
export LINK=${CROSS_COMPILER}-g++
export PATH=${PATH}:/home/user/powerpc-440-linux-gnu/bin
./configure --without-snapshot --prefix=${BUILD_PATH} --dest-cpu=ppc --dest-os=linux
make -j ${JOBS}
make install
Which version of node.js should I use?
Do we have working portable
version of node.js for PowerPC 440EP ?
Sad update
I got the following answer from issues page on https://github.com/nodejs:
[Michael Dawson] The particular chip mentioned is based on the older PowerPC cores and does not have all of the Power5+ instructions available.
There are roughly two reasons for an illegal instruction. Either a memory corruption is derailing the control flow with the result that the CPU is trying to execute garbage/data.
The other reason would be that your node.js binary contains an instruction that isn't known to your CPU aka. your cross compiler output isn't matching your CPU. Investigate if you need to pass an additional -mcpu= or -mtune= argument to the compiler (or rather to configure).
As node.js contains a just in time compiler itself there is also the third option that node.js is generating instructions not suitable for you CPU variant.
I would investigate option two first.
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.
I'd like to communicate read from my RTC in C code rather than the "hwclock" shell command.
However, when I use i2cdetect, it shows 0x68(which is my RTC slave address) is having the status "UU", which means "Probing was skipped, because this address is currently in use by a driver". And after I tried the i2cget, its givng "could bot set address to 0x68: Device or resource busy".
So I'm thinking if there are some problem in my Linux kernel that will force to read from my RTC all the time, or some other reason.
Thanks
I am assuming that you are using DS-1307 RTC, or one of its variants (because of 0x68 slave address). Check if its driver is loaded by:
$ lsmod | grep rtc
If you seen an entry of rtc_ds1307, (like this -> rtc_ds1307 17394 0 ) in the output of above command then this driver might be in hold of that address.
If the driver is loaded in system then unload it using
$ rmmod rtc-ds1307
EDIT:
(In light of OP's feedback,) Please do the following
1) cat /sys/bus/i2c/devices/3-0068/modalias. This will give you the name of the kernel driver that is keeping this device busy. Copy the driver-name after the colon(:)
OP's output of the command tells us that its ds1337
2) Check if ds1337 is an alias for a driver, using
grep ds1337 /lib/modules/`uname -r`/modules.alias
Hopefully you will get the following output
alias i2c:ds1337 rtc_ds1307
This confirms our presumption that rtc_ds1307 is infact the driver in hold of the I2C address 0x68.
3) use rmmod rtc_ds1307 to unload the driver.
Note: This will only work if the driver is a Loadable Kernel Module, otherwise you will see the following error:
ERROR: Module rtc_ds1307 does not exist in /proc/modules
In that case you will have to recompile the kernel again with that driver disabled/modularized.
0x68 is being used by some driver,
Disable that driver in kernel source code and recompile source code.
all.
I'm a kernel newbie. I want to know how to get useful infomations from painc such as which line or which function is wrong.
For example, following is a panic-output about usb hiddev, how to read it? Thanks.
BUG: unable to handle kernel NULL pointer dereference at 0000000000000028
IP: [<ffffffff813b4aa1>] free_async+0xa1/0x100
PGD 2326c9067 PUD 230f4c067 PMD 0
Oops: 0000 [#1] SMP
last sysfs file: /sys/devices/pci0000:00/0000:00:1d.2/usb8/8-2/speed
CPU 3
Modules linked in: ebtable_nat ebtables ipt_MASQUERADE iptable_nat nf_nat xt_CHECKSUM iptable_mangle bridge stp l]
Pid: 2400, comm: lsusb Tainted: G I--------------- 2.6.32-296.el664fixes.3.x86_64 #1 Dell Inc. OptiPlN
RIP: 0010:[<ffffffff813b4aa1>] do_IRQ: 0.97 No irq handler for vector (irq -1)
[Firmware Bug]: the BIOS has corrupted hw-PMU resources (MSR 186 is 53003c)
�Mounting proc filesystem
Mounting sysfs filesystem
Creating /dev
Creating initial device nodes
setfont: KDFONTOP: Invalid argument
Free memory/Total memory (free %): 78672 / 114884 ( 68.4795 )
Loading dm-mod.ko module
Loading dm-log.ko module
Loading dm-region-hash.ko module
Loading dm-mirror.ko module
Loading dm-zero.ko module
Loading dm-snapshot.ko module
Loading freq_table.ko module
Loading mperf.ko module
Loading ipt_REJECT.ko module
Loading nf_defrag_ipv4.ko module
Loading ip_tables.ko module
Loading nf_conntrack.ko module
Loading ip6_tables.ko module
Loading ipv6.ko module
Loading fat.ko module
Loading macvlan.ko module
Loading tun.ko module
Loading kvm.ko module
Loading uinput.ko module
Loading parport.ko module
Loading dcdbas.ko module
Loading microcode.ko module
The panic itself is actually quite accurate as is;
BUG: unable to handle kernel NULL pointer dereference at 0000000000000028
IP: [] free_async+0xa1/0x100
Tells already that the function where the problem happened is free_async and that function is exactly 0x100 bytes long and the crash happened at offset 0xa1. You need to map that offset into the exact line of code, but that now depends a bit on your environment how to do it.
Sometimes manual code review already will show what line has pointer manipulations, so you can do it just by reviewing that function.
Then the next question is that, why do you have a NULL-pointer there?