Example #1
0
/*
 * long ptrace(enum request, int pid, void* addr, void* data)
 */
void SysCalls::sys_ptrace(CONTEXT& ctx)
{
	int request = ctx.Ebx;
	int pid = ctx.Ecx;
	void* addr = (void*)ctx.Edx;
	void* data = (void*)ctx.Esi;

	Process * pTraced = g_pKernelTable->FindProcess(pid);

	//TODO: what does ptrace on a process with threads actually do?
	ThreadInfo * pTracedThread = pTraced->m_ThreadList[0];

	switch(request)
	{
	case linux::PTRACE_TRACEME:
		ktrace("ptrace PTRACE_TRACEME\n");
		P->m_ptrace.OwnerPid = P->m_ParentPid;
		P->m_ptrace.Request = linux::PTRACE_TRACEME;
		ctx.Eax = 0;
		break;

	case linux::PTRACE_SYSCALL:
		{
			ktrace("ptrace PTRACE_SYSCALL pid %d\n", pid);
			pTraced->m_ptrace.Request = linux::PTRACE_SYSCALL;
			if((int)data!=0 && (int)data!=linux::SIGSTOP)
				pTraced->m_ptrace.new_signal = (int)data;
			ktrace("ptrace_syscall resuming pid %d\n",pid);
			ResumeThread(pTraced->m_KernelThreadHandle); //kernel handler thread is paused when using ptrace
			ctx.Eax = 0;
		}
		break;

	case linux::PTRACE_CONT:
		{
			ktrace("ptrace PTRACE_CONT pid %d\n", pid);
			pTraced->m_ptrace.Request = 0;
			if((int)data!=0 && (int)data!=linux::SIGSTOP)
				pTraced->m_ptrace.new_signal = (int)data;
			ktrace("ptrace_cont resuming pid %d\n",pid);
			ResumeThread(pTraced->m_KernelThreadHandle); //kernel handler thread is paused when using ptrace
			ctx.Eax = 0;
		}
		break;

	case linux::PTRACE_PEEKUSR:
		{
			ktrace("ptrace PTRACE_PEEKUSR pid %d addr 0x%lx (reg %ld) data 0x%08lx\n", pid, addr, (DWORD)addr>>2, data);

			if((unsigned long)addr > sizeof(linux::user)-3)
			{
				ctx.Eax = -linux::EFAULT;
				break;
			}

			//read data at offset 'addr' in the kernel 'user' struct (struct user in asm/user.h)
			//we don't keep one of those so make one here
			CONTEXT *pTracedCtx;
			CONTEXT TempCtx;
			if(pTraced->m_ptrace.ctx_valid)
				pTracedCtx = &pTraced->m_ptrace.ctx; 
			else
			{
				ktrace("peekusr get Traced context\n");
				//it's possible that the traced process has caught a signal and then
				//signalled us, however it's kernel thread has yet to sleep
				//so we do an extra suspend here to get the correct context
				SuspendThread(pTracedThread->hThread);
				TempCtx.ContextFlags = CONTEXT_FULL;
				GetThreadContext(pTracedThread->hThread, &TempCtx);
				ResumeThread(pTracedThread->hThread);
				pTracedCtx = &TempCtx;
			}

			linux::user usr;
			memset(&usr,0,sizeof(usr));
			usr.regs.eax  = pTracedCtx->Eax;
			usr.regs.ebx  = pTracedCtx->Ebx;
			usr.regs.ecx  = pTracedCtx->Ecx;
			usr.regs.edx  = pTracedCtx->Edx;
			usr.regs.esi  = pTracedCtx->Esi;
			usr.regs.edi  = pTracedCtx->Edi;
			usr.regs.ebp  = pTracedCtx->Ebp;
			usr.regs.ds   = (unsigned short)pTracedCtx->SegDs;
			usr.regs.__ds = 0;
			usr.regs.es   = (unsigned short)pTracedCtx->SegEs;
			usr.regs.__es = 0;
			usr.regs.fs   = (unsigned short)pTracedCtx->SegFs;
			usr.regs.__fs = 0;
			usr.regs.gs   = (unsigned short)pTracedCtx->SegGs;
			usr.regs.__gs = 0;
			usr.regs.cs   = (unsigned short)pTracedCtx->SegCs;
			usr.regs.__cs = 0;
			usr.regs.ss   = (unsigned short)pTracedCtx->SegSs;
			usr.regs.__ss = 0;
			usr.regs.orig_eax = pTraced->m_ptrace.Saved_Eax;
			usr.regs.eip  = pTracedCtx->Eip;
			usr.regs.eflags = pTracedCtx->EFlags;
			usr.regs.esp  = pTracedCtx->Esp;
			//usr.signal = SIGTRAP; //man ptrace says parent thinks Traced is in this state

			char * pWanted = ((char*)&usr) + (DWORD)addr;
			DWORD retdata = *((DWORD*)pWanted);
			P->WriteMemory((ADDR)data, sizeof(retdata), &retdata);

			ktrace("ptrace [0x%x]=0x%x eax=0x%x orig_eax=0x%x\n", addr, retdata, usr.regs.eax, usr.regs.orig_eax);

			ctx.Eax = 0;
		}
		break;

	case linux::PTRACE_PEEKTEXT:
	case linux::PTRACE_PEEKDATA:
		{
			ktrace("ptrace PTRACE_PEEKDATA pid %d addr 0x%lx data 0x%08lx\n", pid, addr, data);
			DWORD tmp;
			if(!pTraced->ReadMemory(&tmp, (ADDR)addr, sizeof(tmp)))
			{
				ctx.Eax = -linux::EFAULT;
			}
			else
			{
				P->WriteMemory((ADDR)data, sizeof(tmp), &tmp);
				ctx.Eax = tmp;
				ktrace("ptrace [0x%x]=0x%x\n", addr, tmp);
			}
		}
		break;

	case linux::PTRACE_KILL:
		ktrace("ptrace PTRACE_KILL pid %d \n", pid);
		pTraced->SendSignal(linux::SIGKILL);
		ResumeThread(pTraced->m_KernelThreadHandle); //need to wake kernel handler thread so it can die
		ctx.Eax = 0;
		break;

	default:
		ktrace("IMPLEMENT ptrace request %lx\n", ctx.Ebx);
		ctx.Eax = -linux::ENOSYS;
		break;
	}
}
Example #2
0
/*
 * int kill(pid, sig)
 */
