Add kernel module version validation
authorDavid Goulet <dgoulet@efficios.com>
Sun, 22 Jan 2012 21:11:11 +0000 (16:11 -0500)
committerDavid Goulet <dgoulet@efficios.com>
Sun, 22 Jan 2012 21:11:11 +0000 (16:11 -0500)
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 <dgoulet@efficios.com>
src/bin/lttng-sessiond/Makefile.am
src/bin/lttng-sessiond/kern-modules.h [new file with mode: 0644]
src/bin/lttng-sessiond/kernel.c
src/bin/lttng-sessiond/kernel.h
src/bin/lttng-sessiond/lttng-sessiond.h
src/bin/lttng-sessiond/main.c
src/bin/lttng-sessiond/modprobe.c [new file with mode: 0644]
src/bin/lttng-sessiond/modprobe.h [new file with mode: 0644]

index c431ade868b1717a4acbbd7963976fd3fd94d98e..88b7c6974f35acf77f733700a5b7b7544842bfa8 100644 (file)
@@ -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 (file)
index 0000000..ff1684a
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011 - David Goulet <dgoulet@efficios.com>
+ *
+ * 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 */
index afa5e604fbefff9a9a2465fb5809cfe884d19f60..3b0d6e5f5ee05146aff5d2e31b61517577eed62b 100644 (file)
@@ -28,6 +28,7 @@
 #include <common/kernel-ctl/kernel-ctl.h>
 
 #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;
+}
index c4c687e5b97eade8b1b0ad6e6bcd97cd6cb7a770..a916f68411244fb5b6fdb9773e5f04ae700107f0 100644 (file)
@@ -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 */
index 238f27a80c0601e57b443e4812db77d8d863a88d..2ba2550c7a1bda4cdb6fa3d1ff2f1f9313ad35ae 100644 (file)
 #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[],
index 77b10787598616d418ed6d8258fafcff24040c9e..e1d50974bfc2f3c220fd7cf219e6145b005f5ae4 100644 (file)
@@ -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(&lttng_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 (file)
index 0000000..5ff4222
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2011 - David Goulet <dgoulet@efficios.com>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+
+#include <common/common.h>
+
+#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 (file)
index 0000000..acd3e8a
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2011 - David Goulet <dgoulet@efficios.com>
+ *
+ * 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 */
This page took 0.034394 seconds and 4 git commands to generate.