I am having trouble resetting a process after I have hit a breakpoint with Ptrace. I am essentially wrapping this code in python.
I am running this on 64 bit Ubuntu.
I understand the concept of resetting the data at the location and decrementing the instruction pointer, but after I get the trap signal and do that, my process is not finishing.
Code snippet:
# Continue to bp
res = libc.ptrace(PTRACE_CONT,pid,0,0)
libc.wait(byref(wait_status))
if _wifstopped(wait_status):
print('Breakpoint hit. Signal: %s' % (strsignal(_wstopsig(wait_status))))
else:
print('Error process failed to stop')
exit(1)
# Reset Instruction pointer
data = get_registers(pid)
print_rip(data)
data.rip -= 1
res = set_registers(pid,data)
# Verify rip
print_rip(get_registers(pid))
# Reset Instruction
out = set_text(pid,c_ulonglong(addr),c_ulonglong(initial_data))
if out != 0:
print_errno()
print_text(c_ulonglong(addr),c_ulonglong(get_text(c_void_p(addr))))
And I run a PTRACE_DETACH right after returning from this code.
When I run this, it hits the breakpoint the parent process returns successfully, but the child does not resume and finish its code.
If I comment out the call to the breakpoint function it just attaches ptrace to the process and then detaches it, and the program runs fine.
The program itself is just a small c program that prints 10 times to a file.
Full code is in this paste
Is there an error anyone sees with my breakpoint code?
I ended up writing a C program that was as exact a duplicate of the python code as possible:
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <syscall.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/reg.h>
#include <sys/user.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
void set_unset_bp(pid){
int wait_status;
struct user_regs_struct regs;
unsigned long long addr = 0x0000000000400710;
unsigned long long data = ptrace(PTRACE_PEEKTEXT,pid,(void *)addr,0);
printf("Orig data: 0x%016x\n",data);
unsigned long long trap = (data & 0xFFFFFFFFFFFFFF00) | 0xCC;
ptrace(PTRACE_POKETEXT,pid,(void *)addr,(void *)trap);
ptrace(PTRACE_CONT,pid,0,0);
wait(&wait_status);
if(WIFSTOPPED(wait_status)){
printf("Signal recieved: %s\n",strsignal(WSTOPSIG(wait_status)));
}else{
perror("wait");
}
ptrace(PTRACE_POKETEXT,pid,(void *)addr,(void *)data);
ptrace(PTRACE_GETREGS,pid,0,®s);
regs.rip -=1;
ptrace(PTRACE_SETREGS,pid,0,®s);
data = ptrace(PTRACE_PEEKTEXT,pid,(void *)addr,0);
printf("Data after resetting bp data: 0x%016x\n",data);
ptrace(PTRACE_CONT,pid,0,0);
}
int main(void){
//Fork child process
extern int errno;
int pid = fork();
if(pid ==0){//Child
ptrace(PTRACE_TRACEME,0,0,0);
int out = execl("/home/chris/workspace/eliben-debugger/print","/home/chris/workspace/eliben-debugger/print",0);
if(out != 0){
printf("Error Value is: %s\n", strerror(errno));
}
}else{ //Parent
wait(0);
printf("Got stop signal, we just execv'd\n");
set_unset_bp(pid);
printf("Finished setting and unsetting\n");
wait(0);
printf("Got signal, detaching\n");
ptrace(PTRACE_DETACH,pid,0,0);
wait(0);
printf("Parent exiting after waiting for child to finish\n");
}
exit(0);
}
After comparing the output to my Python output I noticed that according to python my original data was 0xfffffffffffe4be8 and 0x00000000fffe4be8.
This lead me to believe that my return data was getting truncated to a 32 bit value.
I changed my get and set methods to something like this, setting the return type to a void pointer:
def get_text(addr):
restype = libc.ptrace.restype
libc.ptrace.restype = c_void_p
out = libc.ptrace(PTRACE_PEEKTEXT,pid,addr, 0)
libc.ptrace.restype = restype
return out
def set_text(pid,addr,data):
return libc.ptrace(PTRACE_POKETEXT,pid,addr,data)
Can't tell you how it works yet, but I was able to get the child process executing successfully after the trap.
Related
On linux and macOS, directories can be nested to seemingly arbitrary depth, as demonstrated by the following C program. However, on macOS but not on linux, there seems to be a hard limit on the nesting level returned by getcwd, specifically a nesting level of 256. When that limit is reached, getcwd returns ENOENT, a rather strange error code. Where does this limit come from? Is there a way around it?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
void fail(char *msg) { perror(msg); exit(1); }
void create_nested_dirs(int n) {
int i;
char name[10];
char cwd[10000];
if (chdir("/tmp") < 0) fail("chdir(\"/tmp\")");
for (i=2; i<=n; i++) {
sprintf(name, "%09d", i);
printf("%s\n",name);
if (mkdir(name, 0777) < 0 && errno != EEXIST) fail("mkdir");
if (chdir(name) < 0) fail("chdir(name)");
if (getcwd(cwd, sizeof(cwd)) == NULL) fail("getcwd");
printf("cwd = \"%s\" strlen(cwd)=%d\n", cwd, strlen(cwd));
}
}
int main() {
long ret = pathconf("/", _PC_PATH_MAX);
printf("PATH_MAX is %ld\n", ret);
create_nested_dirs(300);
return 0;
}
Update
The above program was updated to print the value returned by pathconf("/", _PC_PATH_MAX) and to print the length of the path returned by getcwd.
On my machine running macOS Mojave 10.14, the PATH_MAX is 1024 and the longest string correctly returned by getcwd is 2542 characters long. Then a 2552 character long directory of nesting depth 256 is created by mkdir and then after a successful chdir to that directory a getcwd fails with ENOENT.
If the sprintf(name, "%09d", i); is changed to sprintf(name, "%03d", i); the paths are considerably shorter but the getcwd still fails when the directory nesting depth reaches 256.
So the limiting factor here is the nesting depth, not PATH_MAX.
My understanding of the source code here is that the meat of the work is done by the call fcntl(fd, F_GETPATH, b) so the problem may be in fcntl.
I try to run a sample code as below. The ioctl returned -1 and the error is "Invalid argument". What I know is that ioctl here is used to check the state of shift. Does ioctl return success when the shift is pressed? If not, how do I know the shift is pressed by using ioctl?
Plus, it's under xterm.
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
int main()
{
char shift_state;
shift_state = 6;
if (ioctl(0, TIOCLINUX, &shift_state) < 0) {
perror("ioctl TIOCLINUX 6 (get shift state)");
exit(1);
}
printf("%x\n", shift_state);
return 0;
}
I found out that sys_kill can be used to kill process from a system call, but when i compile the following code, i get the following error:
error: implicit declaration of function ‘sys_kill’ [-Werror=implicit-function-declaration]
long kill = sys_kill(pid,SIGKILL);
#define _POSIX_SOURCE
#include <linux/kernel.h>
#include <linux/unistd.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/cred.h>
asmlinkage long sys_killa(pid_t pid)
{
printk(KERN_INFO "Current UID = %u\n",get_current_user()->uid);
printk(KERN_WARNING "The process to be killed is %d \n", pid);
long kill = sys_kill(pid,SIGKILL);
printk(KERN_WARNING "sys kill returned %ld\n", kill);
return 0;
}
It is often not possible to call the entry point of a system call from the kernel, since the API is for use from user space. Sometimes the functionality is provided in code close to the implementation code. It is usually made available throughout the kernel via an EXPORT_SYMBOL() macro.
For the kill() system call there is the internal kernel function kill_pid, with the declaration
int kill_pid(struct pid *pid, int sig, int priv)
You need to pass a struct pointer to the process, signal number, and boolean 1. Look at other code making this call for how to do so.
I am trying to write a program that will constantly keep track of the changes in a file and do several actions accordingly. I am using inotify and select within a loop to track file modifications in a non-blocking manner. The basic structure of the file tracking portion of my program is as follows.
#include <cstdio>
#include <signal.h>
#include <limits.h>
#include <sys/inotify.h>
#include <fcntl.h>
#include <iostream>
#include <fstream>
#include <string>
int main( int argc, char **argv )
{
const char *filename = "input.txt";
int inotfd = inotify_init();
char buffer[1];
int watch_desc = inotify_add_watch(inotfd, filename, IN_MODIFY);
size_t bufsiz = sizeof(struct inotify_event) + 1;
struct inotify_event* event = ( struct inotify_event * ) &buffer[0];
fd_set rfds;
FD_ZERO (&rfds);
struct timeval timeout;
while(1)
{
/*select() intitialisation.*/
FD_SET(inotfd,&rfds); //keyboard to be listened
timeout.tv_sec = 10;
timeout.tv_usec = 0;
int res=select(FD_SETSIZE,&rfds,NULL,NULL,&timeout);
FD_ZERO(&rfds);
printf("File Changed\n");
}
}
I checked the select manual page and reset the fd_set descriptor each time select() returns. However, whenever I modify the file (input.txt), this code just loops infinitely. I not very experienced using inotify and select, so, I am sure if the problem is with the way I use inotify or select. I would appreciate any hints and recommentations.
you have to read the contents of the buffer after the select returns. if the select() finds data in the buffer, it returns. so, perform read() on that file descriptor (inotfd). read call reads the data and returns amount of bytes it read. now, the buffer is empty and in the next iteration, the select() call waits until any data is available in the buffer.
while(1)
{
// ...
char pBuf[1024];
res=select(FD_SETSIZE,&rfds,NULL,NULL,&timeout);
read(inotfd,&pBuf, BUF_SIZE);
// ...
}
I want to create a file and map it into memory. I think that my code will work but when I run it I'm getting a "bus error". I searched google but I'm not sure how to fix the problem. Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
int main(void)
{
int file_fd,page_size;
char buffer[10]="perfect";
char *map;
file_fd=open("/tmp/test.txt",O_RDWR | O_CREAT | O_TRUNC ,(mode_t)0600);
if(file_fd == -1)
{
perror("open");
return 2;
}
page_size = getpagesize();
map = mmap(0,page_size,PROT_READ | PROT_WRITE,MAP_SHARED,file_fd,page_size);
if(map == MAP_FAILED)
{
perror("mmap");
return 3;
}
strcpy(map, buffer);
munmap(map, page_size);
close(file_fd);
return 0;
}
You are creating a new zero sized file, you can't extend the file size with mmap. You'll get a bus error when you try to write outside the content of the file.
Use e.g. fallocate() on the file descriptor to allocate room in the file.
Note that you're also passing the page_size as the offset to mmap, which doesn't seem to make much sense in your example, you'll have to first extend the file to pagesize + strlen(buffer) + 1 if you want to write buf at that location. More likely you want to start at the beginning of the file, so pass 0 as the last argument to mmap.