void SysCalls::sys_kill(CONTEXT& ctx)
{
	PID pid = ctx.Ebx;
	unsigned int sig = ctx.Ecx;

	if(sig>=linux::_NSIG)
	{
		ctx.Eax = -linux::EINVAL;
		return;
	}

	//helper: sig 0 allows for error checking on pids. no signal actually sent

	// positive - send to 1 process
	if(pid>0)
	{
		ctx.Eax = -linux::ESRCH;
		Process * pDest = g_pKernelTable->FindProcess(pid);
		if(pDest!=NULL)
		{
			if(sig!=0)
				pDest->SendSignal(sig);
			ctx.Eax = 0;
		}
		return;
	}

	// -1 all processes except init
	if(pid == -1)
	{
		KernelTable::ProcessList::iterator it;
		for(it=g_pKernelTable->m_Processes.begin(); it!=g_pKernelTable->m_Processes.end(); ++it)
		{
			if((*it)->m_Pid != 1)
			{
				if(sig!=0)
					(*it)->SendSignal(sig);
			}
		}
		ctx.Eax = 0;
		return;
	}


	//else send to a process group

	PID pgrp = 0;

	if(pid==0)
		pgrp = P->m_Pid; //our group
	else
		pgrp = -pid; //dest group


	KernelTable::ProcessList::iterator it;
	for(it=g_pKernelTable->m_Processes.begin(); it!=g_pKernelTable->m_Processes.end(); ++it)
	{
		if((*it)->m_Pid != 1
		&& (*it)->m_ProcessGroupPID == pgrp)
		{
			if(sig!=0)
				(*it)->SendSignal(sig);
		}
	}
	ctx.Eax = 0;

#undef DO_SIGNAL

}