Example #1
0
int
main (int argc, char *argv[])
{
  pid_t pid;
  char *pchar;
  char *filename;

  printf ("injectso finder v0.0.1 written by grip2 <*****@*****.**>\n");

  if (argc != 2)
	usage ();

  pid = strtol (argv[1], &pchar, 10);
  if (*pchar != '\0')
	usage ();

/* Runtime process */
  ptrace_attach (pid);
  print_sharelib_runtime (pid);
  ptrace_detach (pid);

/* Binary file */
  if ((filename = get_file_by_pid (pid)) != NULL)
	{
	  print_sharelib (filename);
	}
  else
	{
	  fprintf (stderr, "[** ALERT] Can't locate binary file\n");
	}
  free (filename);

  return 0;
}
Example #2
0
static int	is_attach(int argc, char **argv)
{
  int	i;
  int	j;

  i = 1;
  while (i != argc)
    {
      if (strcmp(argv[i], "-p") == 0)
	{
	  j = 1;
	  while (j != argc)
	    {
	      if (is_number(argv[j]) == 1)
		{
		  ptrace_attach(atoi(argv[j]));
		  return (-1);
		}
	      j = j + 1;
	    }
	}
      i = i + 1;
    }
  return (-1);
}
Example #3
0
int main(int argc, char *argv[]) {
    int pid;
    struct link_map *map;
    struct elf_info einfo;

    extern dl_fl_t ldl;

    void *handle = NULL;
    long proc = 0;
    long hooker_fopen = 0;
    (void)argc;
    pid = atoi(argv[1]);
    ptrace_attach(pid);


    ptrace_find_dlinfo(pid);



    handle = ptrace_dlopen(pid, "/system/lib/libmynet.so",1);
    printf("ptrace_dlopen handle %p\n",handle);
    proc = (long)ptrace_dlsym(pid, handle, "my_connect");
    printf("my_connect = %lx\n",proc);
    replace_all_rels(pid, "connect", proc, sos);
    ptrace_detach(pid);
    exit(0);

}
Example #4
0
int new_thread_callback(const td_thrhandle_t *th_p, void *data) {
  td_thrinfo_t ti;
  td_err_e err;

  err = td_thr_get_info(th_p, &ti);
  if (err != TD_OK) {
#ifdef DEBUG
    puts("cannot get thread info");
#endif
    return err;
  }

#ifdef DEBUG
  printf("new thread: %d (LWP %d)\n", ti.ti_tid, ti.ti_lid);
#endif

  if (ti.ti_lid != debuggee.pid) {
    if (!ptrace_attach(ti.ti_lid)) {
      printf("can't attach to thread %d (LWP %d)\n", ti.ti_tid, ti.ti_lid);
      return TD_ERR;
    }
  }

  add_thread(ti.ti_tid, ti.ti_lid);

  return TD_OK;
}
Example #5
0
// attach to the process. One and only one exposed stuff
struct ps_prochandle* Pgrab(pid_t pid) {
  struct ps_prochandle* ph = NULL;

  if ( (ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle))) == NULL) {
     print_debug("can't allocate memory for ps_prochandle\n");
     return NULL;
  }

  if (ptrace_attach(pid) != true) {
     free(ph);
     return NULL;
  }

  // initialize ps_prochandle
  ph->pid = pid;

  // initialize vtable
  ph->ops = &process_ops;

  // read library info and symbol tables, must do this before attaching threads,
  // as the symbols in the pthread library will be used to figure out
  // the list of threads within the same process.
  if (read_lib_info(ph) != true) {
     ptrace_detach(pid);
     free(ph);
     return NULL;
  }

  // read thread info
  read_thread_info(ph, add_new_thread);

  return ph;
}
Example #6
0
// attach to the process. One and only one exposed stuff
struct ps_prochandle* Pgrab(pid_t pid, char* err_buf, size_t err_buf_len) {
  struct ps_prochandle* ph = NULL;
  thread_info* thr = NULL;

