Implementing a system call for CPU hotplug - linux

My goal is to implement a system call in linux kernel that enables/disables a CPU core.
First, I implemented a system call that disbales CPU3 in a 4-core system.
The system call code is as follows:
#include <linux/kernel.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <linux/cpumask.h>
#include <linux/smp.h>
asmlinkage long sys_new_syscall(void)
{
unsigned int cpu3;
set_cpu_online (cpu3, false) ; /* clears the CPU in the cpumask */
printk ("CPU%u is offline\n", cpu3);
return 0;
}
The system call was registered correctly in the kernel and I enabled 'cpu hotplug' feature during kernel configuration. See picture
However, the kernel failed to compile in the last stage and I got this error:
gzip: stdout: No space left on device
E: mkinitramfs failure cpio 141 gzip 1
update-initramfs: failed for /boot/initrd.img-4.6.7-rt13-v7+ with 1.
run-parts: /etc/kernel/postinst.d/initramfs-tools exited with return code 1
arch/arm/boot/Makefile:99: recipe for target 'install' failed
make[1]: *** [install] Error 1
arch/arm/Makefile:333: recipe for target 'install' failed
make: *** [install] Error 2
What am I doing wrong ?

gzip: stdout: No space left on device
This issue has nothing to do with your code. Your /boot filesystem is full.

Related

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

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.

Linux Kernel Driver Compilation Error on STM32MP1

I'm trying to compile a kernel module in Yocto on a STM32MP1 target. I can compile a helloworld example without problem. But as soon as I want to compile following:
#include <linux/platform_device.h>
#include <linux/module.h
#include <linux/types.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Robert W. Oliver II");
MODULE_DESCRIPTION("A simple example Linux module.");
MODULE_VERSION("0.01");
static struct platform_device *pdev;
static int __init fake_eth_add(void)
{
int inst_id = 0;
pdev = platform_device_alloc("fake-eth", inst_id);
return 0;
}
static void __exit fake_eth_put(void)
{
}
module_init(fake_eth_add);
module_exit(fake_eth_put);
I'm getting the following error:
root#txmp-1570:/home/rdm/ethtest# make
make -C /lib/modules/5.7.1/build M=/home/rdm/ethtest modules
make[1]: Entering directory '/lib/modules/5.7.1/build'
MODPOST 1 modules
ERROR: modpost: "platform_device_alloc" [/home/rdm/ethtest/eth-ins.ko] undefined!
make[2]: *** [scripts/Makefile.modpost:94: __modpost] Error 1
make[1]: *** [Makefile:1642: modules] Error 2
make[1]: Leaving directory '/lib/modules/5.7.1/build'
make: *** [Makefile:9: modules] Error 2
The header platform_device.h file is there, but no *.c module as it should be in a platform_device.c file.
My question is, do I need to do any parameter settings in the kernel? If yes, which would it be? So far I didn't find anything with google help regarding platform_device and kernel settings.

what does this error mean: interpreter /lib/ld-linux-armhf.so.3error reading (Invalid argument)

I use this guide enter link description heredocument to install cross compiler 4.9.3 and also qt4.8.6.I installed them and check the version that they correct.
http://www.mediafire.com/file/g0afghia7rkqx05/arm-cortexa9-linux-gnueabihf-4.9.3-20160512.tar.xz
http://www.mediafire.com/file/d54dbygdadergl1/target-qte-4.8.6-to-hostpc.tgz
then:
cd ~
mkdir helloqt
vi main.cpp
then I wrote it:
#include <QApplication>
#include <QPushButton>
int main(int argc, char **argv)
{
QApplication app (argc, argv);
QPushButton button ("Hello world !");
button.show();
return app.exec();
}
and save it
cd ~/helloqt
/usr/local/Trolltech/QtEmbedded-4.8.6-arm/bin/qmake -project
/usr/local/Trolltech/QtEmbedded-4.8.6-arm/bin/qmake
make
when I run this program in ubuntu-qt core I see this eeror:
root#NanoPC-T2:/# tftp 192.168.101.4
tftp> get helloqt
Received 11660 bytes in 0.4 seconds
tftp> quit
root#NanoPC-T2:/# chmod +x helloqt
root#NanoPC-T2:/# .setqt4env
-bash: .setqt4env: command not found
root#NanoPC-T2:/# . setqt4env
ctp = 1
root#NanoPC-T2:/# ./helloqt -qws &
[1] 1909
root#NanoPC-T2:/# ./helloqt -qws &
[2] 1910
[1] Segmentation fault ./helloqt -qws
root#NanoPC-T2:/# ./helloqt -qws
[2]+ Segmentation fault ./helloqt -qws
Segmentation fault
root#NanoPC-T2:/# ./helloqt -qws
Segmentation fault
root#NanoPC-T2:/# [2]+ Segmentation fault ./helloqt -qws
-bash: [2]+: command not found
root#NanoPC-T2:/# Segmentation fault
-bash: Segmentation: command not found
root#NanoPC-T2:/# file ./helloqt
./helloqt: ERROR: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3 error reading (Invalid argument)
How can I solve this error?
It means your file binary is damage. I do these to correct the problem:
my tslib configuration is not good and this code solve my first problem:
sudo ac_cv_func_malloc_0_nonnull=yes ./configure CC=/opt/FriendlyARM/toolchain/4.9.3/bin/arm-none-linux-gnueabihf-gcc CXX=/opt/FriendlyARM/toolchain/4.9.3/bin/arm-none-linux-gnueabihf-g++ --host=arm-none-linux-gnueabihf target=arm-none-linux-gnueabihf --enable-static=yes --enable-shared=yes -prefix=/home/tslib
you should copy the runable program to your device with SFTP(secure ftp), It does not change your file type.

Killing a process using pid and finding user tied to pid in system call

I'm trying to develop a system call that is able to receive pid as argument, kill the pid and print to the kernel log. So far I have the code below but i get this error when trying to compile the kernel. How do i fix this? And is there a way to find the username of that killed the pid that is to be killed in this case?
kill_log/kill_log.c:2:24: fatal error: signal.h: No such file or directory
compilation terminated.
scripts/Makefile.build:289: recipe for target 'kill_log/kill_log.o' failed
make[1]: * [kill_log/kill_log.o] Error 1
Makefile:968: recipe for target 'kill_log' failed
make: * [kill_log] Error 2
#include <linux/kernel.h>
#include <signal.h>
asmlinkage long sys_kill_log(pid_t pid)
{
kill(pid, SIGUSR1);
printk(KERN_WARNING "The process %d has been killed\n", pid);
return 0;
}
Based on your error message, you're missing signal.h. On debian-based systems, you would need to install libc6-dev.
In regards to retrieving the username, you could try with getpwuid.

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.

Resources