Understanding Linux kernel semaphore - linux-kernel

My understanding of semaphore is:
count cannot go below 0 : if tried block the task.
count cannot go above the value given during sema_init().
First case is always honoured. However as you can see from below code, I can increase the count of semaphore beyond the given value, I was expecting down_interruptible() get blocked and up() to fail to increment the count.
# uname -r
5.4.0-132-generic
# tree
.
├── Makefile
├── sm_define.c
Makefile:
obj-m := sm_define.o
KVERS := $(shell uname -r)
all:
make -C /lib/modules/$(KVERS)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(KVERS)/build M=$(PWD) clean
sm_define.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/semaphore.h>
struct semaphore sem;
static int __init
start_module(void)
{
int ret;
sema_init(&sem, 1); /* Binary semaphore */
up(&sem);
up(&sem);
up(&sem);
printk(KERN_INFO "count %d\n", sem.count);
ret = down_interruptible(&sem);
if (ret) {
printk(KERN_INFO "down_interruptible : failed\n");
return -EINVAL;
}
printk(KERN_INFO "count %d\n", sem.count);
ret = down_interruptible(&sem);
if (ret) {
printk(KERN_INFO "down_interruptible : failed\n");
return -EINVAL;
}
printk(KERN_INFO "count %d\n", sem.count);
ret = down_interruptible(&sem);
if (ret) {
printk(KERN_INFO "down_interruptible : failed\n");
return -EINVAL;
}
printk(KERN_INFO "count %d\n", sem.count);
return 0;
}
static void __exit
end_module(void)
{
printk(KERN_INFO "Module exited.\n");
return;
}
module_init(start_module);
module_exit(end_module);
MODULE_LICENSE("GPL");
Output:
# insmod sm_define.ko
# rmmod sm_define
# dmesg
[ 8492.896319] count 4
[ 8492.896320] count 3
[ 8492.896320] count 2
[ 8492.896320] count 1
[ 8500.225030] Module exited.
#
Why this behaviour? and if it is allowed and can't we say notion of binary / counting semaphore is a myth, its just the self followed rule during code, that "I will never increment the value of semaphore before decrementing it?

Related

c++ get value from memory a process

I'm trying to get the int value of a processes' memory address.
I have been able to write to the memory address can't read the memory address value.
#include <iostream>
#include <windows.h>
#include <chrono>
#include <ctime>
using namespace std;
int main(void) {
int nVal = 40000;
HWND hWnd = FindWindowA(0, "Crusader");
if(hWnd == 0){
cerr << "Could not find window." << endl;
} else {
DWORD PID;
GetWindowThreadProcessId(hWnd, &PID);
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, false, PID);
if(!hProc) {
cerr << "Cannot open process." << endl;
} else {
int buffer = 0;
int stat = WriteProcessMemory(hProc, (LPVOID)0x0115FCF8, &nVal, (DWORD)sizeof(nVal), NULL);
SIZE_T NumberOfBytesToRead = sizeof(buffer); //this is equal to 4
SIZE_T NumberOfBytesActuallyRead;
int stat2 = ReadProcessMemory(hProc, (LPVOID)0x0115FCF8, &buffer, NumberOfBytesToRead, &NumberOfBytesActuallyRead);
std:cout<< *stat2;
/* if(stat > 0){
clog << "Memory written to process." << endl;
} else {
cerr << "Memory couldn't be written to process." << endl;
}
*/
CloseHandle(hProc);
cin.get();
}
}
return 0;
}
I can assign a value to the memory address, but reading the memory address returns 1.
How can i get the value of the address
stat and stat2 represent the return value of the Read/Write ProcessMemory calls, these are used in error checking. You appear to be thinking they are the values of the addresses you're trying to read and write.
Assuming your target process is x86, you're compiling for x86, you're running as admin and all your addresses are correct then just change that last line to:
std:cout<< buffer;
This should output the integer representation of the data in 0x0115FCF8
If 0x0115FCF8 is data, not code this should work fine. If it's code, the page will not have write permissions and you will have to change the page permission with VirtualProtectEx to include WRITE.

Setting Include Paths When Building Kernel Modules