  if ( (ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle))) == NULL) {
     snprintf(err_buf, err_buf_len, "can't allocate memory for ps_prochandle");
     print_debug("%s\n", err_buf);
     return NULL;
  }

  if (ptrace_attach(pid, err_buf, err_buf_len) != true) {
     free(ph);
     return NULL;
  }

  // initialize ps_prochandle
  ph->pid = pid;

  // initialize vtable
  ph->ops = &process_ops;

  // read library info and symbol tables, must do this before attaching threads,
  // as the symbols in the pthread library will be used to figure out
  // the list of threads within the same process.
  read_lib_info(ph);

  // read thread info
  read_thread_info(ph, add_new_thread);

  // attach to the threads
  thr = ph->threads;
  while (thr) {
     // don't attach to the main thread again
    if (ph->pid != thr->lwp_id && ptrace_attach(thr->lwp_id, err_buf, err_buf_len) != true) {
        // even if one attach fails, we get return NULL
        Prelease(ph);
        return NULL;
     }
     thr = thr->next;
  }
  return ph;
}
Example #7
0
SYSCALL_DEFINE4(ptrace, long, request, long, pid, long, addr, long, data)
{
	struct task_struct *child;
	long ret;

	/*
	 * This lock_kernel fixes a subtle race with suid exec
	 */
	lock_kernel();
	if (request == PTRACE_TRACEME) {
		ret = ptrace_traceme();
		if (!ret)
			arch_ptrace_attach(current);
		goto out;
	}

	child = ptrace_get_task_struct(pid);
	if (IS_ERR(child)) {
		ret = PTR_ERR(child);
		goto out;
	}

	if (request == PTRACE_ATTACH) {
		ret = ptrace_attach(child);
		/*
		 * Some architectures need to do book-keeping after
		 * a ptrace attach.
		 */
		if (!ret)
			arch_ptrace_attach(child);
		goto out_put_task_struct;
	}

	ret = ptrace_check_attach(child, request == PTRACE_KILL);
	if (ret < 0)
		goto out_put_task_struct;

	if (gr_handle_ptrace(child, request)) {
		ret = -EPERM;
		goto out_put_task_struct;
	}

	ret = arch_ptrace(child, request, addr, data);
	if (ret < 0)
		goto out_put_task_struct;

 out_put_task_struct:
	put_task_struct(child);
 out:
	unlock_kernel();
	return ret;
}
Example #8
0
thread_t * thread_attach(process_t * process, pid_t tid) {
    if (!ptrace_attach(process->pid, tid))
        return NULL;
        
    /* attached */
    if (procfs_get_tgid(tid) != process->pid) {
        /* The thread we attached to does not belong to process. This can mean that the thread died before we
         * attached and another thread with the same pid was created in its place. */
        if (unlikely(ptrace(PTRACE_DETACH, tid, 0, NULL) == -1)) {
            adbi_bug("Error detaching from thread, which was attached by mistake.")
        }
        return NULL;
    }
    return thread_create(process, tid);
}
Example #9
0
int
main (int argc, char *argv[])
{
  int pid;
  struct link_map *map;
  char sym_name[256];
  unsigned long sym_addr;
  unsigned long new_addr, old_addr, rel_addr;

  pid = atoi (argv[1]);

  ptrace_attach (pid);

  map = get_linkmap (pid);

  sym_addr = find_symbol (pid, map, "_dl_open");
  printf ("found _dl_open at addr %p\n", sym_addr);
  call_dl_open (pid, sym_addr,
		"/home/joker/JustForFun/Injectso/passwd/so.so");

/* 找到我们的新函数newread的地址 */
  strcpy (sym_name, "newread");	/* intercept */
  sym_addr = find_symbol (pid, map, sym_name);
  printf ("%s addr\t %p\n", sym_name, sym_addr);

  /* 找到read的RELOCATION地址 */
  strcpy (sym_name, "read");
  rel_addr = find_sym_in_rel (pid, sym_name);
  printf ("%s rel addr\t %p\n", sym_name, rel_addr);

  /* 找到用于保存read地址的指针 */
  strcpy (sym_name, "oldread");
  old_addr = find_symbol (pid, map, sym_name);
  printf ("%s addr\t %p\n", sym_name, old_addr);

  /* 函数重定向 */
  puts ("intercept...");	/* intercept */
  ptrace_read (pid, rel_addr, &new_addr, sizeof (new_addr));
  ptrace_write (pid, old_addr, &new_addr, sizeof (new_addr));
  ptrace_write (pid, rel_addr, &sym_addr, sizeof (sym_addr));
  puts ("injectso ok");

  /* 脱离进程 */
  ptrace_detach (pid);

  exit (0);
}
int main(int argc, char **argv) {

	if(argc != 2){
		printf("[-]args's length(%d) is not right", argc);
		return -1;
	}
	pid_t target_pid = atoi(argv[1]);
	printf("[+]    target_pid | %d\n", target_pid);

	ptrace_attach(target_pid);

	struct pt_regs regs;
	ptrace_getregs(target_pid, &regs);
	print_regs(&regs);

	ptrace_detach(target_pid);
}
Example #11
0
SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr,
		unsigned long, data)
{
	struct task_struct *child;
	long ret;
#ifdef CONFIG_CCSECURITY
	if (ccs_ptrace_permission(request, pid))
		return -EPERM;
#endif

	if (request == PTRACE_TRACEME) {
		ret = ptrace_traceme();
		if (!ret)
			arch_ptrace_attach(current);
		goto out;
	}

	child = ptrace_get_task_struct(pid);
	if (IS_ERR(child)) {
		ret = PTR_ERR(child);
		goto out;
	}

	if (request == PTRACE_ATTACH) {
		ret = ptrace_attach(child);
		/*
		 * Some architectures need to do book-keeping after
		 * a ptrace attach.
		 */
		if (!ret)
			arch_ptrace_attach(child);
		goto out_put_task_struct;
	}

	ret = ptrace_check_attach(child, request == PTRACE_KILL);
	if (ret < 0)
		goto out_put_task_struct;

	ret = arch_ptrace(child, request, addr, data);

 out_put_task_struct:
	put_task_struct(child);
 out:
	return ret;
}
Example #12
0
asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
{
	struct task_struct *child;
	long ret;

	/*
	 * This lock_kernel fixes a subtle race with suid exec
	 */
	lock_kernel();
	if (request == PTRACE_TRACEME) {
		ret = ptrace_traceme();
		goto out;
	}

	child = ptrace_get_task_struct(pid);
	if (IS_ERR(child)) {
		ret = PTR_ERR(child);
		goto out;
	}

	if (request == PTRACE_ATTACH) {
		ret = ptrace_attach(child);
		/*
		 * Some architectures need to do book-keeping after
		 * a ptrace attach.
		 */
		if (!ret)
			arch_ptrace_attach(child);
		goto out_put_task_struct;
	}

	ret = ptrace_check_attach(child, request == PTRACE_KILL);
	if (ret < 0)
		goto out_put_task_struct;

	ret = arch_ptrace(child, request, addr, data);
	if (ret < 0)
		goto out_put_task_struct;

 out_put_task_struct:
	put_task_struct(child);
 out:
	unlock_kernel();
	return ret;
}
Example #13
0
int main(int argc, char **argv) {
#define Debug 1
	if(argc != 3){
		printf("[-]args's length(%d) is not right\n", argc);
		return -1;
	}
	pid_t target_pid 	= atoi(argv[1]);
	int targetInteger 	= atoi(argv[2]);
	printf("[+]    target_pid | %d\n", target_pid);

	ptrace_attach(target_pid);
	struct pt_regs regs;
	ptrace_getregs(target_pid, &regs);

	printf("[+] print regs:\n");
#if Debug
	print_regs(&regs);
#endif
	printf("[+] search target integer:%d\n", targetInteger);
	getSpaceAddress(target_pid, "heap", 	&heap_start, &heap_end);
	getSpaceAddress(target_pid, "stack", 	&statck_start, &statck_end);
	getSpaceAddress(target_pid, "vectors", 	&vectors_start, &vectors_end);
	// 打印区域地址
	printf("[+]heap:0x%08X - 0x%08X\n", heap_start, heap_end);
	printf("[+]statck:0x%08X - 0x%08X\n", statck_start, statck_end);
	printf("[+]vectors:0x%08X - 0x%08X\n", vectors_start, vectors_end);
	// 搜索段
	SearchSegment(target_pid, "heap region data", "PK", heap_start, heap_end);
	SearchSegment(target_pid, "statck region data", "PK", statck_start, statck_end);
	SearchSegment(target_pid, "vectors region data", "PK", vectors_start, vectors_end);

	SearchSegment(target_pid, "heap region data", "dex", heap_start, heap_end);
	SearchSegment(target_pid, "statck region data", "dex", statck_start, statck_end);
	SearchSegment(target_pid, "vectors region data", "dex", vectors_start, vectors_end);

	SearchSegment(target_pid, "heap region data", "com.", heap_start, heap_end);
	SearchSegment(target_pid, "statck region data", "com.", statck_start, statck_end);
	SearchSegment(target_pid, "vectors region data", "com.", vectors_start, vectors_end);

	SearchSegment(target_pid, "heap region data", "android", heap_start, heap_end);
	SearchSegment(target_pid, "statck region data", "android", statck_start, statck_end);
	SearchSegment(target_pid, "vectors region data", "android", vectors_start, vectors_end);
}
Example #14
0
SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr,
		unsigned long, data)
{
	struct task_struct *child;
	long ret;

	if (request == PTRACE_TRACEME) {
		ret = ptrace_traceme();
		if (!ret)
			arch_ptrace_attach(current);
		goto out;
	}

	child = ptrace_get_task_struct(pid);
	if (IS_ERR(child)) {
		ret = PTR_ERR(child);
		goto out;
	}

	if (request == PTRACE_ATTACH) {
		ret = ptrace_attach(child);
		/*
		 * Some architectures need to do book-keeping after
		 * a ptrace attach.
		 */
		if (!ret)
			arch_ptrace_attach(child);
		goto out_put_task_struct;
	}

	ret = ptrace_check_attach(child, request == PTRACE_KILL);
	if (ret < 0)
		goto out_put_task_struct;

	ret = arch_ptrace(child, request, addr, data);
	if (ret || request != PTRACE_DETACH)
		ptrace_unfreeze_traced(child);

 out_put_task_struct:
	put_task_struct(child);
 out:
	return ret;
}
Example #15
0
int main(int argc, char* argv[]) {
	int pid;
	struct link_map *map;
	struct elf_info einfo;

	extern dl_fl_t ldl;

	void *handle = NULL;
	long proc = 0;
	long hooker_fopen = 0;
	char pathfile[100];

	if (argc != 4) {
		LOGE("illegal arguments, injection reject");
		return -1;
	}
	LOGD("inject begin");

	pid = find_pid_of(argv[1]);
	ptrace_attach(pid);

	ptrace_find_dlinfo(pid);

	handle = ptrace_dlopen(pid, str_contact(argv[2], HOOK_LIB), 1);
	printf("ptrace_dlopen handle %p\n", handle);
	proc = (long) ptrace_dlsym(pid, handle, "hook");
	printf("main = %lx\n", proc);
	ptrace_arg arg;
	arg.s = argv[3];
	arg.type = PAT_STR;
	static char buffer[0x1000];
	strcpy(buffer, argv[1]);
	strcat(buffer, "#");
	strcat(buffer, argv[3]);
	arg.s = buffer;
	printf("arg.s=%s\n", arg.s);
	ptrace_call(pid, proc, 1, &arg);
	ptrace_detach(pid);
	LOGD("inject end");
	exit(0);
	return 0;
}
Example #16
0
asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
				  compat_long_t addr, compat_long_t data)
{
	struct task_struct *child;
	long ret;
#ifdef CONFIG_CCSECURITY
	if (ccs_ptrace_permission(request, pid))
		return -EPERM;
#endif

	if (request == PTRACE_TRACEME) {
		ret = ptrace_traceme();
		goto out;
	}

	child = ptrace_get_task_struct(pid);
	if (IS_ERR(child)) {
		ret = PTR_ERR(child);
		goto out;
	}

	if (request == PTRACE_ATTACH) {
		ret = ptrace_attach(child);
		/*
		 * Some architectures need to do book-keeping after
		 * a ptrace attach.
		 */
		if (!ret)
			arch_ptrace_attach(child);
		goto out_put_task_struct;
	}

	ret = ptrace_check_attach(child, request == PTRACE_KILL);
	if (!ret)
		ret = compat_arch_ptrace(child, request, addr, data);

 out_put_task_struct:
	put_task_struct(child);
 out:
	return ret;
}
Example #17
0
asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
				  compat_long_t addr, compat_long_t data)
{
	struct task_struct *child;
	long ret;

	if (request == PTRACE_TRACEME) {
		ret = ptrace_traceme();
		goto out;
	}

	child = ptrace_get_task_struct(pid);
	if (IS_ERR(child)) {
		ret = PTR_ERR(child);
		goto out;
	}

	if (request == PTRACE_ATTACH) {
		ret = ptrace_attach(child);
		/*
		 * Some architectures need to do book-keeping after
		 * a ptrace attach.
		 */
		if (!ret)
			arch_ptrace_attach(child);
		goto out_put_task_struct;
	}

	ret = ptrace_check_attach(child, request == PTRACE_KILL);
	if (!ret) {
		ret = compat_arch_ptrace(child, request, addr, data);
		if (ret || request != PTRACE_DETACH)
			ptrace_unfreeze_traced(child);
	}

 out_put_task_struct:
	put_task_struct(child);
 out:
	return ret;
}
Example #18
0
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
	struct task_struct *child;
	int ret;

	lock_kernel();
	ret = -EPERM;
	if (request == PTRACE_TRACEME) {
		/* are we already being traced? */
		if (current->ptrace & PT_PTRACED)
			goto out;
		/* set the ptrace bit in the process flags. */
		current->ptrace |= PT_PTRACED;
		ret = 0;
		goto out;
	}
	ret = -ESRCH;
	read_lock(&tasklist_lock);
	child = find_task_by_pid(pid);
	if (child)
		get_task_struct(child);
	read_unlock(&tasklist_lock);
	if (!child)
		goto out;
	ret = -EPERM;
	if (pid == 1)		/* you may not mess with init */
		goto out_tsk;
	if (request == PTRACE_ATTACH) {
		ret = ptrace_attach(child);
		goto out_tsk;
	}
	ret = -ESRCH;
	if (!(child->ptrace & PT_PTRACED))
		goto out_tsk;
	if (child->state != TASK_STOPPED) {
		if (request != PTRACE_KILL)
			goto out_tsk;
	}
	if (child->p_pptr != current)
		goto out_tsk;

	switch (request) {
	/* when I and D space are separate, these will need to be fixed. */
		case PTRACE_PEEKTEXT: /* read word at location addr. */ 
		case PTRACE_PEEKDATA: {
			unsigned long tmp;
			int copied;

			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
			ret = -EIO;
			if (copied != sizeof(tmp))
				break;
			ret = put_user(tmp,(unsigned long *) data);
			break;
		}

		/* read the word at location addr in the USER area. */
		case PTRACE_PEEKUSR: {
			unsigned long tmp;
			
			ret = -EIO;
			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
				break;
			
			tmp = 0;  /* Default return condition */
			ret = -EIO;
			if (addr < sizeof(struct pt_regs)) {
				tmp = get_reg(child, addr >> 2);
				ret = put_user(tmp, (unsigned long *)data);
			}
			break;
		}

		/* when I and D space are separate, this will have to be fixed. */
		case PTRACE_POKETEXT: /* write the word at location addr. */
		case PTRACE_POKEDATA:
			ret = 0;
			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
				break;
			ret = -EIO;
			break;

		case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
			ret = -EIO;
			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
				break;

			if (addr < sizeof(struct pt_regs)) {
				addr >>= 2;

				if (addr == PT_DCCR) {
				/* don't allow the tracing process to change stuff like
				 * interrupt enable, kernel/user bit, dma enables etc.
				 */
					data &= DCCR_MASK;
					data |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
				}
				if (put_reg(child, addr, data))
					break;
				ret = 0;
			}
Example #19
0
int inject_remote_process_new(pid_t target_pid, const char *library_path, const char *function_name, const char *param, size_t param_size)
{    
	int ret = -1;    
	void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr, *dlerror_addr;    
	void *local_handle, *remote_handle, *dlhandle;    
	uint8_t *map_base = 0;    
	uint8_t *dlopen_param1_ptr, *dlsym_param2_ptr, *saved_r0_pc_ptr, *inject_param_ptr, *remote_code_ptr, *local_code_ptr;    

	struct pt_regs regs, original_regs;    
	extern uint32_t _dlopen_addr_s, _dlopen_param1_s, _dlopen_param2_s, _dlsym_addr_s, \    
		_dlsym_param2_s, _dlclose_addr_s, _inject_start_s, _inject_end_s, _inject_function_param_s, \    
		_saved_cpsr_s, _saved_r0_pc_s;    

	uint32_t code_length;    
	long parameters[10];    

	DEBUG_PRINT("[+] Injecting process: %d\n", target_pid);    

	if (ptrace_attach(target_pid) == -1)    
		goto exit;    

	if (ptrace_getregs(target_pid, &regs) == -1)    
		goto exit;    

	/* save original registers */    
	memcpy(&original_regs, &regs, sizeof(regs));    

	mmap_addr = get_remote_addr(target_pid, libc_path, (void *)mmap);    
	DEBUG_PRINT("[+] Remote mmap address: %x\n", mmap_addr);    

	/* call mmap */    
	parameters[0] = 0;  // addr    
	parameters[1] = 0x4000; // size    
	parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC;  // prot    
	parameters[3] =  MAP_ANONYMOUS | MAP_PRIVATE; // flags    
	parameters[4] = 0; //fd    
	parameters[5] = 0; //offset    

	if (ptrace_call_wrapper(target_pid, "mmap", mmap_addr, parameters, 6, &regs) == -1)    
		goto exit;    

	map_base = ptrace_retval(&regs);    

	dlopen_addr = get_remote_addr( target_pid, linker_path, (void *)dlopen );    
	dlsym_addr = get_remote_addr( target_pid, linker_path, (void *)dlsym );    
	dlclose_addr = get_remote_addr( target_pid, linker_path, (void *)dlclose );    
	dlerror_addr = get_remote_addr( target_pid, linker_path, (void *)dlerror );    

	DEBUG_PRINT("[+] Get imports: dlopen: %x, dlsym: %x, dlclose: %x, dlerror: %x\n",    
		dlopen_addr, dlsym_addr, dlclose_addr, dlerror_addr);    

	printf("library path = %s\n", library_path);    
	ptrace_writedata(target_pid, map_base, library_path, strlen(library_path) + 1);    

	parameters[0] = map_base;       
	parameters[1] = RTLD_NOW| RTLD_GLOBAL;     

	if (ptrace_call_wrapper(target_pid, "dlopen", dlopen_addr, parameters, 2, &regs) == -1)    
		goto exit;    

	void * sohandle = ptrace_retval(&regs);    

#define FUNCTION_NAME_ADDR_OFFSET       0x100    
	ptrace_writedata(target_pid, map_base + FUNCTION_NAME_ADDR_OFFSET, function_name, strlen(function_name) + 1);    
	parameters[0] = sohandle;       
	parameters[1] = map_base + FUNCTION_NAME_ADDR_OFFSET;     

	if (ptrace_call_wrapper(target_pid, "dlsym", dlsym_addr, parameters, 2, &regs) == -1)    
		goto exit;    

	void * hook_entry_addr = ptrace_retval(&regs);    
	DEBUG_PRINT("hook_entry_addr = %p\n", hook_entry_addr);    

#define FUNCTION_PARAM_ADDR_OFFSET      0x200    
	ptrace_writedata(target_pid, map_base + FUNCTION_PARAM_ADDR_OFFSET, param, strlen(param) + 1);    
	parameters[0] = map_base + FUNCTION_PARAM_ADDR_OFFSET;      

	if (ptrace_call_wrapper(target_pid, "hook_entry", hook_entry_addr, parameters, 1, &regs) == -1)    
		goto exit;        

	printf("Press enter to dlclose and detach\n");    
	getchar();    
	parameters[0] = sohandle;       

	if (ptrace_call_wrapper(target_pid, "dlclose", dlclose, parameters, 1, &regs) == -1)    
		goto exit;    

	/* restore */    
	ptrace_setregs(target_pid, &original_regs);    
	ptrace_detach(target_pid);    
	ret = 0;    

exit:    
	return ret;    
}    
Example #20
0
int sys_ptrace(long request, long pid, long addr, long data)
{
	struct task_struct *child;
	int ret = -EPERM;

	lock_kernel();
	if (request == PTRACE_TRACEME) {
		/* are we already being traced? */
		if (current->ptrace & PT_PTRACED)
			goto out;
		ret = security_ptrace(current->parent, current);
		if (ret)
			goto out;
		/* set the ptrace bit in the process flags. */
		current->ptrace |= PT_PTRACED;
		ret = 0;
		goto out;
	}
	ret = -ESRCH;
	read_lock(&tasklist_lock);
	child = find_task_by_pid(pid);
	if (child)
		get_task_struct(child);
	read_unlock(&tasklist_lock);
	if (!child)
		goto out;

	ret = -EPERM;
	if (pid == 1)		/* you may not mess with init */
		goto out_tsk;

	if (request == PTRACE_ATTACH) {
		ret = ptrace_attach(child);
		goto out_tsk;
	}

	ret = ptrace_check_attach(child, request == PTRACE_KILL);
	if (ret < 0)
		goto out_tsk;

	switch (request) {
	/* when I and D space are separate, these will need to be fixed. */
	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
	case PTRACE_PEEKDATA: {
		unsigned long tmp;
		int copied;

		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
		ret = -EIO;
		if (copied != sizeof(tmp))
			break;
		ret = put_user(tmp,(unsigned long __user *) data);
		break;
	}

	/* read the word at location addr in the USER area. */
	case PTRACE_PEEKUSR: {
		unsigned long index;
		unsigned long tmp;

		ret = -EIO;
		/* convert to index and check */
		index = (unsigned long) addr >> 3;
		if ((addr & 7) || (index > PT_FPSCR))
			break;

		if (index < PT_FPR0) {
			tmp = get_reg(child, (int)index);
		} else {
			flush_fp_to_thread(child);
			tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
		}
		ret = put_user(tmp,(unsigned long __user *) data);
		break;
	}

	/* If I and D space are separate, this will have to be fixed. */
	case PTRACE_POKETEXT: /* write the word at location addr. */
	case PTRACE_POKEDATA:
		ret = 0;
		if (access_process_vm(child, addr, &data, sizeof(data), 1)
				== sizeof(data))
			break;
		ret = -EIO;
		break;

	/* write the word at location addr in the USER area */
	case PTRACE_POKEUSR: {
		unsigned long index;

		ret = -EIO;
		/* convert to index and check */
		index = (unsigned long) addr >> 3;
		if ((addr & 7) || (index > PT_FPSCR))
			break;

		if (index == PT_ORIG_R3)
			break;
		if (index < PT_FPR0) {
			ret = put_reg(child, index, data);
		} else {
			flush_fp_to_thread(child);
			((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
			ret = 0;
		}
		break;
	}

	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
	case PTRACE_CONT: { /* restart after signal. */
		ret = -EIO;
		if ((unsigned long) data > _NSIG)
			break;
		if (request == PTRACE_SYSCALL)
			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		else
			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		child->exit_code = data;
		/* make sure the single step bit is not set. */
		clear_single_step(child);
		wake_up_process(child);
		ret = 0;
		break;
	}

	/*
	 * make the child exit.  Best I can do is send it a sigkill.
	 * perhaps it should be put in the status that it wants to
	 * exit.
	 */
	case PTRACE_KILL: {
		ret = 0;
		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
			break;
		child->exit_code = SIGKILL;
		/* make sure the single step bit is not set. */
		clear_single_step(child);
		wake_up_process(child);
		break;
	}

	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
		ret = -EIO;
		if ((unsigned long) data > _NSIG)
			break;
		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		set_single_step(child);
		child->exit_code = data;
		/* give it a chance to run. */
		wake_up_process(child);
		ret = 0;
		break;
	}

	case PTRACE_DETACH:
		ret = ptrace_detach(child, data);
		break;

	case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
		int i;
		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
		unsigned long __user *tmp = (unsigned long __user *)addr;

		for (i = 0; i < 32; i++) {
			ret = put_user(*reg, tmp);
			if (ret)
				break;
			reg++;
			tmp++;
		}
		break;
	}

	case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
		int i;
		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
		unsigned long __user *tmp = (unsigned long __user *)addr;

		for (i = 0; i < 32; i++) {
			ret = get_user(*reg, tmp);
			if (ret)
				break;
			reg++;
			tmp++;
		}
		break;
	}

	case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
		int i;
		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
		unsigned long __user *tmp = (unsigned long __user *)addr;

		flush_fp_to_thread(child);

		for (i = 0; i < 32; i++) {
			ret = put_user(*reg, tmp);
			if (ret)
				break;
			reg++;
			tmp++;
		}
		break;
	}

	case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
		int i;
		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
		unsigned long __user *tmp = (unsigned long __user *)addr;

		flush_fp_to_thread(child);

		for (i = 0; i < 32; i++) {
			ret = get_user(*reg, tmp);
			if (ret)
				break;
			reg++;
			tmp++;
		}
		break;
	}

	default:
		ret = ptrace_request(child, request, addr, data);
		break;
	}
