]>
Commit | Line | Data |
---|---|---|
a846e9cd MH |
1 | /* -*- linux-c -*- |
2 | * | |
337cd273 | 3 | * staprun.c - SystemTap module loader |
a846e9cd | 4 | * |
ef36f781 | 5 | * Copyright (C) 2005-2014 Red Hat, Inc. |
aa2b3583 | 6 | * |
a846e9cd MH |
7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
e8daaf60 | 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
a846e9cd | 19 | * |
a846e9cd MH |
20 | */ |
21 | ||
d62c7736 FCE |
22 | #define _XOPEN_SOURCE |
23 | #define _BSD_SOURCE | |
c6278d01 | 24 | #define _DEFAULT_SOURCE |
a846e9cd | 25 | #include "staprun.h" |
02311ab4 | 26 | #include "../privilege.h" |
ea15e536 | 27 | #include "../runtime/k_syms.h" |
6bedc77b | 28 | #include <string.h> |
37ddf6e5 | 29 | #include <sys/uio.h> |
df00639d | 30 | #include <glob.h> |
d62c7736 | 31 | #include <time.h> |
34d9471d | 32 | #include <sys/prctl.h> |
9eb83dc6 | 33 | #include <sys/utsname.h> |
5eddf13b | 34 | |
5eddf13b DS |
35 | /* used in dbug, _err and _perr */ |
36 | char *__name__ = "staprun"; | |
37 | ||
38 | extern long delete_module(const char *, unsigned int); | |
39 | ||
37ddf6e5 | 40 | int send_relocations (); |
933e53b0 | 41 | int send_tzinfo (); |
429a4963 | 42 | int send_privilege_credentials (privilege_t user_credentials); |
933e53b0 | 43 | int send_remote_id (); |
37ddf6e5 | 44 | |
cedf63f3 DS |
45 | static int remove_module(const char *name, int verb); |
46 | ||
47 | static int stap_module_inserted = -1; | |
48 | ||
49 | static void term_signal_handler(int signum __attribute ((unused))) | |
50 | { | |
51 | if (stap_module_inserted == 0) { | |
52 | // We have to close the control channel so that | |
53 | // remove_module() can open it back up (which it does | |
54 | // to make sure the module is a systemtap module). | |
55 | close_ctl_channel(); | |
56 | remove_module(modname, 1); | |
57 | free(modname); | |
58 | } | |
59 | _exit(1); | |
60 | } | |
61 | ||
62 | void setup_term_signals(void) | |
63 | { | |
64 | sigset_t s; | |
65 | struct sigaction a; | |
66 | ||
67 | /* blocking all signals while we set things up */ | |
68 | sigfillset(&s); | |
69 | sigprocmask(SIG_SETMASK, &s, NULL); | |
70 | ||
71 | /* handle signals */ | |
72 | memset(&a, 0, sizeof(a)); | |
73 | sigfillset(&a.sa_mask); | |
74 | a.sa_handler = term_signal_handler; | |
75 | sigaction(SIGHUP, &a, NULL); | |
76 | sigaction(SIGINT, &a, NULL); | |
77 | sigaction(SIGTERM, &a, NULL); | |
78 | sigaction(SIGQUIT, &a, NULL); | |
79 | ||
80 | /* unblock all signals */ | |
81 | sigemptyset(&s); | |
82 | sigprocmask(SIG_SETMASK, &s, NULL); | |
83 | } | |
37ddf6e5 | 84 | |
337cd273 | 85 | static int run_as(int exec_p, uid_t uid, gid_t gid, const char *path, char *const argv[]) |
5d65678d | 86 | { |
5eddf13b DS |
87 | pid_t pid; |
88 | int rstatus; | |
5d65678d | 89 | |
6274464e JK |
90 | if (verbose >= 2) { |
91 | int i = 0; | |
11bfd0cc | 92 | eprintf(exec_p ? "execing: ": "spawning: "); |
6274464e | 93 | while (argv[i]) { |
11bfd0cc | 94 | eprintf("%s ", argv[i]); |
6274464e JK |
95 | i++; |
96 | } | |
11bfd0cc | 97 | eprintf("\n"); |
6274464e JK |
98 | } |
99 | ||
337cd273 FCE |
100 | if (exec_p) |
101 | pid = 0; | |
102 | else | |
103 | pid = fork(); | |
104 | ||
105 | if (pid < 0) | |
106 | { | |
107 | _perr("fork"); | |
108 | return -1; | |
109 | } | |
110 | ||
111 | if (pid == 0) /* child process, or exec_p */ | |
112 | { | |
113 | /* Make sure we run as the full user. If we're | |
114 | * switching to a non-root user, this won't allow | |
115 | * that process to switch back to root (since the | |
116 | * original process is setuid). */ | |
117 | if (setresgid (gid, gid, gid) < 0) { | |
118 | _perr("setresgid"); | |
119 | exit(1); | |
120 | } | |
121 | if (setresuid (uid, uid, uid) < 0) { | |
122 | _perr("setresuid"); | |
123 | exit(1); | |
124 | } | |
5eddf13b | 125 | |
337cd273 FCE |
126 | /* Actually run the command. */ |
127 | if (execv(path, argv) < 0) | |
128 | perror(path); | |
129 | _exit(1); | |
130 | } | |
5eddf13b DS |
131 | |
132 | if (waitpid(pid, &rstatus, 0) < 0) | |
337cd273 | 133 | return -1; |
5eddf13b DS |
134 | |
135 | if (WIFEXITED(rstatus)) | |
337cd273 | 136 | return WEXITSTATUS(rstatus); |
5eddf13b DS |
137 | return -1; |
138 | } | |
139 | ||
6274464e JK |
140 | /* |
141 | * Module to be inserted has one or more user-space probes. Make sure | |
142 | * uprobes is enabled. | |
143 | * If /proc/kallsyms lists a symbol in uprobes (e.g. unregister_uprobe), | |
144 | * we're done. | |
145 | * Else try "modprobe uprobes" to load the uprobes module (if any) | |
146 | * built with the kernel. | |
147 | * If that fails, load the uprobes module built in runtime/uprobes. | |
148 | */ | |
149 | static int enable_uprobes(void) | |
150 | { | |
6274464e | 151 | char *argv[10]; |
73dc0c77 | 152 | char runtimeko[2048]; |
a53e79a9 FCE |
153 | int rc; |
154 | ||
155 | /* Formerly, we did a grep /proc/kallsyms search to see if | |
156 | uprobes was already loaded into the kernel. But this is | |
157 | a race waiting to happen. Just try to load the thing. | |
158 | Quietly accept a -EEXIST error. */ | |
6274464e | 159 | |
b7565b41 | 160 | /* NB: don't use /sbin/modprobe, without more env. sanitation. */ |
6274464e | 161 | |
474d17ad DB |
162 | /* Try the specified module or the one from the runtime. */ |
163 | if (uprobes_path) | |
164 | snprintf (runtimeko, sizeof(runtimeko), "%s", uprobes_path); | |
165 | else | |
a53e79a9 FCE |
166 | /* NB: since PR5163, share/runtime/uprobes/uprobes.ko is not built |
167 | by systemtap. */ | |
474d17ad DB |
168 | snprintf (runtimeko, sizeof(runtimeko), "%s/uprobes/uprobes.ko", |
169 | (getenv("SYSTEMTAP_RUNTIME") ?: PKGDATADIR "/runtime")); | |
170 | dbug(2, "Inserting uprobes module from %s.\n", runtimeko); | |
64211010 | 171 | /* This module may be signed, so use insert_module to load it. */ |
64211010 | 172 | argv[0] = NULL; |
a53e79a9 | 173 | |
429a4963 | 174 | rc = insert_module(runtimeko, NULL, argv, assert_uprobes_module_permissions, NULL); |
a53e79a9 FCE |
175 | if ((rc == 0) || /* OK */ |
176 | (rc == -EEXIST)) /* Someone else might have loaded it */ | |
770e94e8 | 177 | return 0; |
73dc0c77 | 178 | |
11bfd0cc | 179 | err("Couldn't insert module '%s': %s\n", runtimeko, moderror(errno)); |
770e94e8 | 180 | return 1; /* failure */ |
6274464e JK |
181 | } |
182 | ||
429a4963 | 183 | static int insert_stap_module(privilege_t *user_credentials) |
6274464e | 184 | { |
a2422e70 | 185 | char special_options[128]; |
710f5084 FCE |
186 | int rc, fips_mode_fd; |
187 | char fips_mode = '0'; | |
188 | char *misc = ""; | |
c94a9cb3 | 189 | |
5ffdc7b0 | 190 | /* Add the _stp_bufsize option. */ |
f2013cc9 | 191 | if (snprintf_chk(special_options, sizeof (special_options), |
5ffdc7b0 | 192 | "_stp_bufsize=%d", buffer_size)) |
6274464e | 193 | return -1; |
a2422e70 | 194 | |
710f5084 FCE |
195 | fips_mode_fd = open("/proc/sys/crypto/fips_enabled", O_RDONLY); |
196 | if (fips_mode_fd >= 0) { | |
197 | char c; | |
198 | rc = read(fips_mode_fd, &c, 1); | |
199 | if (rc == 1) fips_mode = c; | |
200 | close (fips_mode_fd); | |
201 | } | |
202 | ||
203 | /* In FIPS mode, a kernel may panic if given an improperly-signed module. | |
204 | Right now, we have no way of signing them with the kernel build-time keys, | |
205 | so we punt. See also SecureBoot. */ | |
206 | if ((fips_mode != '0') && !getenv("STAP_FIPS_OVERRIDE")) { | |
207 | errno = EPERM; | |
208 | stap_module_inserted = -1; | |
209 | misc = "in FIPS mode "; | |
210 | } else { | |
211 | stap_module_inserted = insert_module(modpath, special_options, | |
212 | modoptions, | |
213 | assert_stap_module_permissions, | |
214 | user_credentials); | |
215 | } | |
a53e79a9 | 216 | if (stap_module_inserted != 0) |
710f5084 | 217 | err("Couldn't insert module %s'%s': %s\n", misc, modpath, moderror(errno)); |
cedf63f3 | 218 | return stap_module_inserted; |
6274464e JK |
219 | } |
220 | ||
b197bf0b MH |
221 | static void remove_all_modules(void) |
222 | { | |
223 | char *base; | |
224 | struct statfs st; | |
225 | struct dirent *d; | |
226 | DIR *moddir; | |
227 | ||
c5f7c84b | 228 | /* NB: nothing to do with PR14245 */ |
b197bf0b MH |
229 | if (statfs("/sys/kernel/debug", &st) == 0 && (int)st.f_type == (int)DEBUGFS_MAGIC) |
230 | base = "/sys/kernel/debug/systemtap"; | |
231 | else | |
232 | base = "/proc/systemtap"; | |
233 | ||
234 | moddir = opendir(base); | |
235 | if (moddir) { | |
236 | while ((d = readdir(moddir))) | |
237 | if (remove_module(d->d_name, 0) == 0) | |
238 | printf("Module %s removed.\n", d->d_name); | |
239 | closedir(moddir); | |
240 | } | |
241 | } | |
242 | ||
243 | static int remove_module(const char *name, int verb) | |
244 | { | |
245 | int ret; | |
246 | dbug(2, "%s\n", name); | |
247 | ||
4870be66 | 248 | #ifdef PR_SET_NAME |
34d9471d FCE |
249 | /* Make self easier to identify in vmcrash images */ |
250 | prctl (PR_SET_NAME, "staprun-d"); | |
4870be66 | 251 | #endif |
34d9471d | 252 | |
c4ca2da6 FCE |
253 | (void) verb; /* XXX: ignore */ |
254 | ||
b197bf0b MH |
255 | if (strcmp(name, "*") == 0) { |
256 | remove_all_modules(); | |
257 | return 0; | |
258 | } | |
259 | ||
b7565b41 FCE |
260 | /* We call init_ctl_channel/close_ctl_channel to check whether |
261 | the module is a systemtap-built one (having the right files), | |
262 | and that it's already unattached (because otherwise it'd EBUSY | |
263 | the opens. */ | |
264 | ret = init_ctl_channel (name, 0); | |
265 | if (ret < 0) { | |
11bfd0cc | 266 | err("'%s' is not a zombie systemtap module.\n", name); |
b7565b41 FCE |
267 | return ret; |
268 | } | |
269 | close_ctl_channel (); | |
b197bf0b MH |
270 | |
271 | dbug(2, "removing module %s\n", name); | |
0f5d597d | 272 | PROBE1(staprun, remove__module, name); |
c4ca2da6 | 273 | ret = delete_module (name, O_NONBLOCK); |
b197bf0b | 274 | if (ret != 0) { |
c4ca2da6 FCE |
275 | /* XXX: maybe we should just accept this, with a |
276 | diagnostic, but without an error. Might it be | |
277 | possible for the same module to be started up just | |
278 | as we're shutting down? */ | |
11bfd0cc | 279 | err("Couldn't remove module '%s': %s.\n", name, strerror(errno)); |
b197bf0b MH |
280 | return 1; |
281 | } | |
282 | ||
283 | dbug(1, "Module %s removed.\n", name); | |
284 | return 0; | |
285 | } | |
5eddf13b | 286 | |
cd125e94 | 287 | |
91872f52 FCE |
288 | /* As per PR13193 & PR1548, some kernels have a buggy |
289 | kprobes-optimization code, which results in BUG/panics in certain | |
290 | circumstances. We turn off kprobes optimization as a conservative | |
291 | measure, unless told otherwise by an environment variable. | |
cd125e94 FCE |
292 | */ |
293 | void disable_kprobes_optimization() | |
294 | { | |
295 | /* Test if the file exists at all. */ | |
296 | const char* proc_kprobes = "/proc/sys/debug/kprobes-optimization"; | |
297 | char prev; | |
298 | int rc, fd; | |
9eb83dc6 FCE |
299 | struct utsname uts; |
300 | ||
ee13a5e0 JS |
301 | /* PR13814; disable this facility for new enough kernels, containing |
302 | * these fix commits: 86b4ce31 46484688 3f33ab1c */ | |
91872f52 FCE |
303 | /* PR15484; whoops, not enough, problem still seen on Debian |
304 | * 3.8.12 kernel. */ | |
305 | if (0 && (uname (&uts) == 0) && (strverscmp (uts.release, "3.4") >= 0)) | |
9eb83dc6 | 306 | return; |
cd125e94 FCE |
307 | |
308 | if (getenv ("STAP_PR13193_OVERRIDE")) | |
309 | return; | |
310 | ||
311 | /* See the initial state; if it's already disabled, we do nothing. */ | |
312 | fd = open (proc_kprobes, O_RDONLY); | |
313 | if (fd < 0) | |
314 | return; | |
315 | rc = read (fd, &prev, sizeof(prev)); | |
316 | (void) close (fd); | |
317 | if (rc < 1 || prev == '0') /* Already disabled or unavailable */ | |
318 | return; | |
319 | ||
320 | fd = open (proc_kprobes, O_WRONLY); | |
321 | if (fd < 0) | |
322 | return; | |
323 | prev = '0'; /* really, next */ | |
324 | rc = write (fd, &prev, sizeof(prev)); | |
325 | (void) close (fd); | |
326 | if (rc == 1) | |
327 | dbug(1, "Disabled %s.\n", proc_kprobes); | |
328 | else | |
329 | dbug(1, "Error %d/%d disabling %s.\n", rc, errno, proc_kprobes); | |
330 | } | |
331 | ||
332 | ||
5eddf13b DS |
333 | int init_staprun(void) |
334 | { | |
3c10a1be | 335 | privilege_t user_credentials = pr_unknown; |
5ffdc7b0 | 336 | int rc; |
5eddf13b DS |
337 | dbug(2, "init_staprun\n"); |
338 | ||
339 | if (mountfs() < 0) | |
340 | return -1; | |
341 | ||
5ffdc7b0 | 342 | rc = 0; |
b197bf0b MH |
343 | if (delete_mod) |
344 | exit(remove_module(modname, 1)); | |
00d577a6 FCE |
345 | if (attach_mod) { |
346 | /* PR14245: prime the relay_basedir_fd pump. */ | |
347 | rc = init_ctl_channel (modname, 0); | |
348 | if (rc >= 0) | |
349 | close_ctl_channel (); | |
350 | } else /* if (!attach_mod) */ { | |
6274464e JK |
351 | if (need_uprobes && enable_uprobes() != 0) |
352 | return -1; | |
cd125e94 FCE |
353 | |
354 | disable_kprobes_optimization(); | |
355 | ||
429a4963 | 356 | if (insert_stap_module(& user_credentials) < 0) { |
5c854d7c CM |
357 | if(!rename_mod && errno == EEXIST) |
358 | err("Rerun with staprun option '-R' to rename this module.\n"); | |
2155081e CW |
359 | return -1; |
360 | } | |
5ffdc7b0 | 361 | rc = init_ctl_channel (modname, 0); |
d0297590 | 362 | if (rc >= 0) { |
933e53b0 DB |
363 | /* If we are unable to send privilege credentials then we have an old |
364 | (pre 1.7) stap module or a non-stap module. In either case, the privilege | |
365 | credentials required for loading the module have already been determined and | |
366 | checked (see check_groups, get_module_required_credentials). | |
367 | */ | |
429a4963 | 368 | send_privilege_credentials(user_credentials); |
5ffdc7b0 | 369 | rc = send_relocations(); |
933e53b0 DB |
370 | if (rc == 0) { |
371 | rc = send_tzinfo(); | |
372 | if (rc == 0 && remote_id >= 0) | |
373 | send_remote_id(); | |
5ffdc7b0 DB |
374 | } |
375 | close_ctl_channel (); | |
376 | } | |
d0297590 DB |
377 | if (rc != 0) |
378 | remove_module(modname, 1); | |
5eddf13b | 379 | } |
5ffdc7b0 | 380 | return rc; |
5eddf13b | 381 | } |
a846e9cd MH |
382 | |
383 | int main(int argc, char **argv) | |
384 | { | |
5eddf13b | 385 | int rc; |
83c5b5fe | 386 | |
b197bf0b MH |
387 | /* NB: Don't do the geteuid()!=0 check here, since we want to |
388 | test command-line error-handling while running non-root. */ | |
5eddf13b DS |
389 | /* Get rid of a few standard environment variables (which */ |
390 | /* might cause us to do unintended things). */ | |
391 | rc = unsetenv("IFS") || unsetenv("CDPATH") || unsetenv("ENV") | |
b197bf0b | 392 | || unsetenv("BASH_ENV"); |
5eddf13b DS |
393 | if (rc) { |
394 | _perr("unsetenv failed"); | |
395 | exit(-1); | |
a846e9cd MH |
396 | } |
397 | ||
73dc0c77 | 398 | if (getuid() != geteuid()) { /* setuid? */ |
aad1a79c | 399 | rc = unsetenv("SYSTEMTAP_STAPRUN") || |
73dc0c77 FCE |
400 | unsetenv("SYSTEMTAP_STAPIO") || |
401 | unsetenv("SYSTEMTAP_RUNTIME"); | |
402 | ||
aad1a79c RM |
403 | if (rc) { |
404 | _perr("unsetenv failed"); | |
405 | exit(-1); | |
406 | } | |
407 | } | |
408 | ||
5eddf13b | 409 | setup_signals(); |
cedf63f3 | 410 | setup_term_signals(); |
5eddf13b DS |
411 | |
412 | parse_args(argc, argv); | |
413 | ||
c5f7c84b FCE |
414 | /* PR14245, For security reasons, preclude "staprun -F fd". |
415 | The -F option is only for stapio, but the overzealous quest | |
416 | for commonality doesn't let us express that nicer. */ | |
417 | if (relay_basedir_fd >= 0) { | |
11bfd0cc | 418 | err(_("Relay basedir -F option is invalid for staprun\n")); |
c5f7c84b FCE |
419 | exit(1); |
420 | } | |
421 | /* NB: later on, some of our own code may set relay_basedir_fd, for | |
422 | passing onto stapio - or for our own reuse. That's OK. */ | |
423 | ||
424 | ||
5eddf13b | 425 | if (buffer_size) |
3b5ab982 | 426 | dbug(2, "Using a buffer of %u MB.\n", buffer_size); |
5eddf13b | 427 | |
5c854d7c | 428 | int mod_optind = optind; |
a846e9cd | 429 | if (optind < argc) { |
5eddf13b | 430 | parse_modpath(argv[optind++]); |
83c5b5fe | 431 | dbug(2, "modpath=\"%s\", modname=\"%s\"\n", modpath, modname); |
a846e9cd MH |
432 | } |
433 | ||
b197bf0b | 434 | if (optind < argc) { |
5d65678d | 435 | if (attach_mod) { |
11bfd0cc | 436 | err("Cannot have module options with attach (-A).\n"); |
5d65678d MH |
437 | usage(argv[0]); |
438 | } else { | |
5eddf13b | 439 | unsigned start_idx = 0; |
b197bf0b | 440 | while (optind < argc && start_idx + 1 < MAXMODOPTIONS) |
5d65678d MH |
441 | modoptions[start_idx++] = argv[optind++]; |
442 | modoptions[start_idx] = NULL; | |
443 | } | |
a846e9cd MH |
444 | } |
445 | ||
5eddf13b | 446 | if (modpath == NULL || *modpath == '\0') { |
11bfd0cc | 447 | err("Need a module name or path to load.\n"); |
a846e9cd MH |
448 | usage(argv[0]); |
449 | } | |
450 | ||
3a9627f6 | 451 | if (geteuid() != 0) { |
11bfd0cc | 452 | err("The effective user ID of staprun must be set to the root user.\n" |
b197bf0b | 453 | " Check permissions on staprun and ensure it is a setuid root program.\n"); |
3a9627f6 FCE |
454 | exit(1); |
455 | } | |
456 | ||
c31d198c LB |
457 | char verbose_level[33]; |
458 | sprintf(verbose_level, "%d", verbose); | |
459 | rc = setenv("SYSTEMTAP_VERBOSE", verbose_level, 0); | |
460 | if (rc) { | |
461 | _perr("SYSTEMTAP_VERBOSE setenv failed"); | |
462 | exit(-1); | |
463 | } | |
464 | ||
5d65678d | 465 | if (init_staprun()) |
a846e9cd | 466 | exit(1); |
a846e9cd | 467 | |
aad1a79c | 468 | argv[0] = getenv ("SYSTEMTAP_STAPIO") ?: PKGLIBDIR "/stapio"; |
5c854d7c CM |
469 | |
470 | /* Copy nenamed modname into argv */ | |
471 | if(rename_mod) | |
472 | argv[mod_optind] = modname; | |
473 | ||
c5f7c84b FCE |
474 | /* PR14245: pass -F fd to stapio. Unfortunately, this requires |
475 | us to extend argv[], with all the C fun that entails. */ | |
476 | #ifdef HAVE_OPENAT | |
477 | if (relay_basedir_fd >= 0) { | |
684925aa | 478 | char ** new_argv = calloc(sizeof(char *),argc+2); |
c5f7c84b FCE |
479 | const int new_Foption_size = 10; /* -FNNNNN */ |
480 | char * new_Foption = malloc(new_Foption_size); | |
481 | int i; | |
482 | ||
483 | if (new_argv && new_Foption) { | |
484 | snprintf (new_Foption, new_Foption_size, "-F%d", relay_basedir_fd); | |
684925aa | 485 | for (i=0; i < argc && argv[i] != NULL; i++) |
c5f7c84b FCE |
486 | new_argv[i] = argv[i]; |
487 | new_argv[i++] = new_Foption; /* overwrite the NULL */ | |
488 | new_argv[i++] = NULL; /* ensconce a new NULL */ | |
489 | ||
490 | argv = new_argv; | |
491 | } | |
492 | } | |
493 | #endif | |
494 | ||
5c854d7c | 495 | /* Run stapio */ |
337cd273 | 496 | if (run_as (1, getuid(), getgid(), argv[0], argv) < 0) { |
b197bf0b MH |
497 | perror(argv[0]); |
498 | goto err; | |
499 | } | |
5c854d7c CM |
500 | |
501 | free(modname); | |
a846e9cd | 502 | return 0; |
b197bf0b MH |
503 | |
504 | err: | |
505 | remove_module(modname, 1); | |
5c854d7c | 506 | free(modname); |
b197bf0b | 507 | return 1; |
a846e9cd | 508 | } |
37ddf6e5 FCE |
509 | |
510 | ||
511 | ||
512 | /* Send a variety of relocation-related data to the kernel: for the | |
513 | kernel proper, just the "_stext" symbol address; for all loaded | |
514 | modules, a variety of symbol base addresses. | |
515 | ||
516 | We do this under protest. The kernel ought expose this data to | |
517 | modules such as ourselves, but instead the upstream community | |
518 | continually shrinks its module-facing interfaces, including this | |
519 | stuff, even when users exist. | |
520 | */ | |
521 | ||
522 | ||
933e53b0 | 523 | int send_a_relocation (const char* module, const char* reloc, unsigned long long address) |
37ddf6e5 FCE |
524 | { |
525 | struct _stp_msg_relocation msg; | |
933e53b0 | 526 | int rc; |
37ddf6e5 | 527 | |
7c7b1cd5 | 528 | if (strlen(module) >= STP_MODULE_NAME_LEN-1) { |
adc149b7 | 529 | dbug (1, "module name too long: %s\n", module); |
933e53b0 | 530 | return -EINVAL; |
7c7b1cd5 FCE |
531 | } |
532 | strncpy (msg.module, module, STP_MODULE_NAME_LEN); | |
533 | ||
534 | if (strlen(reloc) >= STP_SYMBOL_NAME_LEN-1) { | |
adc149b7 | 535 | dbug (1, "reloc name too long: %s\n", reloc); |
933e53b0 | 536 | return -EINVAL; |
7c7b1cd5 FCE |
537 | } |
538 | strncpy (msg.reloc, reloc, STP_MODULE_NAME_LEN); | |
37ddf6e5 FCE |
539 | |
540 | msg.address = address; | |
541 | ||
933e53b0 DB |
542 | rc = send_request (STP_RELOCATION, & msg, sizeof (msg)); |
543 | if (rc != 0) | |
544 | perror ("Unable to send relocation"); | |
545 | return rc; | |
37ddf6e5 FCE |
546 | } |
547 | ||
548 | ||
549 | int send_relocation_kernel () | |
550 | { | |
933e53b0 DB |
551 | FILE* kallsyms; |
552 | int rc = 0; | |
553 | ||
554 | errno = 0; | |
555 | kallsyms = fopen ("/proc/kallsyms", "r"); | |
37ddf6e5 FCE |
556 | if (kallsyms == NULL) |
557 | { | |
337cd273 | 558 | perror("cannot open /proc/kallsyms"); |
37ddf6e5 | 559 | // ... and the kernel module will almost certainly fail to initialize. |
933e53b0 | 560 | return errno; |
37ddf6e5 FCE |
561 | } |
562 | else | |
563 | { | |
df00639d | 564 | int done_with_kallsyms = 0; |
aa2b3583 RM |
565 | char *line = NULL; |
566 | size_t linesz = 0; | |
df00639d | 567 | while (! feof(kallsyms) && !done_with_kallsyms) |
37ddf6e5 | 568 | { |
37ddf6e5 | 569 | ssize_t linesize = getline (& line, & linesz, kallsyms); |
aa2b3583 | 570 | if (linesize > 0) |
37ddf6e5 FCE |
571 | { |
572 | unsigned long long address; | |
aa2b3583 RM |
573 | int pos = -1; |
574 | if (sscanf (line, "%llx %*c %n", &address, &pos) == 1 | |
575 | && pos != -1 | |
576 | && linesize - pos == sizeof KERNEL_RELOC_SYMBOL | |
577 | && !strcmp(line + pos, KERNEL_RELOC_SYMBOL "\n")) | |
37ddf6e5 | 578 | { |
1b94bf6d | 579 | /* NB: even on ppc, we use the _stext relocation name. */ |
933e53b0 DB |
580 | rc = send_a_relocation ("kernel", "_stext", address); |
581 | if (rc != 0) | |
582 | break; | |
37ddf6e5 FCE |
583 | |
584 | /* We need nothing more from the kernel. */ | |
df00639d | 585 | done_with_kallsyms=1; |
37ddf6e5 | 586 | } |
37ddf6e5 FCE |
587 | } |
588 | } | |
aa2b3583 | 589 | free (line); |
37ddf6e5 | 590 | fclose (kallsyms); |
aa2b3583 | 591 | if (!done_with_kallsyms) |
933e53b0 | 592 | return rc; |
aa2b3583 RM |
593 | |
594 | /* detect note section, send flag if there | |
29495972 | 595 | * NB: address=2 represents existed note, the real one in _stp_module |
aa2b3583 RM |
596 | */ |
597 | if (!access("/sys/kernel/notes", R_OK)) | |
933e53b0 | 598 | rc = send_a_relocation ("kernel", ".note.gnu.build-id", 2); |
37ddf6e5 | 599 | } |
df00639d | 600 | |
933e53b0 | 601 | return rc; |
37ddf6e5 FCE |
602 | } |
603 | ||
604 | ||
933e53b0 | 605 | int send_relocation_modules () |
37ddf6e5 | 606 | { |
555ffd15 | 607 | unsigned i = 0; |
df00639d | 608 | glob_t globbuf; |
555ffd15 | 609 | globbuf.gl_pathc = 0; |
df00639d FCE |
610 | int r = glob("/sys/module/*/sections/*", GLOB_PERIOD, NULL, &globbuf); |
611 | ||
612 | if (r == GLOB_NOSPACE || r == GLOB_ABORTED) | |
933e53b0 | 613 | return r; |
df00639d FCE |
614 | |
615 | for (i=0; i<globbuf.gl_pathc; i++) | |
616 | { | |
617 | char *module_section_file; | |
618 | char *section_name; | |
619 | char *module_name; | |
620 | char *module_name_end; | |
621 | FILE* secfile; | |
622 | unsigned long long section_address; | |
623 | ||
624 | module_section_file = globbuf.gl_pathv[i]; | |
625 | ||
337cd273 | 626 | /* Tokenize the file name. |
df00639d FCE |
627 | Sample gl_pathv[]: /sys/modules/zlib_deflate/sections/.text |
628 | Pieces: ^^^^^^^^^^^^ ^^^^^ | |
629 | */ | |
6bedc77b | 630 | section_name = strrchr (module_section_file, '/'); |
df00639d FCE |
631 | if (! section_name) continue; |
632 | section_name ++; | |
633 | ||
634 | if (!strcmp (section_name, ".")) continue; | |
635 | if (!strcmp (section_name, "..")) continue; | |
337cd273 | 636 | |
6bedc77b | 637 | module_name = strchr (module_section_file, '/'); |
df00639d FCE |
638 | if (! module_name) continue; |
639 | module_name ++; | |
6bedc77b | 640 | module_name = strchr (module_name, '/'); |
df00639d FCE |
641 | if (! module_name) continue; |
642 | module_name ++; | |
6bedc77b | 643 | module_name = strchr (module_name, '/'); |
df00639d FCE |
644 | if (! module_name) continue; |
645 | module_name ++; | |
646 | ||
6bedc77b | 647 | module_name_end = strchr (module_name, '/'); |
df00639d FCE |
648 | if (! module_name_end) continue; |
649 | ||
650 | secfile = fopen (module_section_file, "r"); | |
651 | if (! secfile) continue; | |
652 | ||
653 | if (1 == fscanf (secfile, "0x%llx", §ion_address)) | |
654 | { | |
655 | /* Now we destructively modify the string, but by now the file | |
656 | is open so we won't need the full name again. */ | |
657 | *module_name_end = '\0'; | |
337cd273 | 658 | |
ac08441a FCE |
659 | /* PR6503. /sys/module/.../sections/...init.... sometimes contain |
660 | non-0 addresses, even though the respective module-initialization | |
661 | sections were already unloaded. We override the addresses here. */ | |
662 | if (strstr (section_name, "init.") != NULL) /* .init.text, .devinit.rodata, ... */ | |
663 | section_address = 0; | |
664 | ||
0243596c FCE |
665 | (void) send_a_relocation (module_name, section_name, section_address); |
666 | /* PR14005: take a pill, dude, a failure with an overlong | |
667 | * name does not call for freaking out. Nor does an error | |
668 | * coming back from the write(2) into the module. We will | |
669 | * just stagger along without that particular module/section | |
670 | * being present in the _stp_sections[] tables. */ | |
df00639d FCE |
671 | } |
672 | ||
673 | if (strcmp (section_name, ".gnu.linkonce.this_module")) | |
674 | fclose (secfile); | |
675 | else | |
676 | { | |
22902e73 | 677 | (void)set_clexec (fileno (secfile)); |
df00639d FCE |
678 | /* NB: don't fclose this arbitrarily-chosen section file. |
679 | This forces the kernel to keep a nonzero reference count | |
680 | on the subject module, until staprun exits, by which time | |
681 | the kernel module will have inserted its separate claws | |
682 | into the probeworthy modules. This prevents a race | |
683 | condition where a probe may be just starting up at the | |
684 | same time that a probeworthy module is being unloaded. */ | |
685 | } | |
686 | } | |
337cd273 | 687 | |
df00639d | 688 | globfree (& globbuf); |
ef187c96 | 689 | return 0; |
37ddf6e5 FCE |
690 | } |
691 | ||
692 | ||
693 | ||
694 | int send_relocations () | |
695 | { | |
3c02e16c | 696 | int rc; |
3c02e16c | 697 | rc = send_relocation_kernel (); |
933e53b0 DB |
698 | if (rc == 0) |
699 | rc = send_relocation_modules (); | |
37ddf6e5 FCE |
700 | return rc; |
701 | } | |
d62c7736 FCE |
702 | |
703 | ||
933e53b0 | 704 | int send_tzinfo () |
d62c7736 | 705 | { |
d62c7736 FCE |
706 | struct _stp_msg_tzinfo tzi; |
707 | time_t now_t; | |
708 | struct tm* now; | |
933e53b0 | 709 | int rc; |
d62c7736 | 710 | |
d62c7736 FCE |
711 | /* NB: This is not good enough; it sends DST-unaware numbers. */ |
712 | #if 0 | |
713 | tzset (); | |
714 | tzi.tz_gmtoff = timezone; | |
715 | strncpy (tzi.tz_name, tzname[0], STP_TZ_NAME_LEN); | |
716 | #endif | |
717 | ||
718 | time (& now_t); | |
719 | now = localtime (& now_t); | |
720 | tzi.tz_gmtoff = - now->tm_gmtoff; | |
721 | strncpy (tzi.tz_name, now->tm_zone, STP_TZ_NAME_LEN); | |
722 | ||
933e53b0 DB |
723 | rc = send_request(STP_TZINFO, & tzi, sizeof(tzi)); |
724 | if (rc != 0) | |
725 | perror ("Unable to send time zone information"); | |
726 | return rc; | |
5ffdc7b0 DB |
727 | } |
728 | ||
429a4963 | 729 | int send_privilege_credentials (privilege_t user_credentials) |
5ffdc7b0 DB |
730 | { |
731 | struct _stp_msg_privilege_credentials pc; | |
933e53b0 | 732 | int rc; |
429a4963 | 733 | pc.pc_group_mask = user_credentials; |
933e53b0 DB |
734 | rc = send_request(STP_PRIVILEGE_CREDENTIALS, & pc, sizeof(pc)); |
735 | if (rc != 0) { | |
736 | /* Not an error. Happens when pre 1.7 modules are loaded. */ | |
adc149b7 | 737 | dbug (1, "Unable to send user privilege credentials\n"); |
933e53b0 DB |
738 | } |
739 | return rc; | |
d62c7736 | 740 | } |
5137a7a9 | 741 | |
933e53b0 | 742 | int send_remote_id () |
5137a7a9 FCE |
743 | { |
744 | struct _stp_msg_remote_id rem; | |
933e53b0 | 745 | int rc; |
5137a7a9 FCE |
746 | |
747 | rem.remote_id = remote_id; | |
748 | strncpy (rem.remote_uri, remote_uri, STP_REMOTE_URI_LEN); | |
749 | rem.remote_uri [STP_REMOTE_URI_LEN-1]='\0'; /* XXX: quietly truncate */ | |
933e53b0 DB |
750 | rc = send_request(STP_REMOTE_ID, & rem, sizeof(rem)); |
751 | if (rc != 0) | |
752 | perror ("Unable to send remote id"); | |
753 | return rc; | |
5137a7a9 | 754 | } |