unbreak, deprivilege dumpcore(1)
This commit is contained in:
parent
e423c86009
commit
0bafee3d78
|
|
@ -363,7 +363,7 @@ du: du.c
|
||||||
@install -S 256kw $@
|
@install -S 256kw $@
|
||||||
|
|
||||||
dumpcore: dumpcore.c
|
dumpcore: dumpcore.c
|
||||||
$(CCLD) -D_SYSTEM=1 -o $@ $< -lsys
|
$(CCLD) -o $@ $<
|
||||||
@install -S 32k $@
|
@install -S 32k $@
|
||||||
|
|
||||||
ed: ed.c
|
ed: ed.c
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,14 @@
|
||||||
|
/* dumpcore - create core file of running process */
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <assert.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <minix/config.h>
|
#include <minix/config.h>
|
||||||
#include <minix/type.h>
|
#include <minix/type.h>
|
||||||
#include <minix/callnr.h>
|
#include <minix/ipc.h>
|
||||||
#include <minix/safecopies.h>
|
|
||||||
#include <minix/endpoint.h>
|
|
||||||
#include <minix/com.h>
|
|
||||||
#include <minix/syslib.h>
|
|
||||||
#include <minix/const.h>
|
#include <minix/const.h>
|
||||||
#include <sys/ptrace.h>
|
#include <sys/ptrace.h>
|
||||||
#include <sys/svrctl.h>
|
#include <sys/wait.h>
|
||||||
#include <dirent.h>
|
#include <signal.h>
|
||||||
#include <timers.h>
|
#include <timers.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
@ -20,33 +16,82 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "../../kernel/arch/i386/include/archtypes.h"
|
#include "../../kernel/arch/i386/include/archtypes.h"
|
||||||
#include "../../kernel/const.h"
|
|
||||||
#include "../../kernel/type.h"
|
|
||||||
#include "../../kernel/config.h"
|
|
||||||
#include "../../kernel/debug.h"
|
|
||||||
#include "../../kernel/proc.h"
|
#include "../../kernel/proc.h"
|
||||||
#include "../../kernel/ipc.h"
|
|
||||||
|
|
||||||
#define SLOTS (NR_TASKS + NR_PROCS)
|
#define CLICK_WORDS (CLICK_SIZE / sizeof(unsigned long))
|
||||||
struct proc proc[SLOTS];
|
|
||||||
|
|
||||||
|
int adjust_stack(pid_t pid, struct mem_map *seg)
|
||||||
int write_seg(int fd, off_t off, endpoint_t proc_e, int seg,
|
|
||||||
off_t seg_off, phys_bytes seg_bytes)
|
|
||||||
{
|
{
|
||||||
int r, block_size, fl;
|
static unsigned long buf[CLICK_WORDS];
|
||||||
off_t n, o, b_off;
|
struct ptrace_range pr;
|
||||||
block_t b;
|
size_t off, top, bottom;
|
||||||
struct buf *bp;
|
int i;
|
||||||
ssize_t w;
|
|
||||||
static char buf[1024];
|
|
||||||
|
|
||||||
for (o= seg_off; o < seg_off+seg_bytes; o += sizeof(buf))
|
/* FIXME: kernel/VM strangeness */
|
||||||
|
seg->mem_vir -= seg->mem_len - 1;
|
||||||
|
|
||||||
|
/* Scan the stack, top to bottom, to find the lowest accessible region.
|
||||||
|
* In practice that will be at 64MB, so we also scan for the lowest non-zero
|
||||||
|
* region in order to keep the core file size managable.
|
||||||
|
* Portability note: this code assumes that the stack grows down.
|
||||||
|
*/
|
||||||
|
top = seg->mem_vir + seg->mem_len;
|
||||||
|
|
||||||
|
pr.pr_space = TS_DATA;
|
||||||
|
pr.pr_addr = (top - 1) << CLICK_SHIFT;
|
||||||
|
pr.pr_size = sizeof(buf);
|
||||||
|
pr.pr_ptr = buf;
|
||||||
|
|
||||||
|
for (off = top - 1; off >= seg->mem_vir; off--) {
|
||||||
|
if (ptrace(T_GETRANGE, pid, (long) &pr, 0)) {
|
||||||
|
if (errno == EFAULT)
|
||||||
|
break;
|
||||||
|
|
||||||
|
perror("ptrace(T_GETRANGE)");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < CLICK_WORDS; i += sizeof(buf[0]))
|
||||||
|
if (buf[i] != 0)
|
||||||
|
bottom = off;
|
||||||
|
|
||||||
|
pr.pr_addr -= sizeof(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add one extra zero page as margin. */
|
||||||
|
if (bottom > off && bottom > seg->mem_vir)
|
||||||
|
bottom--;
|
||||||
|
|
||||||
|
seg->mem_len -= bottom - seg->mem_vir;
|
||||||
|
seg->mem_vir = bottom;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int write_seg(int fd, pid_t pid, int seg, off_t seg_off, phys_bytes seg_bytes)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
off_t off;
|
||||||
|
ssize_t w;
|
||||||
|
static char buf[CLICK_SIZE];
|
||||||
|
struct ptrace_range pr;
|
||||||
|
|
||||||
|
pr.pr_space = (seg == T) ? TS_INS : TS_DATA;
|
||||||
|
pr.pr_addr = seg_off;
|
||||||
|
pr.pr_size = sizeof(buf);
|
||||||
|
pr.pr_ptr = buf;
|
||||||
|
|
||||||
|
for ( ; pr.pr_addr < seg_off + seg_bytes; pr.pr_addr += sizeof(buf))
|
||||||
{
|
{
|
||||||
/* Copy a chunk from user space to the block buffer. */
|
/* Copy a chunk from user space to the block buffer. */
|
||||||
if(sys_vircopy(proc_e, seg, (phys_bytes) o,
|
if (ptrace(T_GETRANGE, pid, (long) &pr, 0)) {
|
||||||
SELF, D, (vir_bytes) buf, (phys_bytes) sizeof(buf)) != OK) {
|
/* Create holes for inaccessible areas. */
|
||||||
printf("write_seg: sys_vircopy failed\n");
|
if (errno == EFAULT) {
|
||||||
|
lseek(fd, sizeof(buf), SEEK_CUR);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
perror("ptrace(T_GETRANGE)");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,111 +102,135 @@ int write_seg(int fd, off_t off, endpoint_t proc_e, int seg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int dumpcore(pid_t pid)
|
||||||
int dumpcore(endpoint_t proc_e)
|
|
||||||
{
|
{
|
||||||
int r, seg, exists, fd;
|
int r, seg, fd;
|
||||||
mode_t omode;
|
|
||||||
vir_bytes len;
|
vir_bytes len;
|
||||||
off_t off, seg_off;
|
off_t off, seg_off;
|
||||||
long trace_off, trace_data;
|
long data;
|
||||||
struct mem_map segs[NR_LOCAL_SEGS];
|
struct mem_map segs[NR_LOCAL_SEGS];
|
||||||
struct proc procentry;
|
struct proc procentry;
|
||||||
int proc_s;
|
|
||||||
ssize_t w;
|
ssize_t w;
|
||||||
char core_name[200];
|
char core_name[PATH_MAX];
|
||||||
|
|
||||||
if(sys_getproctab(proc) != OK) {
|
/* Get the process table entry for this process. */
|
||||||
printf( "Couldn't get proc tab.\n");
|
len = sizeof(struct proc) / sizeof(long);
|
||||||
|
for (off = 0; off < len; off++)
|
||||||
|
{
|
||||||
|
errno = 0;
|
||||||
|
data = ptrace(T_GETUSER, pid, off * sizeof(long), 0);
|
||||||
|
if (data == -1 && errno != 0)
|
||||||
|
{
|
||||||
|
perror("ptrace(T_GETUSER)");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
((long *) &procentry)[off] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(segs, procentry.p_memmap, sizeof(segs));
|
||||||
|
|
||||||
|
/* Correct and reduce the stack segment. */
|
||||||
|
r = adjust_stack(pid, &segs[S]);
|
||||||
|
if (r != 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Create a core file with a temporary, unique name. */
|
||||||
|
sprintf(core_name, "core.%d", pid);
|
||||||
|
|
||||||
|
if((fd = open(core_name, O_CREAT|O_EXCL|O_WRONLY, 0600)) < 0) {
|
||||||
|
fprintf(stderr, "couldn't open %s (%s)\n", core_name,
|
||||||
|
strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(proc_s = 0; proc_s < SLOTS; proc_s++)
|
/* Write out the process's segments. */
|
||||||
if(proc[proc_s].p_endpoint == proc_e &&
|
|
||||||
!isemptyp(&proc[proc_s]))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if(proc_s >= SLOTS) {
|
|
||||||
printf( "endpoint %d not found.\n", proc_e);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(proc_s < 0 || proc_s >= SLOTS) {
|
|
||||||
printf( "Slot out of range (internal error).\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isemptyp(&proc[proc_s])) {
|
|
||||||
printf( "slot %d is no process (internal error).\n",
|
|
||||||
proc_s);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(core_name, "/tmp/core.%d", proc_e);
|
|
||||||
|
|
||||||
if((fd = open(core_name,
|
|
||||||
O_CREAT|O_WRONLY|O_EXCL|O_NONBLOCK, 0600)) < 0) {
|
|
||||||
printf("couldn't open %s (%s)\n",
|
|
||||||
core_name, strerror(errno));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
proc[proc_s].p_name[P_NAME_LEN-1] = '\0';
|
|
||||||
|
|
||||||
memcpy(segs, proc[proc_s].p_memmap, sizeof(segs));
|
|
||||||
|
|
||||||
off= 0;
|
|
||||||
if((w=write(fd, segs, sizeof(segs))) != sizeof(segs)) {
|
if((w=write(fd, segs, sizeof(segs))) != sizeof(segs)) {
|
||||||
if(w < 0) printf("write error: %s\n", strerror(errno));
|
if(w < 0) printf("write error: %s\n", strerror(errno));
|
||||||
printf( "segs write failed: %d/%d\n", w, sizeof(segs));
|
printf( "segs write failed: %d/%d\n", w, sizeof(segs));
|
||||||
return 1;
|
goto error;
|
||||||
}
|
}
|
||||||
off += sizeof(segs);
|
|
||||||
|
|
||||||
/* Write out the whole kernel process table entry to get the regs. */
|
/* Write out the whole kernel process table entry to get the regs. */
|
||||||
for (trace_off= 0;; trace_off += sizeof(long))
|
if((w=write(fd, &procentry, sizeof(procentry))) != sizeof(procentry)) {
|
||||||
{
|
if(w < 0) printf("write error: %s\n", strerror(errno));
|
||||||
r= sys_trace(T_GETUSER, proc_e, trace_off, &trace_data);
|
printf( "proc write failed: %d/%d\n", w, sizeof(procentry));
|
||||||
if (r != OK)
|
goto error;
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
r= write(fd, &trace_data, sizeof(trace_data));
|
|
||||||
if (r != sizeof(trace_data)) {
|
|
||||||
printf( "trace_data write failed\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
off += sizeof(trace_data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop through segments and write the segments themselves out. */
|
/* Loop through segments and write the segments themselves out. */
|
||||||
for (seg = 0; seg < NR_LOCAL_SEGS; seg++) {
|
for (seg = 0; seg < NR_LOCAL_SEGS; seg++) {
|
||||||
len= segs[seg].mem_len << CLICK_SHIFT;
|
len= segs[seg].mem_len << CLICK_SHIFT;
|
||||||
seg_off= segs[seg].mem_vir << CLICK_SHIFT;
|
seg_off= segs[seg].mem_vir << CLICK_SHIFT;
|
||||||
r= write_seg(fd, off, proc_e, seg, seg_off, len);
|
r= write_seg(fd, pid, seg, seg_off, len);
|
||||||
if (r != OK)
|
if (r != 0)
|
||||||
{
|
goto error;
|
||||||
printf( "write failed\n");
|
}
|
||||||
return 1;
|
|
||||||
}
|
/* Give the core file its final name. */
|
||||||
off += len;
|
if (rename(core_name, "core")) {
|
||||||
|
perror("rename");
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
main(int argc, char *argv[])
|
error:
|
||||||
{
|
close(fd);
|
||||||
if(argc != 2) {
|
|
||||||
printf("usage: %s <endpoint>\n", argv[0]);
|
unlink(core_name);
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
dumpcore(atoi(argv[1]));
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
int r, status;
|
||||||
|
|
||||||
|
if(argc != 2) {
|
||||||
|
printf("usage: %s <pid>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pid = atoi(argv[1]);
|
||||||
|
|
||||||
|
if (ptrace(T_ATTACH, pid, 0, 0) != 0) {
|
||||||
|
perror("ptrace(T_ATTACH)");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (waitpid(pid, &status, 0) != pid) {
|
||||||
|
perror("waitpid");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (WIFSTOPPED(status) && WSTOPSIG(status) != SIGSTOP) {
|
||||||
|
/* whatever happens here is fine */
|
||||||
|
ptrace(T_RESUME, pid, 0, WSTOPSIG(status));
|
||||||
|
|
||||||
|
if (waitpid(pid, &status, 0) != pid) {
|
||||||
|
perror("waitpid");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WIFSTOPPED(status)) {
|
||||||
|
fprintf(stderr, "process died while attaching\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = dumpcore(pid);
|
||||||
|
|
||||||
|
if (ptrace(T_DETACH, pid, 0, 0)) {
|
||||||
|
fprintf(stderr, "warning, detaching failed (%s)\n",
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -142,19 +142,6 @@ service fxp
|
||||||
;
|
;
|
||||||
};
|
};
|
||||||
|
|
||||||
service dumpcore
|
|
||||||
{
|
|
||||||
system
|
|
||||||
TRACE # 5
|
|
||||||
VIRCOPY # 15
|
|
||||||
TIMES # 25
|
|
||||||
GETINFO # 26
|
|
||||||
SETGRANT # 34
|
|
||||||
PROFBUF # 38
|
|
||||||
SYSCTL # 44
|
|
||||||
;
|
|
||||||
};
|
|
||||||
|
|
||||||
service inet
|
service inet
|
||||||
{
|
{
|
||||||
system
|
system
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
.SH NAME
|
.SH NAME
|
||||||
dumpcore \- generate core file of running process
|
dumpcore \- generate core file of running process
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
service run /usr/bin/dumpcore -args \fIendpoint\fR
|
dumpcore \fIpid\fR
|
||||||
.br
|
.br
|
||||||
.de FL
|
.de FL
|
||||||
.TP
|
.TP
|
||||||
|
|
@ -15,12 +15,15 @@ service run /usr/bin/dumpcore -args \fIendpoint\fR
|
||||||
# \\$2
|
# \\$2
|
||||||
..
|
..
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
\fIDumpcore\fR executes the same code that FS executes in order to
|
The \fBdumpcore\fR utility generates a core file for a running process, based
|
||||||
generate a core dump of a currently running process, identified by
|
on that process's process ID (\fIpid\fP). The resulting core file will be
|
||||||
endpoint number. Obtain an endpoint number by using the F1 debug
|
stored under the name "core" in the current working directory. Any previous
|
||||||
dump, or ps with -E option.
|
file with that name will be overwritten.
|
||||||
|
.PP
|
||||||
|
The resulting core file can be used with for example
|
||||||
|
.BR mdb (1).
|
||||||
.SH BUGS
|
.SH BUGS
|
||||||
\fIDumpcore\fR has duplicate code with FS, and has to be started with
|
The process of generating the core file is currently very rudimentary, and
|
||||||
the service command.
|
the generated core file does not contain for example memory mapped areas.
|
||||||
.SH "SEE ALSO"
|
.SH "SEE ALSO"
|
||||||
.BR ps (1).
|
.BR mdb (1).
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user