kern_core.c revision 1.1.2.1 1 /* $NetBSD: kern_core.c,v 1.1.2.1 2006/10/21 14:26:41 ad Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1986, 1989, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 * (c) UNIX System Laboratories, Inc.
7 * All or some portions of this file are derived from material licensed
8 * to the University of California by American Telephone and Telegraph
9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10 * the permission of UNIX System Laboratories, Inc.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)kern_sig.c 8.14 (Berkeley) 5/14/95
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: kern_core.c,v 1.1.2.1 2006/10/21 14:26:41 ad Exp $");
41
42 #include "opt_coredump.h"
43
44 #include <sys/param.h>
45 #include <sys/vnode.h>
46 #include <sys/namei.h>
47 #include <sys/acct.h>
48 #include <sys/file.h>
49 #include <sys/stat.h>
50 #include <sys/proc.h>
51 #include <sys/exec.h>
52 #include <sys/filedesc.h>
53
54 #if !defined(COREDUMP)
55
56 int
57 coredump(struct lwp *l, const char *pattern)
58 {
59
60 return (ENOSYS);
61 }
62
63 #else /* COREDUMP */
64
65 struct coredump_iostate {
66 struct lwp *io_lwp;
67 struct vnode *io_vp;
68 kauth_cred_t io_cred;
69 off_t io_offset;
70 };
71
72 static int coredump_buildname(struct proc *, char *, const char *, size_t);
73
74 /*
75 * Dump core, into a file named "progname.core" or "core" (depending on the
76 * value of shortcorename), unless the process was setuid/setgid.
77 */
78 int
79 coredump(struct lwp *l, const char *pattern)
80 {
81 struct vnode *vp;
82 struct proc *p;
83 struct vmspace *vm;
84 kauth_cred_t cred;
85 struct nameidata nd;
86 struct vattr vattr;
87 struct mount *mp;
88 struct coredump_iostate io;
89 int error, error1;
90 char *name = NULL;
91
92 p = l->l_proc;
93 vm = p->p_vmspace;
94 cred = l->l_cred;
95
96 /*
97 * Make sure the process has not set-id, to prevent data leaks,
98 * unless it was specifically requested to allow set-id coredumps.
99 */
100 if ((p->p_flag & P_SUGID) && !security_setidcore_dump)
101 return EPERM;
102
103 /*
104 * Refuse to core if the data + stack + user size is larger than
105 * the core dump limit. XXX THIS IS WRONG, because of mapped
106 * data.
107 */
108 if (USPACE + ctob(vm->vm_dsize + vm->vm_ssize) >=
109 p->p_rlimit[RLIMIT_CORE].rlim_cur)
110 return EFBIG; /* better error code? */
111
112 restart:
113 /*
114 * The core dump will go in the current working directory. Make
115 * sure that the directory is still there and that the mount flags
116 * allow us to write core dumps there.
117 */
118 vp = p->p_cwdi->cwdi_cdir;
119 if (vp->v_mount == NULL ||
120 (vp->v_mount->mnt_flag & MNT_NOCOREDUMP) != 0) {
121 error = EPERM;
122 goto done;
123 }
124
125 if ((p->p_flag & P_SUGID) && security_setidcore_dump)
126 pattern = security_setidcore_path;
127
128 if (pattern == NULL)
129 pattern = p->p_limit->pl_corename;
130 if (name == NULL) {
131 name = PNBUF_GET();
132 }
133 if ((error = coredump_buildname(p, name, pattern, MAXPATHLEN)) != 0)
134 goto done;
135 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, name, l);
136 if ((error = vn_open(&nd, O_CREAT | O_NOFOLLOW | FWRITE,
137 S_IRUSR | S_IWUSR)) != 0)
138 goto done;
139 vp = nd.ni_vp;
140
141 if (vn_start_write(vp, &mp, V_NOWAIT) != 0) {
142 VOP_UNLOCK(vp, 0);
143 if ((error = vn_close(vp, FWRITE, cred, l)) != 0)
144 goto done;
145 if ((error = vn_start_write(NULL, &mp,
146 V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
147 goto done;
148 goto restart;
149 }
150
151 /* Don't dump to non-regular files or files with links. */
152 if (vp->v_type != VREG ||
153 VOP_GETATTR(vp, &vattr, cred, l) || vattr.va_nlink != 1) {
154 error = EINVAL;
155 goto out;
156 }
157 VATTR_NULL(&vattr);
158 vattr.va_size = 0;
159
160 if ((p->p_flag & P_SUGID) && security_setidcore_dump) {
161 vattr.va_uid = security_setidcore_owner;
162 vattr.va_gid = security_setidcore_group;
163 vattr.va_mode = security_setidcore_mode;
164 }
165
166 VOP_LEASE(vp, l, cred, LEASE_WRITE);
167 VOP_SETATTR(vp, &vattr, cred, l);
168 p->p_acflag |= ACORE;
169
170 io.io_lwp = l;
171 io.io_vp = vp;
172 io.io_cred = cred;
173 io.io_offset = 0;
174
175 /* Now dump the actual core file. */
176 error = (*p->p_execsw->es_coredump)(l, &io);
177 out:
178 VOP_UNLOCK(vp, 0);
179 vn_finished_write(mp, 0);
180 error1 = vn_close(vp, FWRITE, cred, l);
181 if (error == 0)
182 error = error1;
183 done:
184 if (name != NULL)
185 PNBUF_PUT(name);
186 return error;
187 }
188
189 static int
190 coredump_buildname(struct proc *p, char *dst, const char *src, size_t len)
191 {
192 const char *s;
193 char *d, *end;
194 int i;
195
196 for (s = src, d = dst, end = d + len; *s != '\0'; s++) {
197 if (*s == '%') {
198 switch (*(s + 1)) {
199 case 'n':
200 i = snprintf(d, end - d, "%s", p->p_comm);
201 break;
202 case 'p':
203 i = snprintf(d, end - d, "%d", p->p_pid);
204 break;
205 case 'u':
206 i = snprintf(d, end - d, "%.*s",
207 (int)sizeof p->p_pgrp->pg_session->s_login,
208 p->p_pgrp->pg_session->s_login);
209 break;
210 case 't':
211 i = snprintf(d, end - d, "%ld",
212 p->p_stats->p_start.tv_sec);
213 break;
214 default:
215 goto copy;
216 }
217 d += i;
218 s++;
219 } else {
220 copy: *d = *s;
221 d++;
222 }
223 if (d >= end)
224 return (ENAMETOOLONG);
225 }
226 *d = '\0';
227 return 0;
228 }
229
230 int
231 coredump_write(void *cookie, enum uio_seg segflg, const void *data, size_t len)
232 {
233 struct coredump_iostate *io = cookie;
234 int error;
235
236 error = vn_rdwr(UIO_WRITE, io->io_vp, __UNCONST(data), len,
237 io->io_offset, segflg,
238 IO_NODELOCKED|IO_UNIT, io->io_cred, NULL,
239 segflg == UIO_USERSPACE ? io->io_lwp : NULL);
240 if (error) {
241 printf("pid %d (%s): %s write of %zu@%p at %lld failed: %d\n",
242 io->io_lwp->l_proc->p_pid, io->io_lwp->l_proc->p_comm,
243 segflg == UIO_USERSPACE ? "user" : "system",
244 len, data, (long long) io->io_offset, error);
245 return (error);
246 }
247
248 io->io_offset += len;
249 return (0);
250 }
251
252 #endif /* COREDUMP */
253