Passing arguments to custom system call - linux-kernel

I developed a custom system call to log killed processes. A C program kills the process and it invokes the custom system call, passes the process ID of the killed process and then the system call will print out the killed process's ID to the kernel's log. Here I'm just passing a dummy to test if the system call writes to the kernel log. The system call's number in the system call table is 329.
Below is my system call
#include <linux/kernel.h>
asmlinkage long sys_killa(char* proc_id)
{
printk("The process %s has been killed", proc_id);
return 0;
}
This is my C program to call my custom system call.
#include <stdio.h>
#include <linux/kernel.h>
#include <sys/syscall.h>
#include <unistd.h>
int main()
{
char proc_id[5] = "3219";
long int sys = syscall(329, proc_id);
printf("System call sys_killa returned %ld\n", sys);
return 0;
}
Running the C program simply prints "Killed" in the terminal. Running the program again crashes my virtual machine. Nothing is printed out in the kernel log when I check using dmesg utility. What am I doing wrong?

Need to use pid_t variable instead of String.This is the modified system call:
#include <linux/kernel.h>
asmlinkage long sys_killa(pid_t pid)
{
long pid_l = (long) pid;
printk("The process %ld has been killed", pid_l);
return 0;
}
This is the modified C code to use the system call:
#include <stdio.h>
#include <linux/kernel.h>
#include <sys/syscall.h>
#include <unistd.h>
int main()
{
pid_t pid = 3249;
long int sys = syscall(329, pid);
printf("System call sys_killa returned %ld\n", sys);
return 0;
}

Related

Sys V IPC msgsnd(), msgrcv() after fork()

