]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/coredump.c
dbus: better don't expose options we better shouldn't exposed
[thirdparty/systemd.git] / src / journal / coredump.c
CommitLineData
f5e04665
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2012 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
f5e04665
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
f5e04665 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
f5e04665
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
23#include <unistd.h>
803a3464
LP
24#include <stdio.h>
25#include <sys/prctl.h>
f5e04665
LP
26
27#include <systemd/sd-journal.h>
28#include <systemd/sd-login.h>
29
30#include "log.h"
31#include "util.h"
49e942b2 32#include "mkdir.h"
803a3464 33#include "special.h"
f5e04665 34
de0229ca 35#define COREDUMP_MAX (24*1024*1024)
f5e04665
LP
36
37enum {
38 ARG_PID = 1,
39 ARG_UID,
40 ARG_GID,
41 ARG_SIGNAL,
42 ARG_TIMESTAMP,
43 ARG_COMM,
44 _ARG_MAX
45};
46
803a3464
LP
47static int divert_coredump(void) {
48 FILE *f;
49 int r;
50
51 log_info("Detected coredump of the journal daemon itself, diverting coredump to /var/lib/systemd/coredump/.");
52
53 mkdir_p("/var/lib/systemd/coredump", 0755);
54
55 f = fopen("/var/lib/systemd/coredump/core.systemd-journald", "we");
56 if (!f) {
57 log_error("Failed to create coredump file: %m");
58 return -errno;
59 }
60
61 for (;;) {
62 uint8_t buffer[4096];
63 size_t l, q;
64
65 l = fread(buffer, 1, sizeof(buffer), stdin);
66 if (l <= 0) {
67 if (ferror(f)) {
68 log_error("Failed to read coredump: %m");
69 r = -errno;
70 goto finish;
71 }
72
73 r = 0;
74 break;
75 }
76
77 q = fwrite(buffer, 1, l, f);
78 if (q != l) {
79 log_error("Failed to write coredump: %m");
80 r = -errno;
81 goto finish;
82 }
83 }
84
85 fflush(f);
86
87 if (ferror(f)) {
88 log_error("Failed to write coredump: %m");
89 r = -errno;
90 }
91
92finish:
93 fclose(f);
94 return r;
95}
96
f5e04665
LP
97int main(int argc, char* argv[]) {
98 int r, j = 0;
99 char *p = NULL;
100 ssize_t n;
101 pid_t pid;
fee80f69
LP
102 uid_t uid;
103 gid_t gid;
f5e04665
LP
104 struct iovec iovec[14];
105 char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
106 *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
107 *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *t;
108
803a3464 109 prctl(PR_SET_DUMPABLE, 0);
f5e04665
LP
110
111 if (argc != _ARG_MAX) {
803a3464
LP
112 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
113 log_open();
114
f5e04665
LP
115 log_error("Invalid number of arguments passed from kernel.");
116 r = -EINVAL;
117 goto finish;
118 }
119
120 r = parse_pid(argv[ARG_PID], &pid);
121 if (r < 0) {
803a3464
LP
122 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
123 log_open();
124
f5e04665 125 log_error("Failed to parse PID.");
f5e04665
LP
126 goto finish;
127 }
128
803a3464
LP
129 if (sd_pid_get_unit(pid, &t) >= 0) {
130
131 if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
132 /* Make sure we don't make use of the journal,
133 * if it's the journal which is crashing */
134 log_set_target(LOG_TARGET_KMSG);
135 log_open();
136
137 r = divert_coredump();
138 goto finish;
139 }
140
141 core_unit = strappend("COREDUMP_UNIT=", t);
142 free(t);
143
144 if (core_unit)
145 IOVEC_SET_STRING(iovec[j++], core_unit);
146 }
147
148 /* OK, now we know it's not the journal, hence make use of
149 * it */
150 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
151 log_open();
152
fee80f69
LP
153 r = parse_uid(argv[ARG_UID], &uid);
154 if (r < 0) {
155 log_error("Failed to parse UID.");
f5e04665
LP
156 goto finish;
157 }
158
fee80f69
LP
159 r = parse_gid(argv[ARG_GID], &gid);
160 if (r < 0) {
161 log_error("Failed to parse GID.");
f5e04665
LP
162 goto finish;
163 }
164
f5e04665
LP
165 core_pid = strappend("COREDUMP_PID=", argv[ARG_PID]);
166 if (core_pid)
167 IOVEC_SET_STRING(iovec[j++], core_pid);
168
169 core_uid = strappend("COREDUMP_UID=", argv[ARG_UID]);
170 if (core_uid)
171 IOVEC_SET_STRING(iovec[j++], core_uid);
172
173 core_gid = strappend("COREDUMP_GID=", argv[ARG_GID]);
174 if (core_gid)
175 IOVEC_SET_STRING(iovec[j++], core_gid);
176
177 core_signal = strappend("COREDUMP_SIGNAL=", argv[ARG_SIGNAL]);
178 if (core_signal)
179 IOVEC_SET_STRING(iovec[j++], core_signal);
180
181 core_comm = strappend("COREDUMP_COMM=", argv[ARG_COMM]);
182 if (core_comm)
183 IOVEC_SET_STRING(iovec[j++], core_comm);
184
185 if (sd_pid_get_session(pid, &t) >= 0) {
186 core_session = strappend("COREDUMP_SESSION=", t);
187 free(t);
188
189 if (core_session)
190 IOVEC_SET_STRING(iovec[j++], core_session);
191 }
192
f5e04665
LP
193 if (get_process_exe(pid, &t) >= 0) {
194 core_exe = strappend("COREDUMP_EXE=", t);
195 free(t);
196
197 if (core_exe)
198 IOVEC_SET_STRING(iovec[j++], core_exe);
199 }
200
201 if (get_process_cmdline(pid, LINE_MAX, false, &t) >= 0) {
202 core_cmdline = strappend("COREDUMP_CMDLINE=", t);
203 free(t);
204
205 if (core_cmdline)
206 IOVEC_SET_STRING(iovec[j++], core_cmdline);
207 }
208
209 core_timestamp = join("COREDUMP_TIMESTAMP=", argv[ARG_TIMESTAMP], "000000", NULL);
210 if (core_timestamp)
211 IOVEC_SET_STRING(iovec[j++], core_timestamp);
212
213 IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
214 IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
215
216 core_message = join("MESSAGE=Process ", argv[ARG_PID], " (", argv[ARG_COMM], ") dumped core.", NULL);
217 if (core_message)
218 IOVEC_SET_STRING(iovec[j++], core_message);
219
fee80f69
LP
220 /* Now, let's drop privileges to become the user who owns the
221 * segfaulted process and allocate the coredump memory under
222 * his uid. This also ensures that the credentials journald
223 * will see are the ones of the coredumping user, thus making
224 * sure the user himself gets access to the core dump. */
225
226 if (setresgid(gid, gid, gid) < 0 ||
227 setresuid(uid, uid, uid) < 0) {
228 log_error("Failed to drop privileges: %m");
229 r = -errno;
230 goto finish;
231 }
232
233 p = malloc(9 + COREDUMP_MAX);
234 if (!p) {
235 log_error("Out of memory");
236 r = -ENOMEM;
237 goto finish;
238 }
239
240 memcpy(p, "COREDUMP=", 9);
241
242 n = loop_read(STDIN_FILENO, p + 9, COREDUMP_MAX, false);
243 if (n < 0) {
244 log_error("Failed to read core dump data: %s", strerror(-n));
245 r = (int) n;
246 goto finish;
247 }
248
249 iovec[j].iov_base = p;
250 iovec[j].iov_len = 9 + n;
251 j++;
252
f5e04665
LP
253 r = sd_journal_sendv(iovec, j);
254 if (r < 0)
255 log_error("Failed to send coredump: %s", strerror(-r));
256
257finish:
258 free(p);
259 free(core_pid);
260 free(core_uid);
261 free(core_gid);
262 free(core_signal);
263 free(core_timestamp);
264 free(core_comm);
265 free(core_exe);
266 free(core_cmdline);
267 free(core_unit);
268 free(core_session);
269 free(core_message);
270
271 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
272}