From 096102bd1f0665d96f75ad12410ea23189fbf861 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Sun, 22 Jan 2012 16:11:11 -0500 Subject: [PATCH] Add kernel module version validation The session daemon now checks if the kernel modules are compatible whenever it tries to load them. Introduce modprobe.c/.h and kern-modules.h that contains the lttng modules information and function to load/remove them. Also add a call to kernel.c for kernel version validation. Signed-off-by: David Goulet --- src/bin/lttng-sessiond/Makefile.am | 1 + src/bin/lttng-sessiond/kern-modules.h | 33 ++++ src/bin/lttng-sessiond/kernel.c | 45 +++++ src/bin/lttng-sessiond/kernel.h | 1 + src/bin/lttng-sessiond/lttng-sessiond.h | 26 +-- src/bin/lttng-sessiond/main.c | 190 ++++---------------- src/bin/lttng-sessiond/modprobe.c | 223 ++++++++++++++++++++++++ src/bin/lttng-sessiond/modprobe.h | 28 +++ 8 files changed, 368 insertions(+), 179 deletions(-) create mode 100644 src/bin/lttng-sessiond/kern-modules.h create mode 100644 src/bin/lttng-sessiond/modprobe.c create mode 100644 src/bin/lttng-sessiond/modprobe.h diff --git a/src/bin/lttng-sessiond/Makefile.am b/src/bin/lttng-sessiond/Makefile.am index c431ade86..88b7c6974 100644 --- a/src/bin/lttng-sessiond/Makefile.am +++ b/src/bin/lttng-sessiond/Makefile.am @@ -15,6 +15,7 @@ lttng_sessiond_SOURCES = utils.c utils.h \ futex.c futex.h \ shm.c shm.h \ session.c session.h \ + modprobe.c modprobe.h kern-modules.h \ lttng-ust-ctl.h lttng-ust-abi.h if HAVE_LIBLTTNG_UST_CTL diff --git a/src/bin/lttng-sessiond/kern-modules.h b/src/bin/lttng-sessiond/kern-modules.h new file mode 100644 index 000000000..ff1684a15 --- /dev/null +++ b/src/bin/lttng-sessiond/kern-modules.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2011 - David Goulet + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; only version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _KERN_MODULES_H +#define _KERN_MODULES_H + +/* + * Compatible lttng-modules version. + */ +#define KERN_MODULES_VERSION 0 +#define KERN_MODULES_PATCHLEVEL 9 +#define KERN_MODULES_SUBLEVEL 1 + +struct kern_modules_param { + const char *name; + int required; +}; + +#endif /* _KERN_MODULES_H */ diff --git a/src/bin/lttng-sessiond/kernel.c b/src/bin/lttng-sessiond/kernel.c index afa5e604f..3b0d6e5f5 100644 --- a/src/bin/lttng-sessiond/kernel.c +++ b/src/bin/lttng-sessiond/kernel.c @@ -28,6 +28,7 @@ #include #include "kernel.h" +#include "kern-modules.h" /* * Add context on a kernel channel. @@ -606,3 +607,47 @@ error_fp: error: return -1; } + +/* + * Get kernel version and validate it. + */ +int kernel_validate_version(int tracer_fd) +{ + int ret; + struct lttng_kernel_tracer_version version; + + ret = kernctl_tracer_version(tracer_fd, &version); + if (ret < 0) { + ERR("Failed at getting the lttng-modules version"); + goto error; + } + + /* Validate version */ + if (version.version > KERN_MODULES_VERSION) { + goto error_version; + } else { + if (version.patchlevel > KERN_MODULES_PATCHLEVEL) { + goto error_version; + } + else { + if (version.sublevel > KERN_MODULES_SUBLEVEL) { + goto error_version; + } + } + } + + DBG2("Kernel tracer version validated (%d.%d.%d)", version.version, + version.patchlevel, version.sublevel); + + return 0; + +error_version: + ERR("Kernel version is not compatible %d.%d.%d (supporting <= %d.%d.%d)", + version.version, version.patchlevel, version.sublevel, + KERN_MODULES_VERSION, KERN_MODULES_PATCHLEVEL, + KERN_MODULES_SUBLEVEL); + ret = -1; + +error: + return ret; +} diff --git a/src/bin/lttng-sessiond/kernel.h b/src/bin/lttng-sessiond/kernel.h index c4c687e5b..a916f6841 100644 --- a/src/bin/lttng-sessiond/kernel.h +++ b/src/bin/lttng-sessiond/kernel.h @@ -53,5 +53,6 @@ int kernel_stop_session(struct ltt_kernel_session *session); ssize_t kernel_list_events(int tracer_fd, struct lttng_event **event_list); void kernel_wait_quiescent(int fd); int kernel_calibrate(int fd, struct lttng_kernel_calibrate *calibrate); +int kernel_validate_version(int tracer_fd); #endif /* _LTT_KERNEL_CTL_H */ diff --git a/src/bin/lttng-sessiond/lttng-sessiond.h b/src/bin/lttng-sessiond/lttng-sessiond.h index 238f27a80..2ba2550c7 100644 --- a/src/bin/lttng-sessiond/lttng-sessiond.h +++ b/src/bin/lttng-sessiond/lttng-sessiond.h @@ -28,31 +28,7 @@ #include "session.h" #include "ust-app.h" -struct module_param { - const char *name; - int required; -}; - -/* LTTng kernel tracer modules list */ -const struct module_param kernel_modules_list[] = { - { "lttng-ftrace", 0 }, - { "lttng-kprobes", 0 }, - { "lttng-kretprobes", 0 }, - { "lib-ring-buffer", 1 }, - { "ltt-relay", 1 }, - { "ltt-ring-buffer-client-discard", 1 }, - { "ltt-ring-buffer-client-overwrite", 1 }, - { "ltt-ring-buffer-metadata-client", 1 }, - { "ltt-ring-buffer-client-mmap-discard", 1 }, - { "ltt-ring-buffer-client-mmap-overwrite", 1 }, - { "ltt-ring-buffer-metadata-mmap-client", 1 }, - { "lttng-probe-lttng", 1 }, - { "lttng-types", 0 }, - { "lttng-probe-block", 0 }, - { "lttng-probe-irq", 0 }, - { "lttng-probe-kvm", 0 }, - { "lttng-probe-sched", 0 }, -}; +const char *module_proc_lttng = "/proc/lttng"; extern const char default_home_dir[], default_tracing_group[], diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index 77b107875..e1d50974b 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -50,6 +50,7 @@ #include "event.h" #include "futex.h" #include "kernel.h" +#include "modprobe.h" #include "shm.h" #include "ust-ctl.h" #include "utils.h" @@ -268,41 +269,6 @@ static int check_thread_quit_pipe(int fd, uint32_t events) return 0; } -/* - * Remove modules in reverse load order. - */ -static int modprobe_remove_kernel_modules(void) -{ - int ret = 0, i; - char modprobe[256]; - - for (i = ARRAY_SIZE(kernel_modules_list) - 1; i >= 0; i--) { - ret = snprintf(modprobe, sizeof(modprobe), - "/sbin/modprobe -r -q %s", - kernel_modules_list[i].name); - if (ret < 0) { - perror("snprintf modprobe -r"); - goto error; - } - modprobe[sizeof(modprobe) - 1] = '\0'; - ret = system(modprobe); - if (ret == -1) { - ERR("Unable to launch modprobe -r for module %s", - kernel_modules_list[i].name); - } else if (kernel_modules_list[i].required - && WEXITSTATUS(ret) != 0) { - ERR("Unable to remove module %s", - kernel_modules_list[i].name); - } else { - DBG("Modprobe removal successful %s", - kernel_modules_list[i].name); - } - } - -error: - return ret; -} - /* * Return group ID of the tracing group or -1 if not found. */ @@ -455,7 +421,7 @@ static void cleanup(void) DBG2("Closing kernel fd"); close(kernel_tracer_fd); DBG("Unloading kernel modules"); - modprobe_remove_kernel_modules(); + modprobe_remove_lttng_all(); } close(thread_quit_pipe[0]); @@ -1701,147 +1667,64 @@ error: } /* - * modprobe_kernel_modules + * Check version of the lttng-modules. */ -static int modprobe_kernel_modules(void) +static int validate_lttng_modules_version(void) { - int ret = 0, i; - char modprobe[256]; - - for (i = 0; i < ARRAY_SIZE(kernel_modules_list); i++) { - ret = snprintf(modprobe, sizeof(modprobe), - "/sbin/modprobe %s%s", - kernel_modules_list[i].required ? "" : "-q ", - kernel_modules_list[i].name); - if (ret < 0) { - perror("snprintf modprobe"); - goto error; - } - modprobe[sizeof(modprobe) - 1] = '\0'; - ret = system(modprobe); - if (ret == -1) { - ERR("Unable to launch modprobe for module %s", - kernel_modules_list[i].name); - } else if (kernel_modules_list[i].required - && WEXITSTATUS(ret) != 0) { - ERR("Unable to load module %s", - kernel_modules_list[i].name); - } else { - DBG("Modprobe successfully %s", - kernel_modules_list[i].name); - } - } - -error: - return ret; + return kernel_validate_version(kernel_tracer_fd); } /* - * mount_debugfs + * Setup necessary data for kernel tracer action. */ -static int mount_debugfs(char *path) +static int init_kernel_tracer(void) { int ret; - char *type = "debugfs"; - - ret = run_as_mkdir_recursive(path, S_IRWXU | S_IRWXG, geteuid(), getegid()); - if (ret < 0) { - PERROR("Cannot create debugfs path"); - goto error; - } - ret = mount(type, path, type, 0, NULL); + /* Modprobe lttng kernel modules */ + ret = modprobe_lttng_control(); if (ret < 0) { - PERROR("Cannot mount debugfs"); goto error; } - DBG("Mounted debugfs successfully at %s", path); - -error: - return ret; -} - -/* - * Setup necessary data for kernel tracer action. - */ -static void init_kernel_tracer(void) -{ - int ret; - char *proc_mounts = "/proc/mounts"; - char line[256]; - char *debugfs_path = NULL, *lttng_path = NULL; - FILE *fp; - - /* Detect debugfs */ - fp = fopen(proc_mounts, "r"); - if (fp == NULL) { - ERR("Unable to probe %s", proc_mounts); - goto error; - } - - while (fgets(line, sizeof(line), fp) != NULL) { - if (strstr(line, "debugfs") != NULL) { - /* Remove first string */ - strtok(line, " "); - /* Dup string here so we can reuse line later on */ - debugfs_path = strdup(strtok(NULL, " ")); - DBG("Got debugfs path : %s", debugfs_path); - break; - } - } - - fclose(fp); - - /* Mount debugfs if needded */ - if (debugfs_path == NULL) { - ret = asprintf(&debugfs_path, "/mnt/debugfs"); - if (ret < 0) { - perror("asprintf debugfs path"); - goto error; - } - ret = mount_debugfs(debugfs_path); - if (ret < 0) { - perror("Cannot mount debugfs"); - goto error; - } + /* Open debugfs lttng */ + kernel_tracer_fd = open(module_proc_lttng, O_RDWR); + if (kernel_tracer_fd < 0) { + DBG("Failed to open %s", module_proc_lttng); + ret = -1; + goto error_open; } - /* Modprobe lttng kernel modules */ - ret = modprobe_kernel_modules(); + /* Validate kernel version */ + ret = validate_lttng_modules_version(); if (ret < 0) { - goto error; + goto error_version; } - /* Setup lttng kernel path */ - ret = asprintf(<tng_path, "%s/lttng", debugfs_path); + ret = modprobe_lttng_data(); if (ret < 0) { - perror("asprintf lttng path"); - goto error; - } - - /* Open debugfs lttng */ - kernel_tracer_fd = open(lttng_path, O_RDWR); - if (kernel_tracer_fd < 0) { - DBG("Failed to open %s", lttng_path); - goto error; + goto error_modules; } - free(lttng_path); - free(debugfs_path); DBG("Kernel tracer fd %d", kernel_tracer_fd); - return; + return 0; + +error_version: + modprobe_remove_lttng_control(); + close(kernel_tracer_fd); + kernel_tracer_fd = 0; + return LTTCOMM_KERN_VERSION; + +error_modules: + close(kernel_tracer_fd); + +error_open: + modprobe_remove_lttng_control(); error: - if (lttng_path) { - free(lttng_path); - } - if (debugfs_path) { - free(debugfs_path); - } WARN("No kernel tracer available"); kernel_tracer_fd = 0; - return; + return LTTCOMM_KERN_NA; } /* @@ -3277,9 +3160,8 @@ static int process_client_msg(struct command_ctx *cmd_ctx) /* Kernel tracer check */ if (kernel_tracer_fd == 0) { /* Basically, load kernel tracer modules */ - init_kernel_tracer(); - if (kernel_tracer_fd == 0) { - ret = LTTCOMM_KERN_NA; + ret = init_kernel_tracer(); + if (ret != 0) { goto error; } } diff --git a/src/bin/lttng-sessiond/modprobe.c b/src/bin/lttng-sessiond/modprobe.c new file mode 100644 index 000000000..5ff422231 --- /dev/null +++ b/src/bin/lttng-sessiond/modprobe.c @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2011 - David Goulet + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; only version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#define _GNU_SOURCE +#include +#include +#include + +#include + +#include "modprobe.h" +#include "kern-modules.h" + +/* MUST be loaded first */ +const struct kern_modules_param kern_modules_control[] = { + { "ltt-relay", 1 }, +}; + +/* LTTng kernel tracer modules list */ +const struct kern_modules_param kern_modules_list[] = { + { "lttng-ftrace", 0 }, + { "lttng-kprobes", 0 }, + { "lttng-kretprobes", 0 }, + { "lib-ring-buffer", 1 }, + { "ltt-ring-buffer-client-discard", 1 }, + { "ltt-ring-buffer-client-overwrite", 1 }, + { "ltt-ring-buffer-metadata-client", 1 }, + { "ltt-ring-buffer-client-mmap-discard", 1 }, + { "ltt-ring-buffer-client-mmap-overwrite", 1 }, + { "ltt-ring-buffer-metadata-mmap-client", 1 }, + { "lttng-probe-lttng", 1 }, + { "lttng-types", 0 }, + { "lttng-probe-block", 0 }, + { "lttng-probe-irq", 0 }, + { "lttng-probe-kvm", 0 }, + { "lttng-probe-sched", 0 }, +}; + +/* + * Remove control kernel module(s) in reverse load order. + */ +void modprobe_remove_lttng_control(void) +{ + int ret = 0, i; + char modprobe[256]; + + for (i = ARRAY_SIZE(kern_modules_control) - 1; i >= 0; i--) { + ret = snprintf(modprobe, sizeof(modprobe), + "/sbin/modprobe -r -q %s", + kern_modules_control[i].name); + if (ret < 0) { + PERROR("snprintf modprobe -r"); + goto error; + } + modprobe[sizeof(modprobe) - 1] = '\0'; + ret = system(modprobe); + if (ret == -1) { + ERR("Unable to launch modprobe -r for module %s", + kern_modules_control[i].name); + } else if (kern_modules_control[i].required + && WEXITSTATUS(ret) != 0) { + ERR("Unable to remove module %s", + kern_modules_control[i].name); + } else { + DBG("Modprobe removal successful %s", + kern_modules_control[i].name); + } + } + +error: + return; +} + +/* + * Remove data kernel modules in reverse load order. + */ +void modprobe_remove_lttng_data(void) +{ + int ret = 0, i; + char modprobe[256]; + + for (i = ARRAY_SIZE(kern_modules_list) - 1; i >= 0; i--) { + ret = snprintf(modprobe, sizeof(modprobe), + "/sbin/modprobe -r -q %s", + kern_modules_list[i].name); + if (ret < 0) { + perror("snprintf modprobe -r"); + goto error; + } + modprobe[sizeof(modprobe) - 1] = '\0'; + ret = system(modprobe); + if (ret == -1) { + ERR("Unable to launch modprobe -r for module %s", + kern_modules_list[i].name); + } else if (kern_modules_list[i].required + && WEXITSTATUS(ret) != 0) { + ERR("Unable to remove module %s", + kern_modules_list[i].name); + } else { + DBG("Modprobe removal successful %s", + kern_modules_list[i].name); + } + } + +error: + return; +} + +/* + * Remove all kernel modules in reverse order. + */ +void modprobe_remove_lttng_all(void) +{ + modprobe_remove_lttng_data(); + modprobe_remove_lttng_control(); +} + +/* + * Load control kernel module(s). + */ +int modprobe_lttng_control(void) +{ + int ret = 0, i; + char modprobe[256]; + + for (i = 0; i < ARRAY_SIZE(kern_modules_control); i++) { + ret = snprintf(modprobe, sizeof(modprobe), + "/sbin/modprobe %s%s", + kern_modules_control[i].required ? "" : "-q ", + kern_modules_control[i].name); + if (ret < 0) { + PERROR("snprintf modprobe"); + goto error; + } + modprobe[sizeof(modprobe) - 1] = '\0'; + ret = system(modprobe); + if (ret == -1) { + ERR("Unable to launch modprobe for module %s", + kern_modules_control[i].name); + } else if (kern_modules_control[i].required + && WEXITSTATUS(ret) != 0) { + ERR("Unable to load module %s", + kern_modules_control[i].name); + } else { + DBG("Modprobe successfully %s", + kern_modules_control[i].name); + } + } + +error: + return ret; +} + +/* + * Load data kernel module(s). + */ +int modprobe_lttng_data(void) +{ + int ret = 0, i; + char modprobe[256]; + + for (i = 0; i < ARRAY_SIZE(kern_modules_list); i++) { + ret = snprintf(modprobe, sizeof(modprobe), + "/sbin/modprobe %s%s", + kern_modules_list[i].required ? "" : "-q ", + kern_modules_list[i].name); + if (ret < 0) { + perror("snprintf modprobe"); + goto error; + } + modprobe[sizeof(modprobe) - 1] = '\0'; + ret = system(modprobe); + if (ret == -1) { + ERR("Unable to launch modprobe for module %s", + kern_modules_list[i].name); + } else if (kern_modules_list[i].required + && WEXITSTATUS(ret) != 0) { + ERR("Unable to load module %s", + kern_modules_list[i].name); + } else { + DBG("Modprobe successfully %s", + kern_modules_list[i].name); + } + } + +error: + return ret; +} + +/* + * Load all lttng kernel modules. + */ +int modprobe_lttng_all(void) +{ + int ret; + + ret = modprobe_lttng_control(); + if (ret < 0) { + goto error; + } + + ret = modprobe_lttng_data(); + if (ret < 0) { + goto error; + } + +error: + return ret; +} diff --git a/src/bin/lttng-sessiond/modprobe.h b/src/bin/lttng-sessiond/modprobe.h new file mode 100644 index 000000000..acd3e8ac9 --- /dev/null +++ b/src/bin/lttng-sessiond/modprobe.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2011 - David Goulet + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; only version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _MODPROBE_H +#define _MODPROBE_H + +void modprobe_remove_lttng_all(void); +void modprobe_remove_lttng_control(void); +void modprobe_remove_lttng_data(void); +int modprobe_lttng_all(void); +int modprobe_lttng_control(void); +int modprobe_lttng_data(void); + +#endif /* _MODPROBE_H */ -- 2.34.1