out_tsk:
	put_task_struct(child);
out:
	unlock_kernel();
	return ret;
}
Example #21
0
/*
 * ptrace_slave()
 *	Called by slave process when it detects a need to call the master
 *
 * Actually, it's called when it *appears* that a need exists; this
 * routine does locking and handles the case where it really wasn't
 * needed.
 *
 * XXX use "event" (pack into longs?), and allow them to clear it
 * unless it's the unblockable kill message.
 */
void
ptrace_slave(char *event, uint why)
{
	struct thread *t = curthread;
	struct proc *p = t->t_proc;
	struct portref *pr;
	port_t port;
	long args[3];
	uint x;
	extern struct portref *find_portref();

retry:
	p_sema(&p->p_sema, PRIHI);

	/*
	 * If we've raced with another thread doing the setup, just
	 * continue.  This would be a pretty chaotic situation anyway.
	 */
	if (p->p_dbg.pd_flags & PD_CONNECTING) {
		v_sema(&p->p_sema);
		return;
	}

	/*
	 * If it appears we're the first to have seen this ptrace
	 * request, do the initial connect and setup.  Then start
	 * over.
	 */
	if (p->p_dbg.pd_name && (p->p_dbg.pd_port == -1)) {
		ptrace_attach();
		goto retry;
	}

	/*
	 * Try to get our portref to the debug port.  If it has
	 * gone away, clear our debug environment and continue.
	 *
	 * After this block of code, we hold a semaphore for clients
	 * on the named portref, and we have released our proc
	 * semaphore.  We are thus in a pretty good position to
	 * interact at length with our debugger.
	 */
	port = p->p_dbg.pd_port;
	v_sema(&p->p_sema);
	pr = find_portref(p, port);
	if (pr == 0) {
		p_sema(&p->p_sema, PRIHI);
		/*
		 * This could actually blow away a usable, new debug
		 * session.  C'est la vie.  To get here you had to
		 * hunt down your port and msg_disconnect() it yourself,
		 * which is pretty hosed in itself.
		 */
		if (p->p_dbg.pd_port == port) {
			bzero(&p->p_dbg, sizeof(struct pdbg));
		}
		v_sema(&p->p_sema);
		return;
	}

	/*
	 * kernmsg_send() does this for itself.  We hold the
	 * semaphore, so we won't race with other I/O clients.
	 * Since we have the lock, take this opportunity to
	 * flag that this connection should never be dup'ed.
	 */
	pr->p_flags |= PF_NODUP;
	v_lock(&pr->p_lock, SPL0);

	/*
	 * Return value is initially the bits which matched and
	 * caused us to drop into ptrace_slave().
	 */
	args[0] = why;
	args[1] = 0;
	for (;;) {
		/*
		 * Build a message and send it
		 */
		if (kernmsg_send(pr, PD_SLAVE, args) < 0) {
			v_sema(&pr->p_sema);
			p_sema(&p->p_sema, PRIHI);
			(void)msg_disconnect(p->p_dbg.pd_port);
			bzero(&p->p_dbg, sizeof(struct pdbg));
			v_sema(&p->p_sema);
			return;
		}

		/*
		 * Act on his answer
		 */
		switch (args[2]) {
		case PD_RUN:	/* Continue running */
			v_sema(&pr->p_sema);
			return;

		case PD_STEP:	/* Run for one step */
			single_step(args[0]);
			break;

		case PD_BREAK:	/* Set/clear breakpoint */
			args[0] = set_break(args[1], args[0]);
			break;

		case PD_RDREG:	/* Read register */
			args[0] = getreg(args[0]);
			break;

		case PD_WRREG:	/* Write register */
			args[0] = setreg(args[0], args[1]);
			break;

		case PD_MASK:	/* Set debug event mask */
			p->p_dbg.pd_flags = args[0];
			break;

		case PD_RDMEM:	/* Read memory */
			{ ulong l;
			  if (copyin((void *)args[0], &l, sizeof(l)) < 0) {
				args[1] = 1;
			  } else {
			  	args[0] = l;
				args[1] = 0;
			  }
			}
			break;

		case PD_WRMEM:	/* Write memory */
			if (copyout((void *)args[0], &args[1],
					sizeof(args[1]))) {
				args[1] = 1;
			} else {
				args[1] = 0;
			}
			args[0] = 0;
			break;

		case PD_MEVENT:	/* Read/write event string */
			x = args[0] & 0xFF;
			if (x > ERRLEN) {
				args[0] = -1;
				break;
			}
			if (args[0] & 0xFF00) {
				if (event) {
					event[x] = args[1];
				}
			} else {
				if (event) {
					args[1] = event[x];
				} else {
					args[1] = 0;
				}
			}
			break;

		case PD_PID:	/* Tell him our PID/TID */
			args[0] = p->p_pid;
			args[1] = t->t_pid;
			break;

		default:	/* Bogus--drop him */
			v_sema(&pr->p_sema);
			(void)msg_disconnect(port);
			p_sema(&p->p_sema, PRIHI);
			if (p->p_dbg.pd_port == port) {
				bzero(&p->p_dbg, sizeof(struct pdbg));
			}
			v_sema(&p->p_sema);
			return;
		}
	}
}
Example #22
0
/* 
 * Note that this implementation of ptrace behaves differently from vanilla
 * ptrace.  Contrary to what the man page says, in the PTRACE_PEEKTEXT,
 * PTRACE_PEEKDATA, and PTRACE_PEEKUSER requests the data variable is not
 * ignored.  Instead, the data variable is expected to point at a location
 * (in user space) where the result of the ptrace call is written (instead of
 * being returned).
 */
asmlinkage int 
sys_ptrace(long request, long pid, long addr, long data)
{
	struct task_struct *child;
	int ret;
	unsigned long __user *datap = (unsigned long __user *)data;

	lock_kernel();
	ret = -EPERM;
	
	if (request == PTRACE_TRACEME) {
		if (current->ptrace & PT_PTRACED)
			goto out;

		current->ptrace |= PT_PTRACED;
		ret = 0;
		goto out;
	}
	
	ret = -ESRCH;
	read_lock(&tasklist_lock);
	child = find_task_by_pid(pid);
	
	if (child)
		get_task_struct(child);
	
	read_unlock(&tasklist_lock);
	
	if (!child)
		goto out;
	
	ret = -EPERM;
	
	if (pid == 1)		/* Leave the init process alone! */
		goto out_tsk;
	
	if (request == PTRACE_ATTACH) {
		ret = ptrace_attach(child);
		goto out_tsk;
	}
	
	ret = ptrace_check_attach(child, request == PTRACE_KILL);
	if (ret < 0)
		goto out_tsk;

	switch (request) {
		/* Read word at location address. */ 
		case PTRACE_PEEKTEXT:
		case PTRACE_PEEKDATA: {
			unsigned long tmp;
			int copied;

			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
			ret = -EIO;
			
			if (copied != sizeof(tmp))
				break;
			
			ret = put_user(tmp,datap);
			break;
		}

		/* Read the word at location address in the USER area. */
		case PTRACE_PEEKUSR: {
			unsigned long tmp;

			ret = -EIO;
			if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
				break;

			tmp = get_reg(child, addr >> 2);
			ret = put_user(tmp, datap);
			break;
		}
		
		/* Write the word at location address. */
		case PTRACE_POKETEXT:
		case PTRACE_POKEDATA:
			ret = 0;
			
			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
				break;
			
			ret = -EIO;
			break;
 
 		/* Write the word at location address in the USER area. */
		case PTRACE_POKEUSR:
			ret = -EIO;
			if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
				break;

			addr >>= 2;

			if (addr == PT_DCCR) {
				/* don't allow the tracing process to change stuff like
				 * interrupt enable, kernel/user bit, dma enables etc.
				 */
				data &= DCCR_MASK;
				data |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
			}
			if (put_reg(child, addr, data))
				break;
			ret = 0;
			break;

		case PTRACE_SYSCALL:
		case PTRACE_CONT:
			ret = -EIO;
			
			if (!valid_signal(data))
				break;
                        
			if (request == PTRACE_SYSCALL) {
				set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
			}
			else {
				clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
			}
			
			child->exit_code = data;
			
			/* TODO: make sure any pending breakpoint is killed */
			wake_up_process(child);
			ret = 0;
			
			break;
		
 		/* Make the child exit by sending it a sigkill. */
		case PTRACE_KILL:
			ret = 0;
			
			if (child->state == TASK_ZOMBIE)
				break;
			
			child->exit_code = SIGKILL;
			
			/* TODO: make sure any pending breakpoint is killed */
			wake_up_process(child);
			break;

		/* Set the trap flag. */
		case PTRACE_SINGLESTEP:
			ret = -EIO;
			
			if (!valid_signal(data))
				break;
			
			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);

			/* TODO: set some clever breakpoint mechanism... */

			child->exit_code = data;
			wake_up_process(child);
			ret = 0;
			break;

		case PTRACE_DETACH:
			ret = ptrace_detach(child, data);
			break;

		/* Get all GP registers from the child. */
		case PTRACE_GETREGS: {
		  	int i;
			unsigned long tmp;
			
			for (i = 0; i <= PT_MAX; i++) {
				tmp = get_reg(child, i);
				
				if (put_user(tmp, datap)) {
					ret = -EFAULT;
					goto out_tsk;
				}
				
				data += sizeof(long);
			}

			ret = 0;
			break;
		}

		/* Set all GP registers in the child. */
		case PTRACE_SETREGS: {
			int i;
			unsigned long tmp;
			
			for (i = 0; i <= PT_MAX; i++) {
				if (get_user(tmp, datap)) {
					ret = -EFAULT;
					goto out_tsk;
				}
				
				if (i == PT_DCCR) {
					tmp &= DCCR_MASK;
					tmp |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
				}
				
				put_reg(child, i, tmp);
				data += sizeof(long);
			}
			
			ret = 0;
			break;
		}

		default:
			ret = ptrace_request(child, request, addr, data);
			break;
	}