I'm trying to compile a kernel module for Linux. I have the following files: testuio.c and Makefile. When I type make all I get the following errors:
$ make all
make -C /lib/modules/`uname -r`/build M=/srv/dev-disk-by-label-tboWolfRaid/home/alex/ma/source/kernel_modules/memory modules
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-0.bpo.2-amd64'
CC [M] /srv/dev-disk-by-label-tboWolfRaid/home/alex/ma/source/kernel_modules/memory/testuio.o
In file included from /usr/include/unistd.h:25,
from /srv/dev-disk-by-label-tboWolfRaid/home/alex/ma/source/kernel_modules/memory/testuio.c:13:
/usr/include/features.h:424:12: fatal error: sys/cdefs.h: No such file or directory
# include <sys/cdefs.h>
^~~~~~~~~~~~~
compilation terminated.
make[3]: *** [/usr/src/linux-headers-5.4.0-0.bpo.2-common/scripts/Makefile.build:271: /srv/dev-disk-by-label-tboWolfRaid/home/alex/ma/source/kernel_modules/memory/testuio.o] Error 1
make[2]: *** [/usr/src/linux-headers-5.4.0-0.bpo.2-common/Makefile:1665: /srv/dev-disk-by-label-tboWolfRaid/home/alex/ma/source/kernel_modules/memory] Error 2
make[1]: *** [/usr/src/linux-headers-5.4.0-0.bpo.2-common/Makefile:179: sub-make] Error 2
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-0.bpo.2-amd64'
make: *** [Makefile:19: all] Error 2
This is correct, there is no such file under /usr/include/sys/. What I don't understand is why it would not find it under /usr/include/x86_64-linux-gnu/sys where there is such a file.
The following is part of gcc -xc -E -v - output:
#include <...> search starts here:
.
/usr/lib/gcc/x86_64-linux-gnu/8/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/8/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
My Makefile contains:
# (1) consult https://www.kernel.org/doc/Documentation/kbuild/modules.txt to build a kbuild-compatible Makefile
# sections of special interest: 3.1 (shared makefile)
# (2) specifics about the Makefile under https://www.kernel.org/doc/Documentation/kbuild/makefiles.txt
# sections of special interest 3.7 (compilation flags)
ifneq ($(KERNELRELEASE),)
# kbuild part of the makefile (could pull this out into a file named Kbuild, this variant is more robust though)
obj-m += testuio.o
CFLAGS_testuio.o = -I/usr/include/x86_64-linux-gnu
ccflags-m = -I/usr/include/x86_64-linux-gnu # see (2) section 3.7
ccflags-y += ${ccflags-m}
#ccflags-y = -I/usr/include/aarch64-linux-gnu -I/usr/include # see (2) section 3.7
else
# "normal" makefile
KDIR ?= /lib/modules/`uname -r`/build # ?= sets KDIR only if it has no value already
all:
make -C $(KDIR) M=$(PWD) modules
install:
make -C $(KDIR) M=$(PWD) modules_install
clean:
make -C $(KDIR) M=$(PWD) clean
endif
For reference my testuio.c contains:
// In order for a device to be compatible with this UIO platform device driver
// it needs to use "generic-uio" in its compatible property
// This is a kernel driver.
#include <linux/module.h> // included for module_* macros
#include <linux/device.h> // included for devm_kzalloc
#include <linux/mman.h> // included for mmap
// #include <linux/stat.h> // included for fstat (for being able to read out of files)
#include <linux/platform_device.h> // included for struct platform_device
#include <linux/uio_driver.h> // included for struct uio_info
#include <unistd.h> // included for read and write syscalls
#include <fcntl.h> // included for file creation flags
#include <stdio.h> // included for FILE* type, fscanf
#define EOPENUIOFD 1
#define EMEMMAP 2
#define UIO_SIZE_FILE "/sys/class/uio/uio0/maps/map0/size"
MODULE_LICENSE("");
MODULE_AUTHOR("Alexander Pastor");
MODULE_VERSION("0.0.1");
// MODULE_DEVICE_TABLE(???);
typedef struct testuio_dev {
struct uio_info* info;
} testuio_dev;
// TODO: change s.t. interupts can be handled correctly
// HINT: might not be necessary tho
static int testuio_irq_handler(int irq, struct uio_info* info)
{
// if (IRQ is not caused by my hardware)
if (true)
return IRQ_NONE;
/* Disable interrupt */
// Perform some register access to silence the IRQ line
return IRQ_HANDLED;
}
static int testuio_probe(struct platform_device* pdev)
{
struct testuio_dev* dev;
struct resource* res;
int irq;
// collect handles and information from platform device
// devm_kzalloc => managed (free upon detaching device from system) kernel zero-initialized memory allocation
// gfp flags => get free page flags
dev = devm_kzalloc(&pdev->dev, (sizeof(struct testuio_dev)), GFP_KERNEL);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
// basic uio info struct initialization (required!)
dev->info->name = "testuio";
dev->info->version = "0.0.1";
// memory region initialization
dev->info->mem[0].name = "dummy_mem";
dev->info->mem[0].addr = res->start;
dev->info->mem[0].size = resource_size(res);
dev->info->mem[0].memtype = UIO_MEM_PHYS;
// other memory types include:
// - UIO_MEM_LOGICAL allocated by kmalloc
// - UIO_MEM_VIRTUAL allocated by vmalloc
// interrupt initialization
dev->info->irq = irq;
dev->info->irq_flags = 0;
dev->info->handler = &testuio_irq_handler;
if(uio_register_device(&pdev->dev, info))
{
iounmap(dev->info->mem[0].internal_addr);
return -ENODEV;
} else {
return 0;
}
}
int main(int argc, char** argv)
{
int uio_fd; // UIO file descriptor
unsigned int uio_size; // memory size of UIO
FILE* size_fp; // pointer to the file containing memory size
void* base_address; // start address of mapped memory
uio_fd = open(/dev/uio, O_RDWR);
if(uio_fd == -1)
return EOPENUIOFD;
size_fp = fopen(UIO_SIZE_FILE, O_RDONLY);
fscanf(size_fp, "0x%08x", &uio_size); // 0x%08x expects unsigned int; %p expects void*
// Whenever the user space program reads or writes in the virtual address range
// it is accessing the device w/o the need for a system call. This improves performance.
base_address = mmap(NULL, // NULL => kernel chooses page-aligned address at which to create mapping
uio_size, // length of memory mapping
PROT_READ | PROT_WRITE, // flags: grant read + write access
MAP_SHARED_VALIDATE, // updates to mapping are visible to other processes
// (+validates given flags, available since Linux 4.15)
uio_fd,
0);
if (uio_fd == MAP_FAILED)
return EMEMMAP;
// --- BEGIN APPLICATION CODE
// ??? Is this even the right spot for the application code
// see also
// https://docplayer.net/37414164-Linux-user-space-device-drivers-john-linn-based-on-3-14-linux-kernel.html
// helpful: https://stackoverflow.com/questions/26259421/use-mmap-in-c-to-write-into-memory
// TODO: read in content from file as done in link above using fstat
int testvals[8] = {0xDEADBEEF, 7, 12, 13, 31, 42, -63, -65535}
memcpy(base_address, testvals, sizeof(testvals));
for(int i=0; i<8; i++)
{
printk(KERN_INFO "The value at address %p is %d",
base_address+i*sizeof(int),
(int)*(base_address+i*sizeof(int)));
}
//! interrupt stuff
// read() returns the number of interrupt events.
// It allows blocking and non-blocking modes with this being blocking mode
int pending = 0;
int reennable = 1;
read(uio_fd, (void*)&pending, sizeof(int));
//! device specific processing
// acking the interrupt in the device
write(uio_fd, (void*)&reenable, sizeof(int));
// --- END APPLICATON CODE
//! undo virtual address mapping
munmap(base_address, uio_size);
return 0;
}
You seem to be mixing up kernel and userspace stuff in your code. However all this is wrong:
CFLAGS_testuio.o = -I/usr/include/x86_64-linux-gnu
ccflags-m = -I/usr/include/x86_64-linux-gnu # see (2) section 3.7
ccflags-y += ${ccflags-m}
As you're stitching some user-space include paths to your kernel flags.
And also all these:
#include <unistd.h> // included for read and write syscalls
#include <fcntl.h> // included for file creation flags
#include <stdio.h> // included for FILE* type, fscanf
don't belong in a kernel module.The main function also has to go away.
My assumption is you need a kernel module and a userspace application to test it. Don't mix the two of them together. Keep these things separate.