I have a program running on Linux that fork()s after a TCP connection was accept()ed. Before the fork, it connects to a message queue via msgget() and happily sends and receives messages. At some point in the program, both the parent and the child will be waiting at the same time on a msgrcv() using the same msgtype. A separate process then sends a message via msgsnd() using this same msgtype.
However, only one of the forked processes returns from msgrcv(), and it also seems to depend on the path, the parent and the child took. It is very repeatable. In one case, only the parent receives the message, in another case only the child receives the message, leaving the other one waiting infinitely.
Does anyone have a hint on what could go wrong and why not both the parent and the child always receive the message?
I wrote two little test programs, recv.c and send.c, see below.
It turns out that the parent and the child only receive every other message. It seems to be strictly "every other", not even by chance which of the two receives a message. This would very well explain what's happening to my software.
Is this how message queues are supposed to work? Can I not send a message to multiple recipients?
/* recv.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/wait.h>
int main(void)
{
int msgid = msgget(247, 0666 | IPC_CREAT);
pid_t cldpid = fork();
struct msgform
{
long mtype;
char mbuf[16];
} msg;
msg.mtype = 1;
if (cldpid == 0)
{
while(true)
{
printf("Child waiting\n");
msgrcv(msgid, &msg, sizeof(msg), 1, 0);
printf("Child done\n");
}
}
while(true)
{
printf("Parent waiting\n");
msgrcv(msgid, &msg, sizeof(msg), 1, 0);
printf("Parent done\n");
}
return 0;
}
and
/* send.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/wait.h>
int main(void)
{
int msgid = msgget(247, 0666 | IPC_CREAT);
struct msgform {
long mtype;
char mbuf[16];
} msg;
msg.mtype = 1;
msgsnd(msgid, &msg, sizeof(msg), IPC_NOWAIT);
return 0;
}
Thanks

linux hw_breakpoint does not work while accessing memory from userspace

I am debugging a ARMv7 board and I want to know whether a kernel symbol is accessed. So I have to use hw_breakpoint in kernel.
For simplicity, I use kernel sample code:data_breakpoint to test, which locates in samples/hw_breakpoint/data_breakpoint.c.
Then I did the following operation:
insmod data_breakpoint.ko ksym=max
cat /proc/kallsyms | grep max
./read_kmem c06fa128
But this did not trigger the callback function.
If I print the value in that address in any kernel module, callback function will be triggered.
I read the cpu manual and it says that the breakpoint register in my cpu support virtual address matching. But I don't know why it doesn't work while accessing memory from userspace. I think that program does read the right value of kernel symbol.
read_kmem.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
#define DEVKMEM "/dev/kmem"
#define PAGE_SIZE 0x1000
#define PAGE_MASK (~(PAGE_SIZE-1))
int main(int argc, char* argv[])
{
int fd;
char *mbase;
char read_buf[10];
unsigned int varAddr;
varAddr = strtoul(argv[1], 0, 16);
unsigned int ptr = varAddr & ~(PAGE_MASK);
fd = open(DEVKMEM, O_RDONLY);
if (fd == -1) {
perror("open");
exit(-1);
}
mbase = mmap(0,PAGE_SIZE,PROT_READ,MAP_SHARED,fd, (varAddr & PAGE_MASK));
if (mbase == MAP_FAILED) {
printf("map failed %s\n",strerror(errno));
}
printf("varAddr = 0x%X \n", varAddr);
printf("mapbase = 0x%X \n", (unsigned int)mbase);
printf("value = 0x%X \n",*(unsigned int*)(mbase+ptr));
close(fd);
munmap(mbase,PAGE_SIZE);
return 0;
}
Your userspace does not access address c06fa128, it accesses a different address - one that that mmap() returned (plus offset). Thus no breakpoint hit.
The fact that virtual address being accessed resolves to same physical address as some other virtual address that has a breapoint, does not matter. CPU executing your userspace code has no idea that different mapping exists.

gdb cracking && cryptanalysis CTF

hello guys i am playing CTF and i have to crack a program to get shell the source code is :
/*
* gcc ch21.c -lcrypt -o ch21
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <crypt.h>
#include <sys/types.h>
#include <unistd.h>
int main (int argc, char *argv[]) {
char pid[16];
char *args[] = { "/bin/bash", "-p", 0 };
snprintf(pid, sizeof(pid), "%i", getpid());
if (argc != 2)
return 0;
printf("%s=%s",argv[1], crypt(pid, "$1$awesome"));
if (strcmp(argv[1], crypt(pid, "$1$awesome")) == 0) {
printf("WIN!\n");
execve(args[0], &args[0], NULL);
} else {
printf("Fail... :/\n");
}
return 0;
}
now i debugged it with gdb as i understood from the source i have to enter proccessid (PID) during runtime to get successful shell with GDB-PEDA i have tried getpid during breakpoint but how to continue with proccess id with gdb only run command pass input to the program any help !
any notify !
Not sure if I understood your question correctly, but PID is limited in range and cycle when there limit is reached and the max is usually around 2^15. You could simply run a loop that would run through the potential PID to match the one that will be assigned for the process.
Something like this would do:
import os, crypt, subprocess
pid = os.getpid()+50 #safe buffer for things created after python script was started
print "Selected: ",pid
for i in range(32768):
sp = subprocess.Popen(['./ch21', crypt.crypt(str(pid), "$1$awesome")], stdout=subprocess.PIPE)
output = sp.stdout.readline()
if "Fail" not in output:
print output
break

How to make lldb ignore EXC_BAD_ACCESS exception?

I am writing a program on Mac OSX depending on the sigaction/sa_handler mechanism. Run a code snippet from user and get ready to catch signals/exceptions at any time. The program works fine, but the problem is I can't debug it with lldb. lldb seems not being able to ignore any exceptions even I set
proc hand -p true -s false SIGSEGV
proc hand -p true -s false SIGBUS
The control flow stops at the instruction that triggers the exception and does not jump to the sa_handler I installed earlier even I tried command c. The output was:
Process 764 stopped
* thread #2: tid = 0xf140, 0x00000001000b8000, stop reason = EXC_BAD_ACCESS (code=2, address=0x1000b8000)
How do I make lldb ignore the exception/signal and let the sa_handler of the program do its work?
EDIT: sample code
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
static void handler(int signo, siginfo_t *sigaction, void *context)
{
printf("in handler.\n");
signal(signo, SIG_DFL);
}
static void gen_exception()
{
printf("gen_exception in.\n");
*(int *)0 = 0;
printf("gen_exception out.\n");
}
void *gen_exception_thread(void *parg)
{
gen_exception();
return 0;
}
int main()
{
struct sigaction sa;
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
if(sigaction(/*SIGBUS*/SIGSEGV, &sa, NULL) == -1) {
printf("sigaction fails.\n");
return 0;
}
pthread_t id;
pthread_create(&id, NULL, gen_exception_thread, NULL);
pthread_join(id, NULL);
return 0;
}
I needed this in a recent project, so I just built my own LLDB. I patched a line in tools/debugserver/source/MacOSX/MachTask.mm from
err = ::task_set_exception_ports (task, m_exc_port_info.mask, m_exception_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE);
to
err = ::task_set_exception_ports (task, m_exc_port_info.mask & ~EXC_MASK_BAD_ACCESS, m_exception_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE);
which causes the debugserver to be unable to catch EXC_BAD_ACCESS exceptions. Now, my custom LLDB works just fine: it still catches SIGSEGV and SIGBUS but no longer enters a silly infinite loop when faced with EXC_BAD_ACCESS. Setting process handle options on the previously-fatal signals works fine too, and I can now debug SEGV handlers with impunity.
Apple really ought to make this an option in LLDB...seems like a really easy fix for them.
This is a long-standing bug in the debugger interface in Mac OS X (gdb had the same problem...) If you have a developer account, please file a bug with http://bugreport.apple.com. So few people actually use SIGSEGV handlers that the problem never gets any attention from the kernel folks, so more bugs is good...
We can do it easily. Just add this code.
#include <mach/task.h>
#include <mach/mach_init.h>
#include <mach/mach_port.h>
int ret = task_set_exception_ports(
mach_task_self(),
EXC_MASK_BAD_ACCESS,
MACH_PORT_NULL,//m_exception_port,
EXCEPTION_DEFAULT,
0);
Don't forget to do this
proc hand -p true -s false SIGSEGV
proc hand -p true -s false SIGBUS
Full code:
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <mach/task.h>
#include <mach/mach_init.h>
#include <mach/mach_port.h>
static void handler(int signo, siginfo_t *sigaction, void *context)
{
printf("in handler.\n");
signal(signo, SIG_DFL);
}
static void gen_exception()
{
printf("gen_exception in.\n");
*(int *)0 = 0;
printf("gen_exception out.\n");
}
void *gen_exception_thread(void *parg)
{
gen_exception();
return 0;
}
int main()
{
task_set_exception_ports(
mach_task_self(),
EXC_MASK_BAD_ACCESS,
MACH_PORT_NULL,//m_exception_port,
EXCEPTION_DEFAULT,
0);
struct sigaction sa;
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
if(sigaction(/*SIGBUS*/SIGSEGV, &sa, NULL) == -1) {
printf("sigaction fails.\n");
return 0;
}
pthread_t id;
pthread_create(&id, NULL, gen_exception_thread, NULL);
pthread_join(id, NULL);
return 0;
}
Refer to (Chinese article): https://zhuanlan.zhihu.com/p/33542591
A little bit of example code can make a question like this a lot easier to answer ... I've never used the sigaction API before but I threw this together -
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void segv_handler (int in)
{
puts ("in segv_handler()");
}
void sigbus_handler (int in)
{
puts ("in sigbus_handler()");
}
int main ()
{
struct sigaction action;
action.sa_mask = 0;
action.sa_flags = 0;
action.sa_handler = segv_handler;
sigaction (SIGSEGV, &action, NULL);
action.sa_handler = sigbus_handler;
sigaction (SIGBUS, &action, NULL);
puts ("about to send SIGSEGV signal from main()");
kill (getpid(), SIGSEGV);
puts ("about to send SIGBUS signal from main()");
kill (getpid(), SIGBUS);
puts ("exiting main()");
}
% lldb a.out
(lldb) br s -n main
(lldb) r
(lldb) pr h -p true -s false SIGSEGV SIGBUS
(lldb) c
Process 54743 resuming
about to send SIGSEGV signal from main()
Process 54743 stopped and restarted: thread 1 received signal: SIGSEGV
in segv_handler()
about to send SIGBUS signal from main()
Process 54743 stopped and restarted: thread 1 received signal: SIGBUS
in sigbus_handler()
exiting main()
Process 54743 exited with status = 0 (0x00000000)
(lldb)
Everything looks like it's working correctly here. If I'd added -n false to the process handle arguments, lldb wouldn't have printed the lines about Process .. stopped and restarted.
Note that these signal settings do not persist across process executions. So if you're starting your debug session over (r once you've already started the process once), you'll need to re-set these. You may want to create a command alias shortcut and put it in your ~/.lldbinit file so you can set the process handling the way you prefer with a short cmd.

execlp() in C doesn't give prompt back after execution

I try to fork() a child which will run an ls command.
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
if (fork()==0){ //child
execlp("ls", "ls", "-l", (char*)0);
exit(1);
}
fflush(stderr); //doesn't fix my problem
fflush(stdout); //doesn't fix my problem
exit(0);
}
This works fine but the cursor gets stuck after the execution of the child. I have to press the enter key to get back the terminal. Why is that?
Your main process exits before the child process is done. Wait for the child process to exit using wait() or waitpid().

Resources