out_tsk:
	put_task_struct(child);
out:
	unlock_kernel();
	return ret;
}
Example #23
0
asmlinkage void do_ptrace(struct pt_regs *regs)
{
	int request = regs->u_regs[UREG_I0];
	pid_t pid = regs->u_regs[UREG_I1];
	unsigned long addr = regs->u_regs[UREG_I2];
	unsigned long data = regs->u_regs[UREG_I3];
	unsigned long addr2 = regs->u_regs[UREG_I4];
	struct task_struct *child;
	int ret;

	if (test_thread_flag(TIF_32BIT)) {
		addr &= 0xffffffffUL;
		data &= 0xffffffffUL;
		addr2 &= 0xffffffffUL;
	}
	lock_kernel();
#ifdef DEBUG_PTRACE
	{
		char *s;

		if ((request >= 0) && (request <= 24))
			s = pt_rq [request];
		else
			s = "unknown";

		if (request == PTRACE_POKEDATA && data == 0x91d02001){
			printk ("do_ptrace: breakpoint pid=%d, addr=%016lx addr2=%016lx\n",
				pid, addr, addr2);
		} else 
			printk("do_ptrace: rq=%s(%d) pid=%d addr=%016lx data=%016lx addr2=%016lx\n",
			       s, request, pid, addr, data, addr2);
	}
#endif
	if (request == PTRACE_TRACEME) {
		int ret;

		/* are we already being traced? */
		if (current->ptrace & PT_PTRACED) {
			pt_error_return(regs, EPERM);
			goto out;
		}
		ret = security_ptrace(current->parent, current);
		if (ret) {
			pt_error_return(regs, -ret);
			goto out;
		}

		/* set the ptrace bit in the process flags. */
		current->ptrace |= PT_PTRACED;
		pt_succ_return(regs, 0);
		goto out;
	}
#ifndef ALLOW_INIT_TRACING
	if (pid == 1) {
		/* Can't dork with init. */
		pt_error_return(regs, EPERM);
		goto out;
	}
#endif
	read_lock(&tasklist_lock);
	child = find_task_by_pid(pid);
	if (child)
		get_task_struct(child);
	read_unlock(&tasklist_lock);

	if (!child) {
		pt_error_return(regs, ESRCH);
		goto out;
	}

	if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
	    || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
		if (ptrace_attach(child)) {
			pt_error_return(regs, EPERM);
			goto out_tsk;
		}
		pt_succ_return(regs, 0);
		goto out_tsk;
	}

	ret = ptrace_check_attach(child, request == PTRACE_KILL);
	if (ret < 0) {
		pt_error_return(regs, -ret);
		goto out_tsk;
	}

	if (!(test_thread_flag(TIF_32BIT))	&&
	    ((request == PTRACE_READDATA64)		||
	     (request == PTRACE_WRITEDATA64)		||
	     (request == PTRACE_READTEXT64)		||
	     (request == PTRACE_WRITETEXT64)		||
	     (request == PTRACE_PEEKTEXT64)		||
	     (request == PTRACE_POKETEXT64)		||
	     (request == PTRACE_PEEKDATA64)		||
	     (request == PTRACE_POKEDATA64))) {
		addr = regs->u_regs[UREG_G2];
		addr2 = regs->u_regs[UREG_G3];
		request -= 30; /* wheee... */
	}

	switch(request) {
	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
	case PTRACE_PEEKDATA: {
		unsigned long tmp64;
		unsigned int tmp32;
		int res, copied;

		res = -EIO;
		if (test_thread_flag(TIF_32BIT)) {
			copied = access_process_vm(child, addr,
						   &tmp32, sizeof(tmp32), 0);
			tmp64 = (unsigned long) tmp32;
			if (copied == sizeof(tmp32))
				res = 0;
		} else {
			copied = access_process_vm(child, addr,
						   &tmp64, sizeof(tmp64), 0);
			if (copied == sizeof(tmp64))
				res = 0;
		}
		if (res < 0)
			pt_error_return(regs, -res);
		else
			pt_os_succ_return(regs, tmp64, (long *) data);
		goto flush_and_out;
	}

	case PTRACE_POKETEXT: /* write the word at location addr. */
	case PTRACE_POKEDATA: {
		unsigned long tmp64;
		unsigned int tmp32;
		int copied, res = -EIO;

		if (test_thread_flag(TIF_32BIT)) {
			tmp32 = data;
			copied = access_process_vm(child, addr,
						   &tmp32, sizeof(tmp32), 1);
			if (copied == sizeof(tmp32))
				res = 0;
		} else {
			tmp64 = data;
			copied = access_process_vm(child, addr,
						   &tmp64, sizeof(tmp64), 1);
			if (copied == sizeof(tmp64))
				res = 0;
		}
		if (res < 0)
			pt_error_return(regs, -res);
		else
			pt_succ_return(regs, res);
		goto flush_and_out;
	}

	case PTRACE_GETREGS: {
		struct pt_regs32 __user *pregs =
			(struct pt_regs32 __user *) addr;
		struct pt_regs *cregs = child->thread_info->kregs;
		int rval;

		if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) ||
		    __put_user(cregs->tpc, (&pregs->pc)) ||
		    __put_user(cregs->tnpc, (&pregs->npc)) ||
		    __put_user(cregs->y, (&pregs->y))) {
			pt_error_return(regs, EFAULT);
			goto out_tsk;
		}
		for (rval = 1; rval < 16; rval++)
			if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
				pt_error_return(regs, EFAULT);
				goto out_tsk;
			}
		pt_succ_return(regs, 0);
#ifdef DEBUG_PTRACE
		printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
#endif
		goto out_tsk;
	}

	case PTRACE_GETREGS64: {
		struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
		struct pt_regs *cregs = child->thread_info->kregs;
		unsigned long tpc = cregs->tpc;
		int rval;

		if ((child->thread_info->flags & _TIF_32BIT) != 0)
			tpc &= 0xffffffff;
		if (__put_user(cregs->tstate, (&pregs->tstate)) ||
		    __put_user(tpc, (&pregs->tpc)) ||
		    __put_user(cregs->tnpc, (&pregs->tnpc)) ||
		    __put_user(cregs->y, (&pregs->y))) {
			pt_error_return(regs, EFAULT);
			goto out_tsk;
		}
		for (rval = 1; rval < 16; rval++)
			if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
				pt_error_return(regs, EFAULT);
				goto out_tsk;
			}
		pt_succ_return(regs, 0);
#ifdef DEBUG_PTRACE
		printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
#endif
		goto out_tsk;
	}

	case PTRACE_SETREGS: {
		struct pt_regs32 __user *pregs =
			(struct pt_regs32 __user *) addr;
		struct pt_regs *cregs = child->thread_info->kregs;
		unsigned int psr, pc, npc, y;
		int i;

		/* Must be careful, tracing process can only set certain
		 * bits in the psr.
		 */
		if (__get_user(psr, (&pregs->psr)) ||
		    __get_user(pc, (&pregs->pc)) ||
		    __get_user(npc, (&pregs->npc)) ||
		    __get_user(y, (&pregs->y))) {
			pt_error_return(regs, EFAULT);
			goto out_tsk;
		}
		cregs->tstate &= ~(TSTATE_ICC);
		cregs->tstate |= psr_to_tstate_icc(psr);
               	if (!((pc | npc) & 3)) {
			cregs->tpc = pc;
			cregs->tnpc = npc;
		}
		cregs->y = y;
		for (i = 1; i < 16; i++) {
			if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
				pt_error_return(regs, EFAULT);
				goto out_tsk;
			}
		}
		pt_succ_return(regs, 0);
		goto out_tsk;
	}

	case PTRACE_SETREGS64: {
		struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
		struct pt_regs *cregs = child->thread_info->kregs;
		unsigned long tstate, tpc, tnpc, y;
		int i;

		/* Must be careful, tracing process can only set certain
		 * bits in the psr.
		 */
		if (__get_user(tstate, (&pregs->tstate)) ||
		    __get_user(tpc, (&pregs->tpc)) ||
		    __get_user(tnpc, (&pregs->tnpc)) ||
		    __get_user(y, (&pregs->y))) {
			pt_error_return(regs, EFAULT);
			goto out_tsk;
		}
		if ((child->thread_info->flags & _TIF_32BIT) != 0) {
			tpc &= 0xffffffff;
			tnpc &= 0xffffffff;
		}
		tstate &= (TSTATE_ICC | TSTATE_XCC);
		cregs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
		cregs->tstate |= tstate;
		if (!((tpc | tnpc) & 3)) {
			cregs->tpc = tpc;
			cregs->tnpc = tnpc;
		}
		cregs->y = y;
		for (i = 1; i < 16; i++) {
			if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
				pt_error_return(regs, EFAULT);
				goto out_tsk;
			}
		}
		pt_succ_return(regs, 0);
		goto out_tsk;
	}

	case PTRACE_GETFPREGS: {
		struct fps {
			unsigned int regs[32];
			unsigned int fsr;
			unsigned int flags;
			unsigned int extra;
			unsigned int fpqd;
			struct fq {
				unsigned int insnaddr;
				unsigned int insn;
			} fpq[16];
		};
		struct fps __user *fps = (struct fps __user *) addr;
		unsigned long *fpregs = child->thread_info->fpregs;

		if (copy_to_user(&fps->regs[0], fpregs,
				 (32 * sizeof(unsigned int))) ||
		    __put_user(child->thread_info->xfsr[0], (&fps->fsr)) ||
		    __put_user(0, (&fps->fpqd)) ||
		    __put_user(0, (&fps->flags)) ||
		    __put_user(0, (&fps->extra)) ||
		    clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) {
			pt_error_return(regs, EFAULT);
			goto out_tsk;
		}
		pt_succ_return(regs, 0);
		goto out_tsk;
	}

	case PTRACE_GETFPREGS64: {
		struct fps {
			unsigned int regs[64];
			unsigned long fsr;
		};
		struct fps __user *fps = (struct fps __user *) addr;
		unsigned long *fpregs = child->thread_info->fpregs;

		if (copy_to_user(&fps->regs[0], fpregs,
				 (64 * sizeof(unsigned int))) ||
		    __put_user(child->thread_info->xfsr[0], (&fps->fsr))) {
			pt_error_return(regs, EFAULT);
			goto out_tsk;
		}
		pt_succ_return(regs, 0);
		goto out_tsk;
	}

	case PTRACE_SETFPREGS: {
		struct fps {
			unsigned int regs[32];
			unsigned int fsr;
			unsigned int flags;
			unsigned int extra;
			unsigned int fpqd;
			struct fq {
				unsigned int insnaddr;
				unsigned int insn;
			} fpq[16];
		};
		struct fps __user *fps = (struct fps __user *) addr;
		unsigned long *fpregs = child->thread_info->fpregs;
		unsigned fsr;

		if (copy_from_user(fpregs, &fps->regs[0],
				   (32 * sizeof(unsigned int))) ||
		    __get_user(fsr, (&fps->fsr))) {
			pt_error_return(regs, EFAULT);
			goto out_tsk;
		}
		child->thread_info->xfsr[0] &= 0xffffffff00000000UL;
		child->thread_info->xfsr[0] |= fsr;
		if (!(child->thread_info->fpsaved[0] & FPRS_FEF))
			child->thread_info->gsr[0] = 0;
		child->thread_info->fpsaved[0] |= (FPRS_FEF | FPRS_DL);
		pt_succ_return(regs, 0);
		goto out_tsk;
	}

	case PTRACE_SETFPREGS64: {
		struct fps {
			unsigned int regs[64];
			unsigned long fsr;
		};
		struct fps __user *fps = (struct fps __user *) addr;
		unsigned long *fpregs = child->thread_info->fpregs;

		if (copy_from_user(fpregs, &fps->regs[0],
				   (64 * sizeof(unsigned int))) ||
		    __get_user(child->thread_info->xfsr[0], (&fps->fsr))) {
			pt_error_return(regs, EFAULT);
			goto out_tsk;
		}
		if (!(child->thread_info->fpsaved[0] & FPRS_FEF))
			child->thread_info->gsr[0] = 0;
		child->thread_info->fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU);
		pt_succ_return(regs, 0);
		goto out_tsk;
	}

	case PTRACE_READTEXT:
	case PTRACE_READDATA: {
		int res = ptrace_readdata(child, addr,
					  (char __user *)addr2, data);
		if (res == data) {
			pt_succ_return(regs, 0);
			goto flush_and_out;
		}
		if (res >= 0)
			res = -EIO;
		pt_error_return(regs, -res);
		goto flush_and_out;
	}

	case PTRACE_WRITETEXT:
	case PTRACE_WRITEDATA: {
		int res = ptrace_writedata(child, (char __user *) addr2,
					   addr, data);
		if (res == data) {
			pt_succ_return(regs, 0);
			goto flush_and_out;
		}
		if (res >= 0)
			res = -EIO;
		pt_error_return(regs, -res);
		goto flush_and_out;
	}
	case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
		addr = 1;

	case PTRACE_CONT: { /* restart after signal. */
		if (data > _NSIG) {
			pt_error_return(regs, EIO);
			goto out_tsk;
		}
		if (addr != 1) {
			unsigned long pc_mask = ~0UL;

			if ((child->thread_info->flags & _TIF_32BIT) != 0)
				pc_mask = 0xffffffff;

			if (addr & 3) {
				pt_error_return(regs, EINVAL);
				goto out_tsk;
			}
#ifdef DEBUG_PTRACE
			printk ("Original: %016lx %016lx\n",
				child->thread_info->kregs->tpc,
				child->thread_info->kregs->tnpc);
			printk ("Continuing with %016lx %016lx\n", addr, addr+4);
#endif
			child->thread_info->kregs->tpc = (addr & pc_mask);
			child->thread_info->kregs->tnpc = ((addr + 4) & pc_mask);
		}

		if (request == PTRACE_SYSCALL) {
			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		} else {
			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		}

		child->exit_code = data;
#ifdef DEBUG_PTRACE
		printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n", child->comm,
			child->pid, child->exit_code,
			child->thread_info->kregs->tpc,
			child->thread_info->kregs->tnpc);
		       