`ioctl` to read and write GPIO: invalid argument

I'm imitating the gpio-hammer example in Linux source code. I'm using Raspberry Pi 3B+ and want an LED to blink.
Here's what I do:
#include <linux/gpio.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
int main(int argc, const char **argv) {
int fd, ret;
struct gpiohandle_request req;
struct gpiohandle_data data;
char *gpio_dev_name = "/dev/gpiochip0";
unsigned int gpio_line = 8;
memset(&data.values, 0, sizeof(data.values));
// open device
fd = open(gpio_dev_name, 0);
if (fd == -1) {
fprintf(stderr, "Failed to open %s, %s\n",
gpio_dev_name, strerror(errno));
}
// request gpio output
req.lineoffsets[0] = gpio_line;
req.flags = GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW;
strcpy(req.consumer_label, "blink");
req.lines = 1;
memcpy(req.default_values, &data, sizeof(req.default_values));
ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
if (ret == -1) {
fprintf(stderr, "Failed to issue %s (%d), %s\n",
"GPIO_GET_LINEHANDLE_IOCTL", ret, strerror(errno));
}
// blink
while (1) {
// read data
ret = ioctl(fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
if (ret == -1) {
ret = -errno;
fprintf(stderr, "Failed to issue %s (%d), %s\n",
"GPIOHANDLE_GET_LINE_VALUES_IOCTL", ret, strerror(errno));
exit(ret);
}
// flip digits
data.values[0] = !data.values[0];
// set data
ret = ioctl(fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
if (ret == -1) {
ret = -errno;
fprintf(stderr, "Failed to issue %s (%d), %s\n",
"GPIOHANDLE_SET_LINE_VALUES_IOCTL", ret, strerror(errno));
exit(ret);
}
// delay
sleep(1);
}
}
I can compile the gpio-hammer example on RPi and run it with ./gpio-hammer -n gpiochip0 -o 8. Attached to gpiochip0 line8 is an LED and it blinks.
But my program does not work. It fails with
Failed to issue GPIOHANDLE_GET_LINE_VALUES_IOCTL (-22), Invalid argument
I looked into the implement of gpiolib. The ioctl of gpio line handle returns EINVAL (22) if ioctl cmd is not GPIOHANDLE_GET_LINE_VALUES_IOCTL nor GPIOHANDLE_SET_LINE_VALUES_IOCTL. But that's not the case. What's going wrong?
In linux/gpio.h, the description of struct gpiohandle_request says:
/*
* ...
* #fd: if successful this field will contain a valid anonymous file handle
* after a GPIO_GET_LINEHANDLE_IOCTL operation, zero or negative value
* means error
*/
struct gpiohandle_request {
__u32 lineoffsets[GPIOHANDLES_MAX];
__u32 flags;
__u8 default_values[GPIOHANDLES_MAX];
char consumer_label[32];
__u32 lines;
int fd;
};
When use GPIO_GET_LINEHANDLE_IOCTL, the file handle of GPIO chip device is passed through the first argument of ioctl(), and another file handle will be sent back in gpiohandle_request::fd, if the operation successes. This new fd should be used in ioctl of GPIO_GET_LINE_VALUES_IOCTL or GPIO_SET_LINE_VALUES_IOCTL.
So the code should be
ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
if (ret == -1) {
fprintf(stderr, "Failed to issue %s (%d), %s\n",
"GPIO_GET_LINEHANDLE_IOCTL", ret, strerror(errno));
}
else {
if (close(fd) == -1) {
fprintf(stderr, "Failed to close GPIO char dev.\n");
}
fd = req.fd;
}

uprobe programming on ARM Target

I want place a uprobe on target ARMV7 Board, i have uprobe_example.ko which is build against kernel 2.6.39.
insmod uprobe_example.ko vaddr=$vaddr pid=$!
Uprobes handles interesting events in the lifetime of the probed
+process, such as fork, clone, exec, and exit.
# insmod uprobe_example.ko pid=1461 vaddr=0x000084ac
[15245.267358] up: Unknown parameterpid'`
I want to Insert this module with the above parameters, it is not allowing.
/*
* Usage: insmod uprobe_example.ko pid=<pid> vaddr=<address> [verbose=0]
* where <pid> identifies the probed process and <address> is the virtual
* address of the probed instruction.
*/
static int pid = 0;
module_param(pid, int, 0);
MODULE_PARM_DESC(pid, “pid”);
static int verbose = 1;
module_param(verbose, int, 0);
MODULE_PARM_DESC(verbose, “verbose”);
static long vaddr = 0;
module_param(vaddr, long, 0);
MODULE_PARM_DESC(vaddr, “vaddr”);
static int nhits;
static struct uprobe usp;
static void uprobe_handler(struct uprobe *u, struct pt_regs *regs)
{
nhits++;
if (verbose)
printk(KERN_INFO “Hit #%d on probepoint at %#lx\n”,
nhits, u->vaddr);
}
int __init init_module(void)
{
int ret;
usp.pid = pid;
usp.vaddr = vaddr;
usp.handler = uprobe_handler;
printk(KERN_INFO “Registering uprobe on pid %d, vaddr %#lx\n”,
usp.pid, usp.vaddr);
ret = register_uprobe(&usp);
if (ret != 0) {
printk(KERN_ERR “register_uprobe() failed, returned %d\n”, ret);
return -1;
}
return 0;
}
void __exit cleanup_module(void)
{
printk(KERN_INFO “Unregistering uprobe on pid %d, vaddr %#lx\n”,
usp.pid, usp.vaddr);
printk(KERN_INFO “Probepoint was hit %d times\n”, nhits);
unregister_uprobe(&usp);
}
Make File
obj-m := uprobe_example.o
KERNELDIR ?= $(DLI_KERNEL)
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) EXTRA_CFLAGS=-I`pwd` modules
#sync.sh up.ko
clean:
rm -f *.o *.ko *.mod.c *.symvers
rm -f trace/*.o arch/*.o
obj-m += uprobe_example.o
KERNELDIR ?= $(DLI_KERNEL)
all:
make -C $(KERNELDIR) M=$(PWD) modules
clean:
make -C $(KERNELDIR) M=$(PWD) clean
This Makefile will work fine, without any errors

C shell printing output infinitely without stopping at gets()

I am trying to use the SIGCHLD handler but for some reason it prints of the command I gave infinitely. If I remove the struct act it works fine.
Can anyone take a look at it, I am not able to understand what the problem is.
Thanks in advance!!
/* Simplest dead child cleanup in a SIGCHLD handler. Prevent zombie processes
but dont actually do anything with the information that a child died. */
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
typedef char *string;
/* SIGCHLD handler. */
static void sigchld_hdl (int sig)
{
/* Wait for all dead processes.
* We use a non-blocking call to be sure this signal handler will not
* block if a child was cleaned up in another part of the program. */
while (waitpid(-1, NULL, WNOHANG) > 0) {
}
}
int main (int argc, char *argv[])
{
struct sigaction act;
int i;
int nbytes = 100;
char my_string[nbytes];
string arg_list[5];
char *str;
memset (&act, 0, sizeof(act));
act.sa_handler = sigchld_hdl;
if (sigaction(SIGCHLD, &act, 0)) {
perror ("sigaction");
return 1;
}
while(1){
printf("myshell>> ");
gets(my_string);
str=strtok(my_string," \n");
arg_list[0]=str;
i =1;
while ( (str=strtok (NULL," \n")) != NULL){
arg_list[i]= str;
i++;
}
if (i==1)
arg_list[i]=NULL;
else
arg_list[i+1]=NULL;
pid_t child_pid;
child_pid=fork();
if (child_pid == (pid_t)-1){
printf("ERROR OCCURED");
exit(0);
}
if(child_pid!=0){
printf("this is the parent process id is %d\n", (int) getpid());
printf("the child's process ID is %d\n",(int)child_pid);
}
else{
printf("this is the child process, with id %d\n", (int) getpid());
execvp(arg_list[0],arg_list);
printf("this should not print - ERROR occured");
abort();
}
}
return 0;
}
I haven't run your code, and am merely hypothesizing:
SIGCHLD is arriving and interrupting fgets (I'll just pretend you didn't use gets). fgets returns before actually reading any data, my_string contains the tokenized list that it had on the previous loop, you fork again, enter fgets, which is interrupted before reading any data, and repeat indefinitely.
In other words, check the return value of fgets. If it is NULL and has set errno to EINTR, then call fgets again. (Or set act.sa_flags = SA_RESTART.)

Resources