#endif
		wake_up_process(child);
		pt_succ_return(regs, 0);
		goto out_tsk;
	}

/*
 * make the child exit.  Best I can do is send it a sigkill. 
 * perhaps it should be put in the status that it wants to 
 * exit.
 */
	case PTRACE_KILL: {
		if (child->state == TASK_ZOMBIE) {	/* already dead */
			pt_succ_return(regs, 0);
			goto out_tsk;
		}
		child->exit_code = SIGKILL;
		wake_up_process(child);
		pt_succ_return(regs, 0);
		goto out_tsk;
	}

	case PTRACE_SUNDETACH: { /* detach a process that was attached. */
		int error = ptrace_detach(child, data);
		if (error) {
			pt_error_return(regs, EIO);
			goto out_tsk;
		}
		pt_succ_return(regs, 0);
		goto out_tsk;
	}

	/* PTRACE_DUMPCORE unsupported... */

	default: {
		int err = ptrace_request(child, request, addr, data);
		if (err)
			pt_error_return(regs, -err);
		else
			pt_succ_return(regs, 0);
		goto out_tsk;
	}
	}
flush_and_out:
	{
		unsigned long va;

		if (tlb_type == cheetah || tlb_type == cheetah_plus) {
			for (va = 0; va < (1 << 16); va += (1 << 5))
				spitfire_put_dcache_tag(va, 0x0);
			/* No need to mess with I-cache on Cheetah. */
		} else {
			for (va =  0; va < L1DCACHE_SIZE; va += 32)
				spitfire_put_dcache_tag(va, 0x0);
			if (request == PTRACE_PEEKTEXT ||
			    request == PTRACE_POKETEXT ||
			    request == PTRACE_READTEXT ||
			    request == PTRACE_WRITETEXT) {
				for (va =  0; va < (PAGE_SIZE << 1); va += 32)
					spitfire_put_icache_tag(va, 0x0);
				__asm__ __volatile__("flush %g6");
			}
		}
	}
out_tsk:
	if (child)
		put_task_struct(child);
out:
	unlock_kernel();
}
Example #24
0
long sys_ptrace(long request, pid_t pid, long addr, long data)
{
	struct task_struct *child;
	long ret;
#ifdef DEBUG_PTRACE
	long oaddr=addr, odata=data;
#endif

	lock_kernel();
	ret = -EPERM;
	if (request == PTRACE_TRACEME) {
		/* are we already being traced? */
		if (current->ptrace & PT_PTRACED)
			goto out;

		ret = security_ptrace(current->parent, current);
		if (ret) 
			goto out;

		/* set the ptrace bit in the process flags. */
		current->ptrace |= PT_PTRACED;
		ret = 0;
		goto out;
	}

	ret = -ESRCH;
	read_lock(&tasklist_lock);
	child = find_task_by_pid(pid);
	if (child)
		get_task_struct(child);
	read_unlock(&tasklist_lock);
	if (!child)
		goto out;
	ret = -EPERM;
	if (pid == 1)		/* no messing around with init! */
		goto out_tsk;

	if (request == PTRACE_ATTACH) {
		ret = ptrace_attach(child);
		goto out_tsk;
	}

	ret = ptrace_check_attach(child, request == PTRACE_KILL);
	if (ret < 0)
		goto out_tsk;

	switch (request) {
	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
	case PTRACE_PEEKDATA: {
		int copied;

#ifdef __LP64__
		if (is_compat_task(child)) {
			unsigned int tmp;

			addr &= 0xffffffffL;
			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
			ret = -EIO;
			if (copied != sizeof(tmp))
				goto out_tsk;
			ret = put_user(tmp,(unsigned int *) data);
			DBG(("sys_ptrace(PEEK%s, %d, %lx, %lx) returning %ld, data %x\n",
				request == PTRACE_PEEKTEXT ? "TEXT" : "DATA",
				pid, oaddr, odata, ret, tmp));
		}
		else
#endif
		{
			unsigned long tmp;

			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
			ret = -EIO;
			if (copied != sizeof(tmp))
				goto out_tsk;
			ret = put_user(tmp,(unsigned long *) data);
		}
		goto out_tsk;
	}

	/* when I and D space are separate, this will have to be fixed. */
	case PTRACE_POKETEXT: /* write the word at location addr. */
	case PTRACE_POKEDATA:
		ret = 0;
#ifdef __LP64__
		if (is_compat_task(child)) {
			unsigned int tmp = (unsigned int)data;
			DBG(("sys_ptrace(POKE%s, %d, %lx, %lx)\n",
				request == PTRACE_POKETEXT ? "TEXT" : "DATA",
				pid, oaddr, odata));
			addr &= 0xffffffffL;
			if (access_process_vm(child, addr, &tmp, sizeof(tmp), 1) == sizeof(tmp))
				goto out_tsk;
		}
		else
#endif
		{
			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
				goto out_tsk;
		}
		ret = -EIO;
		goto out_tsk;

	/* Read the word at location addr in the USER area.  For ptraced
	   processes, the kernel saves all regs on a syscall. */
	case PTRACE_PEEKUSR: {
		ret = -EIO;
#ifdef __LP64__
		if (is_compat_task(child)) {
			unsigned int tmp;

			if (addr & (sizeof(int)-1))
				goto out_tsk;
			if ((addr = translate_usr_offset(addr)) < 0)
				goto out_tsk;

			tmp = *(unsigned int *) ((char *) task_regs(child) + addr);
			ret = put_user(tmp, (unsigned int *) data);
			DBG(("sys_ptrace(PEEKUSR, %d, %lx, %lx) returning %ld, addr %lx, data %x\n",
				pid, oaddr, odata, ret, addr, tmp));
		}
		else
#endif
		{
			unsigned long tmp;

			if ((addr & (sizeof(long)-1)) || (unsigned long) addr >= sizeof(struct pt_regs))
				goto out_tsk;
			tmp = *(unsigned long *) ((char *) task_regs(child) + addr);
			ret = put_user(tmp, (unsigned long *) data);
		}
		goto out_tsk;
	}

	/* Write the word at location addr in the USER area.  This will need
	   to change when the kernel no longer saves all regs on a syscall.
	   FIXME.  There is a problem at the moment in that r3-r18 are only
	   saved if the process is ptraced on syscall entry, and even then
	   those values are overwritten by actual register values on syscall
	   exit. */
	case PTRACE_POKEUSR:
		ret = -EIO;
		/* Some register values written here may be ignored in
		 * entry.S:syscall_restore_rfi; e.g. iaoq is written with
		 * r31/r31+4, and not with the values in pt_regs.
		 */
		 /* PT_PSW=0, so this is valid for 32 bit processes under 64
		 * bit kernels.
		 */
		if (addr == PT_PSW) {
			/* PT_PSW=0, so this is valid for 32 bit processes
			 * under 64 bit kernels.
			 *
			 * Allow writing to Nullify, Divide-step-correction,
			 * and carry/borrow bits.
			 * BEWARE, if you set N, and then single step, it won't
			 * stop on the nullified instruction.
			 */
			DBG(("sys_ptrace(POKEUSR, %d, %lx, %lx)\n",
				pid, oaddr, odata));
			data &= USER_PSW_BITS;
			task_regs(child)->gr[0] &= ~USER_PSW_BITS;
			task_regs(child)->gr[0] |= data;
			ret = 0;
			goto out_tsk;
		}
#ifdef __LP64__
		if (is_compat_task(child)) {
			if (addr & (sizeof(int)-1))
				goto out_tsk;
			if ((addr = translate_usr_offset(addr)) < 0)
				goto out_tsk;
			DBG(("sys_ptrace(POKEUSR, %d, %lx, %lx) addr %lx\n",
				pid, oaddr, odata, addr));
			if (addr >= PT_FR0 && addr <= PT_FR31) {
				/* Special case, fp regs are 64 bits anyway */
				*(unsigned int *) ((char *) task_regs(child) + addr) = data;
				ret = 0;
			}
			else if ((addr >= PT_GR1+4 && addr <= PT_GR31+4) ||
					addr == PT_IAOQ0+4 || addr == PT_IAOQ1+4 ||
					addr == PT_SAR+4) {
				/* Zero the top 32 bits */
				*(unsigned int *) ((char *) task_regs(child) + addr - 4) = 0;
				*(unsigned int *) ((char *) task_regs(child) + addr) = data;
				ret = 0;
			}
			goto out_tsk;
		}
		else
#endif
		{
			if ((addr & (sizeof(long)-1)) || (unsigned long) addr >= sizeof(struct pt_regs))
				goto out_tsk;
			if ((addr >= PT_GR1 && addr <= PT_GR31) ||
					addr == PT_IAOQ0 || addr == PT_IAOQ1 ||
					(addr >= PT_FR0 && addr <= PT_FR31) ||
					addr == PT_SAR) {
				*(unsigned long *) ((char *) task_regs(child) + addr) = data;
				ret = 0;
			}
			goto out_tsk;
		}

	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
	case PTRACE_CONT:
		ret = -EIO;
		DBG(("sys_ptrace(%s)\n",
			request == PTRACE_SYSCALL ? "SYSCALL" : "CONT"));
		if ((unsigned long) data > _NSIG)
			goto out_tsk;
		child->ptrace &= ~(PT_SINGLESTEP|PT_BLOCKSTEP);
		if (request == PTRACE_SYSCALL) {
			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		} else {
			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		}		
		child->exit_code = data;
		goto out_wake_notrap;

	case PTRACE_KILL:
		/*
		 * make the child exit.  Best I can do is send it a
		 * sigkill.  perhaps it should be put in the status
		 * that it wants to exit.
		 */
		DBG(("sys_ptrace(KILL)\n"));
		if (child->state == TASK_ZOMBIE)	/* already dead */
			goto out_tsk;
		child->exit_code = SIGKILL;
		goto out_wake_notrap;

	case PTRACE_SINGLEBLOCK:
		DBG(("sys_ptrace(SINGLEBLOCK)\n"));
		ret = -EIO;
		if ((unsigned long) data > _NSIG)
			goto out_tsk;
		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		child->ptrace &= ~PT_SINGLESTEP;
		child->ptrace |= PT_BLOCKSTEP;
		child->exit_code = data;

		/* Enable taken branch trap. */
		pa_psw(child)->r = 0;
		pa_psw(child)->t = 1;
		pa_psw(child)->h = 0;
		pa_psw(child)->l = 0;
		goto out_wake;

	case PTRACE_SINGLESTEP:
		DBG(("sys_ptrace(SINGLESTEP)\n"));
		ret = -EIO;
		if ((unsigned long) data > _NSIG)
			goto out_tsk;
		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		child->ptrace &= ~PT_BLOCKSTEP;
		child->ptrace |= PT_SINGLESTEP;
		child->exit_code = data;

		if (pa_psw(child)->n) {
			struct siginfo si;

			/* Nullified, just crank over the queue. */
			task_regs(child)->iaoq[0] = task_regs(child)->iaoq[1];
			task_regs(child)->iasq[0] = task_regs(child)->iasq[1];
			task_regs(child)->iaoq[1] = task_regs(child)->iaoq[0] + 4;
			pa_psw(child)->n = 0;
			pa_psw(child)->x = 0;
			pa_psw(child)->y = 0;
			pa_psw(child)->z = 0;
			pa_psw(child)->b = 0;
			ptrace_disable(child);
			/* Don't wake up the child, but let the
			   parent know something happened. */
			si.si_code = TRAP_TRACE;
			si.si_addr = (void *) (task_regs(child)->iaoq[0] & ~3);
			si.si_signo = SIGTRAP;
			si.si_errno = 0;
			force_sig_info(SIGTRAP, &si, child);
			//notify_parent(child, SIGCHLD);
			//ret = 0;
			goto out_wake;
		}

		/* Enable recovery counter traps.  The recovery counter
		 * itself will be set to zero on a task switch.  If the
		 * task is suspended on a syscall then the syscall return
		 * path will overwrite the recovery counter with a suitable
		 * value such that it traps once back in user space.  We
		 * disable interrupts in the childs PSW here also, to avoid
		 * interrupts while the recovery counter is decrementing.
		 */
		pa_psw(child)->r = 1;
		pa_psw(child)->t = 0;
		pa_psw(child)->h = 0;
		pa_psw(child)->l = 0;
		/* give it a chance to run. */
		goto out_wake;

	case PTRACE_DETACH:
		ret = ptrace_detach(child, data);
		goto out_tsk;

	default:
		ret = ptrace_request(child, request, addr, data);
		goto out_tsk;
	}

out_wake_notrap:
	ptrace_disable(child);
out_wake:
	wake_up_process(child);
	ret = 0;
out_tsk:
	put_task_struct(child);
out:
	unlock_kernel();
	DBG(("sys_ptrace(%ld, %d, %lx, %lx) returning %ld\n",
		request, pid, oaddr, odata, ret));
	return ret;
}
Example #25
0
asmlinkage int sys32_ptrace(long request, long pid, long addr, s32 data)
{
	struct task_struct *child;
	int ret = -EPERM;
	unsigned long flags;
	u32 tmp;
	int copied;
	ptrace_area   parea; 

	lock_kernel();
	if (request == PTRACE_TRACEME) 
	{
		/* are we already being traced? */
		if (current->ptrace & PT_PTRACED)
			goto out;
		/* set the ptrace bit in the process flags. */
		current->ptrace |= PT_PTRACED;
		ret = 0;
		goto out;
	}
	ret = -ESRCH;
	read_lock(&tasklist_lock);
	child = find_task_by_pid(pid);
	read_unlock(&tasklist_lock);
	if (!child)
		goto out;
	ret = -EPERM;
	if (pid == 1)		/* you may not mess with init */
		goto out;
	if (request == PTRACE_ATTACH) 
	{
		ret = ptrace_attach(child);
		goto out;
	}
	ret = -ESRCH;
	// printk("child=%lX child->flags=%lX",child,child->flags);
	/* I added child!=current line so we can get the */
	/* ieee_instruction_pointer from the user structure DJB */
	if(child!=current)
	{
		if (!(child->ptrace & PT_PTRACED))
			goto out;
		if (child->state != TASK_STOPPED) 
		{
			if (request != PTRACE_KILL)
				goto out;
		}
		if (child->p_pptr != current)
			goto out;
	}
	switch (request) 
	{
		/* If I and D space are separate, these will need to be fixed. */
	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
	case PTRACE_PEEKDATA: 
		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
		ret = -EIO;
		if (copied != sizeof(tmp))
			goto out;
		ret = put_user(tmp,(u32 *)(unsigned long)data);
		goto out;

		/* read the word at location addr in the USER area. */
	case PTRACE_PEEKUSR:
		ret=copy_user(child,addr,data,sizeof(u32),1,0);
		break;

		/* If I and D space are separate, this will have to be fixed. */
	case PTRACE_POKETEXT: /* write the word at location addr. */
	case PTRACE_POKEDATA:
		ret = 0;
		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
			goto out;
		ret = -EIO;
		goto out;
		break;

	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
		ret=copy_user(child,addr,(addr_t)&data,sizeof(u32),0,1);
		break;

	case PTRACE_SYSCALL: 	/* continue and stop at next (return from) syscall */
	case PTRACE_CONT: 	 /* restart after signal. */
		ret = -EIO;
		if ((unsigned long) data >= _NSIG)
			break;
		if (request == PTRACE_SYSCALL)
			child->ptrace |= PT_TRACESYS;
		else
			child->ptrace &= ~PT_TRACESYS;
		child->exit_code = data;
		/* make sure the single step bit is not set. */
		clear_single_step(child);
		wake_up_process(child);
		ret = 0;
		break;

/*
 * make the child exit.  Best I can do is send it a sigkill. 
 * perhaps it should be put in the status that it wants to 
 * exit.
 */
	case PTRACE_KILL:
		ret = 0;
		if (child->state == TASK_ZOMBIE) /* already dead */
			break;
		child->exit_code = SIGKILL;
		clear_single_step(child);
		wake_up_process(child);
		/* make sure the single step bit is not set. */
		break;

	case PTRACE_SINGLESTEP:  /* set the trap flag. */
		ret = -EIO;
		if ((unsigned long) data >= _NSIG)
			break;
		child->ptrace &= ~PT_TRACESYS;
		child->exit_code = data;
		set_single_step(child);
		/* give it a chance to run. */
		wake_up_process(child);
		ret = 0;
		break;

	case PTRACE_DETACH:  /* detach a process that was attached. */
		ret = -EIO;
		if ((unsigned long) data >= _NSIG)
			break;
		child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
		child->exit_code = data;
		write_lock_irqsave(&tasklist_lock, flags);
		REMOVE_LINKS(child);
		child->p_pptr = child->p_opptr;
		SET_LINKS(child);
		write_unlock_irqrestore(&tasklist_lock, flags);
		/* make sure the single step bit is not set. */
		clear_single_step(child);
		wake_up_process(child);
		ret = 0;
		break;
	case PTRACE_PEEKUSR_AREA:
	case PTRACE_POKEUSR_AREA:
		{
		ptrace_area_emu31 * parea31 = (void *)addr;
		if (!access_ok(VERIFY_READ, parea31, sizeof(*parea31)))
			return(-EFAULT);
		ret = __get_user(parea.len, &parea31->len);
		ret |= __get_user(parea.kernel_addr, &parea31->kernel_addr);
		ret |= __get_user(parea.process_addr, &parea31->process_addr);
		if(ret==0)  
		   ret=copy_user(child,parea.kernel_addr,parea.process_addr,
				 parea.len,1,(request==PTRACE_POKEUSR_AREA));
		break;
		}
	default:
		ret = -EIO;
		break;
	}
 out:
	unlock_kernel();
	return ret;
}
Example #26
0
/* 实现核心功能--注入 */
int inject_remote_process(pid_t target_pid, const char *library_path,
		const char *function_name, const char *param, size_t param_size)
{
    int ret = -1;
    // 存放目标进程地址
    void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr, *dlerror_addr;
    void *local_handle, *remote_handle, *dlhandle;
    uint8_t *map_base = 0; // 存放目标进程mmap获取的内存块地址,mmap将一个文件或者其它对象映射进内存
    uint8_t *dlopen_param1_ptr, *dlsym_param2_ptr, *saved_r0_pc_ptr, *inject_param_ptr, *remote_code_ptr, *local_code_ptr;

    struct pt_regs regs, original_regs;
    extern uint32_t _dlopen_addr_s, _dlopen_param1_s, _dlopen_param2_s, _dlsym_addr_s, \
        _dlsym_param2_s, _dlclose_addr_s, _inject_start_s, _inject_end_s, _inject_function_param_s, \
        _saved_cpsr_s, _saved_r0_pc_s;

    uint32_t code_length;
    long parameters[10];

    DEBUG_PRINT("[+] Injecting process: %d\n", target_pid);

    // step 1. attach到目标进程
    if (ptrace_attach(target_pid) == -1)
        goto exit;

    // step 2. save context, 保存目标进程被注入前的寄存器内容
    // 方便注入完成后恢复
    if (ptrace_getregs(target_pid, &regs) == -1)
        goto exit;

    /* save original registers */
    memcpy(&original_regs, &regs, sizeof(regs));

    /* step 3. 获取目标进程存放mmap()代码的地址,执行mmap调用,
     * 在目标进程分配一块地址,用于存放后面要注入的库路径和相关函数地址等
     * mmap()会开辟一块内存,用于将一个文件或者其它对象映射进内存
     */
    // 寻找目标进程mmap的地址
    // libc为c语音标准库,一般进程都会加载;libc.so包含mmap函数
    mmap_addr = get_remote_addr(target_pid, libc_path, (void *)mmap);
    DEBUG_PRINT("[+] Remote mmap address: %x\n", mmap_addr);

    parameters[0] = 0;  // addr
    parameters[1] = 0x4000; // size
    parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC;  // prot
    parameters[3] =  MAP_ANONYMOUS | MAP_PRIVATE; // flags
    parameters[4] = 0; //fd
    parameters[5] = 0; //offset

    // 目标进程执行mmap
    if (ptrace_call_wrapper(target_pid, "mmap", mmap_addr, parameters, 6, &regs) == -1)
        goto exit;

    map_base = ptrace_retval(&regs);// mmap调用后返回值存入regs内的ax寄存器,syscall之前ax存调用号,调用后存返回值

    // step 4. 获取目标进程动态库的几个函数,并将要注入的so的路径写入刚刚申请的内存初始地址
    // dlopen()函数以指定模式打开指定的动态链接库文件,并返回一个句柄给dlsym()的调用进程。使用dlclose()来卸载打开的库。
    dlopen_addr = get_remote_addr(target_pid, linker_path, (void *)dlopen); // 找到dlopen()的地址
    dlsym_addr = get_remote_addr(target_pid, linker_path, (void *)dlsym); // 找到dlsys()地址
    dlclose_addr = get_remote_addr(target_pid, linker_path, (void *)dlclose); // 找到dlclose()地址
    dlerror_addr = get_remote_addr(target_pid, linker_path, (void *)dlerror); // 找到dlerror()地址

    DEBUG_PRINT("[+] Get imports: dlopen: %x, dlsym: %x, dlclose: %x, dlerror: %x\n",
            dlopen_addr, dlsym_addr, dlclose_addr, dlerror_addr);

    printf("library path = %s\n", library_path);
    // 将要注入的so的路径写入刚刚申请的内存初始地址,作为即将要调用的dlopen函数的参数parameters[0]
    ptrace_writedata(target_pid, map_base, library_path, strlen(library_path) + 1);

    // step 5. 在目标进程内调用dlopen函数加载要注入的so
    // 完成后so已经被注入目标进程的地址空间内了
    // 当库被装入后,可以把 dlopen() 返回的句柄作为给 dlsym() 的第一个参数,以获得符号在库中的地址。
    // 使用这个地址,就可以获得库中特定函数的指针,并且调用装载库中的相应函数。
    parameters[0] = map_base;
    parameters[1] = RTLD_NOW| RTLD_GLOBAL;

    if (ptrace_call_wrapper(target_pid, "dlopen", dlopen_addr, parameters, 2, &regs) == -1)
        goto exit;

    // step 6. 在目标进程内调用dlsym函数获取刚刚注入的so里的hook函数
    void * sohandle = ptrace_retval(&regs);

#define FUNCTION_NAME_ADDR_OFFSET       0x100
    ptrace_writedata(target_pid, map_base + FUNCTION_NAME_ADDR_OFFSET, function_name, strlen(function_name) + 1);
    parameters[0] = sohandle;
    parameters[1] = map_base + FUNCTION_NAME_ADDR_OFFSET;

    if (ptrace_call_wrapper(target_pid, "dlsym", dlsym_addr, parameters, 2, &regs) == -1)
        goto exit;

    // step 7. 在目标进程内调用hook函数
    void * hook_entry_addr = ptrace_retval(&regs); // dlsys()返回hook函数地址
    DEBUG_PRINT("hook_entry_addr = %p\n", hook_entry_addr);

#define FUNCTION_PARAM_ADDR_OFFSET      0x200
    ptrace_writedata(target_pid, map_base + FUNCTION_PARAM_ADDR_OFFSET, param, strlen(param) + 1);
    parameters[0] = map_base + FUNCTION_PARAM_ADDR_OFFSET;
    function_name
    if (ptrace_call_wrapper(target_pid, "hook_entry", hook_entry_addr, parameters, 1, &regs) == -1)
        goto exit;

    printf("Press enter to dlclose and detach\n");
    getchar();
    parameters[0] = sohandle;

    if (ptrace_call_wrapper(target_pid, "dlclose", dlclose, parameters, 1, &regs) == -1)
        goto exit;

    /* restore */
    // step 8. 恢复目标进程的寄存器,detach ptrace
    ptrace_setregs(target_pid, &original_regs);
    ptrace_detach(target_pid);
    ret = 0;

exit:
    return ret;
}
Example #27
0
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
	struct task_struct *child;
	int ret;
	int add = 0;

	lock_kernel();
	ret = -EPERM;
	if (request == PTRACE_TRACEME) {
		/* are we already being traced? */
		if (current->ptrace & PT_PTRACED)
			goto out;
		/* set the ptrace bit in the process flags. */
		current->ptrace |= PT_PTRACED;
		ret = 0;
		goto out;
	}
	ret = -ESRCH;
	read_lock(&tasklist_lock);
	child = find_task_by_pid(pid);
	if (child)
		get_task_struct(child);
	read_unlock(&tasklist_lock);	/* FIXME!!! */
	if (!child)
		goto out;
	ret = -EPERM;
	if (pid == 1)		/* you may not mess with init */
		goto out_tsk;
	if (request == PTRACE_ATTACH) {

		ret = ptrace_attach(child);
		goto out_tsk;
	}

	ret = ptrace_check_attach(child, request == PTRACE_KILL);
	if (ret < 0)
		goto out_tsk;

	switch (request) {
		/* when I and D space are separate, these will need to be fixed. */
	case PTRACE_PEEKDATA:
#ifdef DEBUG
		printk("PTRACE_PEEKDATA\n");
#endif
		add = MAX_SHARED_LIBS * 4;	/* space between text and data */
		/* fall through */
	case PTRACE_PEEKTEXT:	/* read word at location addr. */
		{
			unsigned long tmp = 0;
			int copied;

#ifdef DEBUG
			printk("PEEKTEXT at addr %x + add %d %d", addr, add,
			       sizeof(data));
#endif
			copied =
			    access_process_vm(child, addr + add, &tmp,
					      sizeof(tmp), 0);
#ifdef DEBUG
			printk(" bytes %x\n", data);
#endif
			ret = -EIO;
			if (copied != sizeof(tmp))
				goto out_tsk;
			ret = put_user(tmp, (unsigned long *)data);
			goto out_tsk;
		}

		/* read the word at location addr in the USER area. */
	case PTRACE_PEEKUSR:
		{
			unsigned long tmp;
			ret = -EIO;
			tmp = 0;
			if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 8))) {
				printk
				    ("ptrace error : PEEKUSR : temporarily returning 0 - %x sizeof(pt_regs) is %lx\n",
				     (int)addr, sizeof(struct pt_regs));
				goto out_tsk;
			}
			if (addr == sizeof(struct pt_regs)) {
				tmp = child->mm->start_code + TEXT_OFFSET;
			} else if (addr == (sizeof(struct pt_regs) + 4)) {
				// should really just be start_data but the .gdb file has data starting
				// at an offset and gdb refuses to reduce the start value
				tmp =
				    child->mm->start_data -
				    (child->mm->end_code -
				     child->mm->start_code);
			} else if (addr == (sizeof(struct pt_regs) + 8)) {
				// should really just be end_data but the .gdb file has data starting
				// at an offset and gdb refuses to reduce the start value
				tmp =
				    child->mm->end_data - (child->mm->end_code -
							   child->mm->
							   start_code);
			} else {
				tmp = get_reg(child, addr);
			}
			ret = put_user(tmp, (unsigned long *)data);
			goto out_tsk;
		}

		/* when I and D space are separate, this will have to be fixed. */
	case PTRACE_POKEDATA:
		printk("PTRACE_PEEKDATA\n");
		/* fall through */
	case PTRACE_POKETEXT:	/* write the word at location addr. */
		{
			ret = 0;
#ifdef DEBUG
			printk("POKETEXT at addr %x + add %d %d bytes %x\n",
			       addr, add, sizeof(data), data);
#endif
			if (access_process_vm(child, addr + add,
					      &data, sizeof(data),
					      1) == sizeof(data))
				goto out_tsk;
			ret = -EIO;
			goto out_tsk;
		}

	case PTRACE_POKEUSR:	/* write the word at location addr in the USER area */
		ret = -EIO;
		if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 8))) {
			printk
			    ("ptrace error : POKEUSR: temporarily returning 0\n");
			goto out_tsk;
		}

		if (addr == PT_SYSCFG) {
			data &= SYSCFG_MASK;
			data |= get_reg(child, PT_SYSCFG);
		}
		ret = put_reg(child, addr, data);
		goto out_tsk;

	case PTRACE_SYSCALL:	/* continue and stop at next (return from) syscall */
	case PTRACE_CONT:
		{		/* restart after signal. */
			long tmp;
#ifdef DEBUG
			printk("ptrace_cont\n");
#endif

			ret = -EIO;
			if (!valid_signal(data))
				goto out_tsk;
			if (request == PTRACE_SYSCALL)
				set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
			else
				clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);

			child->exit_code = data;
			/* make sure the single step bit is not set. */
			tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
			put_reg(child, PT_SYSCFG, tmp);
#ifdef DEBUG
			printk("before wake_up_process\n");
#endif
			wake_up_process(child);
			ret = 0;
			goto out_tsk;
		}

/*
 * make the child exit.  Best I can do is send it a sigkill.
 * perhaps it should be put in the status that it wants to
 * exit.
 */
	case PTRACE_KILL:
		{
			long tmp;
			ret = 0;
			if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
				goto out_tsk;
			child->exit_code = SIGKILL;
			/* make sure the single step bit is not set. */
			tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
			put_reg(child, PT_SYSCFG, tmp);
			wake_up_process(child);
			goto out_tsk;
		}

	case PTRACE_SINGLESTEP:
		{		/* set the trap flag. */
			long tmp;
#ifdef DEBUG
			printk("single step\n");
#endif
			ret = -EIO;
			if (!valid_signal(data))
				goto out_tsk;
			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);

			tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS);
			put_reg(child, PT_SYSCFG, tmp);

			child->exit_code = data;
			/* give it a chance to run. */
			wake_up_process(child);
			ret = 0;
			goto out;
		}

	case PTRACE_DETACH:
		{		/* detach a process that was attached. */
			ret = ptrace_detach(child, data);
			break;
		}

	case PTRACE_GETREGS:
		{

			/* Get all gp regs from the child. */
			ret = ptrace_getregs(child, (void __user *)data);
			goto out_tsk;
		}

	case PTRACE_SETREGS:
		{

			printk("SETREGS : **** NOT IMPLEMENTED ***\n");
			/* Set all gp regs in the child. */
			ret = 0;
			goto out_tsk;
		}

	default:
		printk("Ptrace :  *** Unhandled case **** %d\n", (int)request);
		ret = -EIO;
		goto out_tsk;
	}
      out_tsk:
	put_task_struct(child);
      out:
	unlock_kernel();
	return ret;
}
Example #28
0
/* write the assembler code into target proc,
 * and invoke it to execute
 */
int writecode_to_targetproc( 
        pid_t target_pid, // target process pid
        const char *library_path, // the path of .so that will be 
        // upload to target process 
        const char *function_name, // .so init fucntion e.g. hook_init
        void *param, // the parameters of init function
        size_t param_size ) // number of parameters 
{
    int ret = -1;
    void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr;
    void *local_handle, *remote_handle, *dlhandle;
    uint8_t *map_base;
    uint8_t *dlopen_param1_ptr, *dlsym_param2_ptr, *saved_r0_pc_ptr, *inject_param_ptr, *remote_code_ptr, *local_code_ptr;

    struct pt_regs regs, original_regs;

    // extern global variable in the assembler code 
    extern uint32_t _dlopen_addr_s, _dlopen_param1_s, _dlopen_param2_s, \
        _dlsym_addr_s, _dlsym_param2_s, _dlclose_addr_s, \
        _inject_start_s, _inject_end_s, _inject_function_param_s, \
        _saved_cpsr_s, _saved_r0_pc_s;

    uint32_t code_length;

    long parameters[10];

    // make target_pid as its child process and stop
    if ( ptrace_attach( target_pid ) == -1 )
        return -1;

    // get the values of 18 registers from target_pid
    if ( ptrace_getregs( target_pid, &regs ) == -1 )
        goto exit;

    // save original registers 
    memcpy( &original_regs, @regs, sizeof(regs) );

    // get mmap address from target_pid
    // the mmap is the address of mmap in the cur process
    mmap_addr = get_remote_addr( target_pid, "/system/lib/libc.so", (void *)mmap );

    // set mmap parameters
    parameters[0] = 0;  // addr
    parameters[1] = 0x4000; // size
    parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC;  // prot
    parameters[3] =  MAP_ANONYMOUS | MAP_PRIVATE; // flags
    parameters[4] = 0; //fd
    parameters[5] = 0; //offset

    // execute the mmap in target_pid
    if ( ptrace_call( target_pid, (uint32_t)mmap_addr, parameters, 6, &regs) == -1 )
        goto exit;

    // get the return values of mmap <in r0>
    if ( ptrace_getregs( target_pid, &regs) == -1 )
        goto exit;

    // get the start address for assembler code
    map_base = (uint8_t *)regs.ARM_r0;

    // get the address of dlopen, dlsym and dlclose in target process
    dlopen_addr = get_remote_addr( target_pid, "/system/bin/linker", (void *)dlopen );
    dlsym_addr = get_remote_addr( target_pid, "/system/bin/linker", (void *)dlsym );
    dlclose_addr = get_remote_addr( target_pid, "/system/bin/linker", (void *)dlclose );

    // set the start address for assembler code in target process
    remote_code_ptr = map_base + 0x3C00;

    // set the start address for assembler code in cur process
    local_code_ptr = (uint8_t *)&_inject_start_s;

    // set global variable of assembler code
    // and these address is in the target process
    _dlopen_addr_s = (uint32_t)dlopen_addr;
    _dlsym_addr_s = (uint32_t)dlsym_addr;
    _dlclose_addr_s = (uint32_t)dlclose_addr;

    code_length = (uint32_t)&_inject_end_s - (uint32_t)&_inject_start_s;

    dlopen_param1_ptr = local_code_ptr + code_length + 0x20;
    dlsym_param2_ptr = dlopen_param1_ptr + MAX_PATH;
    saved_r0_pc_ptr = dlsym_param2_ptr + MAX_PATH;
    inject_param_ptr = saved_r0_pc_ptr + MAX_PATH;


    // save library path to assembler code global variable
    strcpy( dlopen_param1_ptr, library_path );
    _dlopen_param1_s = REMOTE_ADDR( dlopen_param1_ptr, local_code_ptr, remote_code_ptr );


    // save function name to assembler code global variable
    strcpy( dlsym_param2_ptr, function_name );
    _dlsym_param2_s = REMOTE_ADDR( dlsym_param2_ptr, local_code_ptr, remote_code_ptr );

    // save cpsr to assembler code global variable
    _saved_cpsr_s = original_regs.ARM_cpsr;

    // save r0-r15 to assembler code global variable
    memcpy( saved_r0_pc_ptr, &(original_regs.ARM_r0), 16 * 4 ); // r0 ~ r15
    _saved_r0_pc_s = REMOTE_ADDR( saved_r0_pc_ptr, local_code_ptr, remote_code_ptr );

    // save function parameters to assembler code global variable
    memcpy( inject_param_ptr, param, param_size );
    _inject_function_param_s = REMOTE_ADDR( inject_param_ptr, local_code_ptr, remote_code_ptr );

    // write the assembler code into target process
    // now the values of global variable is in the target process space
    ptrace_writedata( target_pid, remote_code_ptr, local_code_ptr, 0x400 );

    memcpy( &regs, &original_regs, sizeof(regs) );

    // set sp and pc to the start address of assembler code
    regs.ARM_sp = (long)remote_code_ptr;
    regs.ARM_pc = (long)remote_code_ptr;

    // set registers for target process
    ptrace_setregs( target_pid, &regs );

    // make the target_pid is not a child process of cur process
    // and make target_pid continue to running
    ptrace_detach( target_pid );

    // now finish it successfully
    ret = 0;

exit:
    return ret;
}
Example #29
0
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
	struct task_struct *child;
	int ret;

	lock_kernel();
	ret = -EPERM;
	if (request == PTRACE_TRACEME) {
		/* are we already being traced? */
		if (current->ptrace & PT_PTRACED)
			goto out;
		/* set the ptrace bit in the process flags. */
		current->ptrace |= PT_PTRACED;
		ret = 0;
		goto out;
	}
	ret = -ESRCH;
	read_lock(&tasklist_lock);
	child = find_task_by_pid(pid);
	if (child)
		get_task_struct(child);
	read_unlock(&tasklist_lock);
	if (!child)
		goto out;
	ret = -EPERM;
	if (pid == 1)		/* you may not mess with init */
		goto out_tsk;
	if (request == PTRACE_ATTACH) {
		ret = ptrace_attach(child);
		goto out_tsk;
	}
	ret = -ESRCH;
	if (!(child->ptrace & PT_PTRACED))
		goto out_tsk;
	if (child->state != TASK_STOPPED) {
		if (request != PTRACE_KILL)
			goto out_tsk;
	}
	if (child->p_pptr != current)
		goto out_tsk;

	switch (request) {
	/* when I and D space are separate, these will need to be fixed. */
		case PTRACE_PEEKTEXT: /* read word at location addr. */ 
		case PTRACE_PEEKDATA: {
			unsigned long tmp;
			int copied;

			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
			ret = -EIO;
			if (copied != sizeof(tmp))
				break;
			ret = put_user(tmp,(unsigned long *) data);
			break;
		}

		/* read the word at location addr in the USER area. */
		case PTRACE_PEEKUSR: {
			unsigned long tmp;

			ret = -EIO;
			if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
				break;

			tmp = get_reg(child, addr >> 2);
			ret = put_user(tmp, (unsigned long *)data);
			break;
		}

		/* when I and D space are separate, this will have to be fixed. */
		case PTRACE_POKETEXT: /* write the word at location addr. */
		case PTRACE_POKEDATA:
			ret = 0;
			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
				break;
			ret = -EIO;
			break;

		case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
			ret = -EIO;
			if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
				break;

			addr >>= 2;

			if (addr == PT_DCCR) {
				/* don't allow the tracing process to change stuff like
				 * interrupt enable, kernel/user bit, dma enables etc.
				 */
				data &= DCCR_MASK;
				data |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
			}
			if (put_reg(child, addr, data))
				break;
			ret = 0;
			break;

		case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
		case PTRACE_CONT: /* restart after signal. */
			ret = -EIO;
			if ((unsigned long) data > _NSIG)
				break;
			if (request == PTRACE_SYSCALL)
				child->ptrace |= PT_TRACESYS;
			else
				child->ptrace &= ~PT_TRACESYS;
			child->exit_code = data;
			/* TODO: make sure any pending breakpoint is killed */
			wake_up_process(child);
			ret = 0;
			break;

/*
 * make the child exit.  Best I can do is send it a sigkill. 
 * perhaps it should be put in the status that it wants to 
 * exit.
 */
		case PTRACE_KILL:
			ret = 0;
			if (child->state == TASK_ZOMBIE) /* already dead */
				break;
			child->exit_code = SIGKILL;
			/* TODO: make sure any pending breakpoint is killed */
			wake_up_process(child);
			break;

		case PTRACE_SINGLESTEP: /* set the trap flag. */
			ret = -EIO;
			if ((unsigned long) data > _NSIG)
				break;
			child->ptrace &= ~PT_TRACESYS;

			/* TODO: set some clever breakpoint mechanism... */

			child->exit_code = data;
			/* give it a chance to run. */
			wake_up_process(child);
			ret = 0;
			break;

		case PTRACE_DETACH:
			ret = ptrace_detach(child, data);
			break;

		case PTRACE_GETREGS: { /* Get all gp regs from the child. */
		  	int i;
			unsigned long tmp;
			for (i = 0; i <= PT_MAX; i++) {
				tmp = get_reg(child, i);
				if (put_user(tmp, (unsigned long *) data)) {
					ret = -EFAULT;
					break;
				}
				data += sizeof(long);
			}
			ret = 0;
			break;
		}

		case PTRACE_SETREGS: { /* Set all gp regs in the child. */
			int i;
			unsigned long tmp;
			for (i = 0; i <= PT_MAX; i++) {
				if (get_user(tmp, (unsigned long *) data)) {
					ret = -EFAULT;
					break;
				}
				if (i == PT_DCCR) {
					tmp &= DCCR_MASK;
					tmp |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
				}
				put_reg(child, i, tmp);
				data += sizeof(long);
			}
			ret = 0;
			break;
		}

		default:
			ret = -EIO;
			break;
	}
out_tsk:
	free_task_struct(child);
out:
	unlock_kernel();
	return ret;
}
Example #30
0
int sys_ptrace(long request, long pid, long addr, long data)
{
	struct task_struct *child;
	int ret = -EPERM;

	lock_kernel();
	if (request == PTRACE_TRACEME) {
		/* are we already being traced? */
		if (current->ptrace & PT_PTRACED)
			goto out;
		ret = security_ptrace(current->parent, current);
		if (ret)
			goto out;
		/* set the ptrace bit in the process flags. */
		current->ptrace |= PT_PTRACED;
		ret = 0;
		goto out;
	}
	ret = -ESRCH;
	read_lock(&tasklist_lock);
	child = find_task_by_pid(pid);
	if (child)
		get_task_struct(child);
	read_unlock(&tasklist_lock);
	if (!child)
		goto out;

	ret = -EPERM;
	if (pid == 1)		/* you may not mess with init */
		goto out_tsk;

	if (request == PTRACE_ATTACH) {
		ret = ptrace_attach(child);
		goto out_tsk;
	}

	ret = ptrace_check_attach(child, request == PTRACE_KILL);
	if (ret < 0)
		goto out_tsk;

	switch (request) {
	/* when I and D space are separate, these will need to be fixed. */
	case PTRACE_PEEKTEXT: /* read word at location addr. */
	case PTRACE_PEEKDATA: {
		unsigned long tmp;
		int copied;

		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
		ret = -EIO;
		if (copied != sizeof(tmp))
			break;
		ret = put_user(tmp,(unsigned long __user *) data);
		break;
	}

	/* read the word at location addr in the USER area. */
	/* XXX this will need fixing for 64-bit */
	case PTRACE_PEEKUSR: {
		unsigned long index, tmp;

		ret = -EIO;
		/* convert to index and check */
		index = (unsigned long) addr >> 2;
		if ((addr & 3) || index > PT_FPSCR
		    || child->thread.regs == NULL)
			break;

		CHECK_FULL_REGS(child->thread.regs);
		if (index < PT_FPR0) {
			tmp = get_reg(child, (int) index);
		} else {
			preempt_disable();
			if (child->thread.regs->msr & MSR_FP)
				giveup_fpu(child);
			preempt_enable();
			tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
		}
		ret = put_user(tmp,(unsigned long __user *) data);
		break;
	}

	/* If I and D space are separate, this will have to be fixed. */
	case PTRACE_POKETEXT: /* write the word at location addr. */
	case PTRACE_POKEDATA:
		ret = 0;
		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
			break;
		ret = -EIO;
		break;

	/* write the word at location addr in the USER area */
	case PTRACE_POKEUSR: {
		unsigned long index;

		ret = -EIO;
		/* convert to index and check */
		index = (unsigned long) addr >> 2;
		if ((addr & 3) || index > PT_FPSCR
		    || child->thread.regs == NULL)
			break;

		CHECK_FULL_REGS(child->thread.regs);
		if (index == PT_ORIG_R3)
			break;
		if (index < PT_FPR0) {
			ret = put_reg(child, index, data);
		} else {
			preempt_disable();
			if (child->thread.regs->msr & MSR_FP)
				giveup_fpu(child);
			preempt_enable();
			((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
			ret = 0;
		}
		break;
	}

	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
	case PTRACE_CONT: { /* restart after signal. */
		ret = -EIO;
		if (!valid_signal(data))
			break;
		if (request == PTRACE_SYSCALL) {
			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		} else {
			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		}
		child->exit_code = data;
		/* make sure the single step bit is not set. */
		clear_single_step(child);
		wake_up_process(child);
		ret = 0;
		break;
	}

/*
 * make the child exit.  Best I can do is send it a sigkill.
 * perhaps it should be put in the status that it wants to
 * exit.
 */
	case PTRACE_KILL: {
		ret = 0;
		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
			break;
		child->exit_code = SIGKILL;
		/* make sure the single step bit is not set. */
		clear_single_step(child);
		wake_up_process(child);
		break;
	}

	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
		ret = -EIO;
		if (!valid_signal(data))
			break;
		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		set_single_step(child);
		child->exit_code = data;
		/* give it a chance to run. */
		wake_up_process(child);
		ret = 0;
		break;
	}

	case PTRACE_DETACH:
		ret = ptrace_detach(child, data);
		break;

#ifdef CONFIG_ALTIVEC
	case PTRACE_GETVRREGS:
		/* Get the child altivec register state. */
		preempt_disable();
		if (child->thread.regs->msr & MSR_VEC)
			giveup_altivec(child);
		preempt_enable();
		ret = get_vrregs((unsigned long __user *)data, child);
		break;

	case PTRACE_SETVRREGS:
		/* Set the child altivec register state. */
		/* this is to clear the MSR_VEC bit to force a reload
		 * of register state from memory */
		preempt_disable();
		if (child->thread.regs->msr & MSR_VEC)
			giveup_altivec(child);
		preempt_enable();
		ret = set_vrregs(child, (unsigned long __user *)data);
		break;
#endif
#ifdef CONFIG_SPE
	case PTRACE_GETEVRREGS:
		/* Get the child spe register state. */
		if (child->thread.regs->msr & MSR_SPE)
			giveup_spe(child);
		ret = get_evrregs((unsigned long __user *)data, child);
		break;

	case PTRACE_SETEVRREGS:
		/* Set the child spe register state. */
		/* this is to clear the MSR_SPE bit to force a reload
		 * of register state from memory */
		if (child->thread.regs->msr & MSR_SPE)
			giveup_spe(child);
		ret = set_evrregs(child, (unsigned long __user *)data);
		break;
#endif

	default:
		ret = ptrace_request(child, request, addr, data);
		break;
	}
out_tsk:
	put_task_struct(child);
out:
	unlock_kernel();
	return ret;
}