From 74011e88983b12958dacd6621d60c18f6a84f59b Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Thu, 14 Feb 2019 16:14:42 -0500 Subject: [PATCH 01/16] Fix: procname context async-signal safety Ensure an instrumented signal handler interrupting the procname context code will not write a partial process name string into the trace context. Signed-off-by: Mathieu Desnoyers --- liblttng-ust/lttng-context-procname.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/liblttng-ust/lttng-context-procname.c b/liblttng-ust/lttng-context-procname.c index b6e69501..95d5f28d 100644 --- a/liblttng-ust/lttng-context-procname.c +++ b/liblttng-ust/lttng-context-procname.c @@ -28,6 +28,9 @@ #include #include "compat.h" +/* Maximum number of nesting levels for the procname cache. */ +#define PROCNAME_NESTING_MAX 2 + /* * We cache the result to ensure we don't trigger a system call for * each event. @@ -37,22 +40,34 @@ * be set for a thread before the first event is logged within this * thread. */ -typedef char procname_array[17]; +typedef char procname_array[PROCNAME_NESTING_MAX][17]; + static DEFINE_URCU_TLS(procname_array, cached_procname); +static DEFINE_URCU_TLS(int, procname_nesting); + static inline char *wrapper_getprocname(void) { - if (caa_unlikely(!URCU_TLS(cached_procname)[0])) { - lttng_ust_getprocname(URCU_TLS(cached_procname)); - URCU_TLS(cached_procname)[LTTNG_UST_PROCNAME_LEN - 1] = '\0'; + int nesting = URCU_TLS(procname_nesting); + + if (caa_unlikely(nesting >= PROCNAME_NESTING_MAX)) + return ""; + if (caa_unlikely(!URCU_TLS(cached_procname)[nesting][0])) { + CMM_STORE_SHARED(URCU_TLS(procname_nesting), nesting + 1); + lttng_ust_getprocname(URCU_TLS(cached_procname)[nesting]); + URCU_TLS(cached_procname)[nesting][LTTNG_UST_PROCNAME_LEN - 1] = '\0'; + CMM_STORE_SHARED(URCU_TLS(procname_nesting), nesting); } - return URCU_TLS(cached_procname); + return URCU_TLS(cached_procname)[nesting]; } void lttng_context_procname_reset(void) { - URCU_TLS(cached_procname)[0] = '\0'; + URCU_TLS(cached_procname)[1][0] = '\0'; + CMM_STORE_SHARED(URCU_TLS(procname_nesting), 1); + URCU_TLS(cached_procname)[0][0] = '\0'; + CMM_STORE_SHARED(URCU_TLS(procname_nesting), 0); } static -- 2.34.1 From 2c44512a8bb58e1b566c285137c0c38dfa26278f Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Thu, 14 Feb 2019 16:39:57 -0500 Subject: [PATCH 02/16] Fix: additional compiler barriers for procname context Use additional volatile load/stores and compiler barriers to make sure the compiler do not reorder the nesting counter wrt procname cache content load/stores. Signed-off-by: Mathieu Desnoyers --- liblttng-ust/lttng-context-procname.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/liblttng-ust/lttng-context-procname.c b/liblttng-ust/lttng-context-procname.c index 95d5f28d..8c1520ad 100644 --- a/liblttng-ust/lttng-context-procname.c +++ b/liblttng-ust/lttng-context-procname.c @@ -49,24 +49,29 @@ static DEFINE_URCU_TLS(int, procname_nesting); static inline char *wrapper_getprocname(void) { - int nesting = URCU_TLS(procname_nesting); + int nesting = CMM_LOAD_SHARED(URCU_TLS(procname_nesting)); if (caa_unlikely(nesting >= PROCNAME_NESTING_MAX)) return ""; if (caa_unlikely(!URCU_TLS(cached_procname)[nesting][0])) { CMM_STORE_SHARED(URCU_TLS(procname_nesting), nesting + 1); + /* Increment nesting before updating cache. */ + cmm_barrier(); lttng_ust_getprocname(URCU_TLS(cached_procname)[nesting]); URCU_TLS(cached_procname)[nesting][LTTNG_UST_PROCNAME_LEN - 1] = '\0'; + /* Decrement nesting after updating cache. */ + cmm_barrier(); CMM_STORE_SHARED(URCU_TLS(procname_nesting), nesting); } return URCU_TLS(cached_procname)[nesting]; } +/* Reset should not be called from a signal handler. */ void lttng_context_procname_reset(void) { - URCU_TLS(cached_procname)[1][0] = '\0'; + CMM_STORE_SHARED(URCU_TLS(cached_procname)[1][0], '\0'); CMM_STORE_SHARED(URCU_TLS(procname_nesting), 1); - URCU_TLS(cached_procname)[0][0] = '\0'; + CMM_STORE_SHARED(URCU_TLS(cached_procname)[0][0], '\0'); CMM_STORE_SHARED(URCU_TLS(procname_nesting), 0); } -- 2.34.1 From 060577e34998f721439135e8fc533a0e52d98ff1 Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Fri, 8 Mar 2019 10:01:12 -0500 Subject: [PATCH 03/16] Move wait_shm_mmap initialization to library constructor Prevent us from deadlocking ourself if some glibc implementation decide to hold the dl_load_* locks on fork operation. This happens on Yocto Rocko and up when performing python tracing (import lttngust). Why Yocto decided to patch glibc this way is a mystery (ongoing effort) [1][2][3]. Anyhow, we can prevent this by moving the initialization of the wait_shm_mmap to the library constructor since the dl_load_* locks are nestable mutex. Nothing in the git log for the wait_shm_mmap indicate a specific reason to why it was done inside the listener thread. Doing it inside wait_for_sessiond can help in some corner cases were /dev/shm (or the shm path) files are unlinked. This is not much of an advantage. [1] From yocto master branch: ee9db1a9152e8757ce4d831ff9f4472ff5a57dad [2] From OE-Core: f2e586ebf59a9b7d5b216fc92aeb892069a4b0c1 [3] https://www.mail-archive.com/openembedded-core@lists.openembedded.org/msg101186.html This was tested on a Yocto Rocko qemu x86-64 image with python agent enabled. Signed-off-by: Jonathan Rajotte Signed-off-by: Mathieu Desnoyers --- liblttng-ust/lttng-ust-comm.c | 76 +++++++++++++++++++++++++++-------- 1 file changed, 60 insertions(+), 16 deletions(-) diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index eab2d8eb..61dbb41b 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -264,7 +264,7 @@ struct sock_info global_apps = { .global = 1, .root_handle = -1, - .allowed = 1, + .allowed = 0, .thread_active = 0, .sock_path = LTTNG_DEFAULT_RUNDIR "/" LTTNG_UST_SOCK_FILENAME, @@ -343,6 +343,8 @@ extern void lttng_ring_buffer_client_discard_exit(void); extern void lttng_ring_buffer_client_discard_rt_exit(void); extern void lttng_ring_buffer_metadata_client_exit(void); +static char *get_map_shm(struct sock_info *sock_info); + ssize_t lttng_ust_read(int fd, void *buf, size_t len) { ssize_t ret; @@ -434,25 +436,48 @@ void print_cmd(int cmd, int handle) lttng_ust_obj_get_name(handle), handle); } +static +int setup_global_apps(void) +{ + int ret = 0; + assert(!global_apps.wait_shm_mmap); + + global_apps.wait_shm_mmap = get_map_shm(&global_apps); + if (!global_apps.wait_shm_mmap) { + WARN("Unable to get map shm for global apps. Disabling LTTng-UST global tracing."); + global_apps.allowed = 0; + ret = -EIO; + goto error; + } + + global_apps.allowed = 1; +error: + return ret; +} static int setup_local_apps(void) { + int ret = 0; const char *home_dir; uid_t uid; + assert(!local_apps.wait_shm_mmap); + uid = getuid(); /* * Disallow per-user tracing for setuid binaries. */ if (uid != geteuid()) { assert(local_apps.allowed == 0); - return 0; + ret = 0; + goto end; } home_dir = get_lttng_home_dir(); if (!home_dir) { WARN("HOME environment variable not set. Disabling LTTng-UST per-user tracing."); assert(local_apps.allowed == 0); - return -ENOENT; + ret = -ENOENT; + goto end; } local_apps.allowed = 1; snprintf(local_apps.sock_path, PATH_MAX, "%s/%s/%s", @@ -462,7 +487,16 @@ int setup_local_apps(void) snprintf(local_apps.wait_shm_path, PATH_MAX, "/%s-%u", LTTNG_UST_WAIT_FILENAME, uid); - return 0; + + local_apps.wait_shm_mmap = get_map_shm(&local_apps); + if (!local_apps.wait_shm_mmap) { + WARN("Unable to get map shm for local apps. Disabling LTTng-UST per-user tracing."); + local_apps.allowed = 0; + ret = -EIO; + goto end; + } +end: + return ret; } /* @@ -1305,19 +1339,17 @@ error: static void wait_for_sessiond(struct sock_info *sock_info) { + /* Use ust_lock to check if we should quit. */ if (ust_lock()) { goto quit; } if (wait_poll_fallback) { goto error; } - if (!sock_info->wait_shm_mmap) { - sock_info->wait_shm_mmap = get_map_shm(sock_info); - if (!sock_info->wait_shm_mmap) - goto error; - } ust_unlock(); + assert(sock_info->wait_shm_mmap); + DBG("Waiting for %s apps sessiond", sock_info->name); /* Wait for futex wakeup */ if (uatomic_read((int32_t *) sock_info->wait_shm_mmap)) @@ -1756,8 +1788,15 @@ void __attribute__((constructor)) lttng_ust_init(void) PERROR("sem_init"); } + ret = setup_global_apps(); + if (ret) { + assert(global_apps.allowed == 0); + DBG("global apps setup returned %d", ret); + } + ret = setup_local_apps(); if (ret) { + assert(local_apps.allowed == 0); DBG("local apps setup returned %d", ret); } @@ -1781,14 +1820,18 @@ void __attribute__((constructor)) lttng_ust_init(void) ERR("pthread_attr_setdetachstate: %s", strerror(ret)); } - pthread_mutex_lock(&ust_exit_mutex); - ret = pthread_create(&global_apps.ust_listener, &thread_attr, - ust_listener_thread, &global_apps); - if (ret) { - ERR("pthread_create global: %s", strerror(ret)); + if (global_apps.allowed) { + pthread_mutex_lock(&ust_exit_mutex); + ret = pthread_create(&global_apps.ust_listener, &thread_attr, + ust_listener_thread, &global_apps); + if (ret) { + ERR("pthread_create global: %s", strerror(ret)); + } + global_apps.thread_active = 1; + pthread_mutex_unlock(&ust_exit_mutex); + } else { + handle_register_done(&global_apps); } - global_apps.thread_active = 1; - pthread_mutex_unlock(&ust_exit_mutex); if (local_apps.allowed) { pthread_mutex_lock(&ust_exit_mutex); @@ -1859,6 +1902,7 @@ void lttng_ust_cleanup(int exiting) cleanup_sock_info(&global_apps, exiting); cleanup_sock_info(&local_apps, exiting); local_apps.allowed = 0; + global_apps.allowed = 0; /* * The teardown in this function all affect data structures * accessed under the UST lock by the listener thread. This -- 2.34.1 From 0ebe7f89845aefc7b62229bc35f118bfaf5a3f95 Mon Sep 17 00:00:00 2001 From: Michael Jeanson Date: Thu, 14 Mar 2019 11:39:59 -0400 Subject: [PATCH 04/16] tap-driver.sh: flush stdout after each test result This is useful in a CI system where stdout is fully buffered and you look at the console output to see which test is hanging. Signed-off-by: Michael Jeanson Signed-off-by: Mathieu Desnoyers --- config/tap-driver.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/tap-driver.sh b/config/tap-driver.sh index 4254e2b3..12742cae 100755 --- a/config/tap-driver.sh +++ b/config/tap-driver.sh @@ -273,6 +273,9 @@ function report(result, details) msg = msg " " details # Output on console might be colorized. print decorate_result(result) msg + # Flush stdout after each test result, this is useful when stdout + # is buffered, for example in a CI system. + fflush() # Log the result in the log file too, to help debugging (this is # especially true when said result is a TAP error or "Bail out!"). print result msg | "cat >&3"; -- 2.34.1 From bc6aca41dbe090e52277734119baf142fc70d79e Mon Sep 17 00:00:00 2001 From: Sebastien Boisvert Date: Thu, 14 Mar 2019 08:56:15 -0400 Subject: [PATCH 05/16] doc: remove repeated word in coding style Signed-off-by: Sebastien Boisvert Signed-off-by: Mathieu Desnoyers --- CodingStyle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodingStyle b/CodingStyle index 4fe2bdfe..a7f512ea 100644 --- a/CodingStyle +++ b/CodingStyle @@ -1,6 +1,6 @@ LTTng-UST Coding Style -The coding style used for this project follows the the Linux kernel +The coding style used for this project follows the Linux kernel guide lines. Please refer to: - Linux kernel Documentation/CodingStyle document for details, -- 2.34.1 From 6e9ac4ae894690c95df4566289422c4c05ab472a Mon Sep 17 00:00:00 2001 From: Michael Jeanson Date: Thu, 14 Mar 2019 12:31:35 -0400 Subject: [PATCH 06/16] Code cleanup in contexts Signed-off-by: Michael Jeanson Signed-off-by: Mathieu Desnoyers --- liblttng-ust/lttng-context-cpu-id.c | 5 +---- liblttng-ust/lttng-context-perf-counters.c | 5 +---- liblttng-ust/lttng-context-procname.c | 10 ++-------- liblttng-ust/lttng-context-pthread-id.c | 5 +---- 4 files changed, 5 insertions(+), 20 deletions(-) diff --git a/liblttng-ust/lttng-context-cpu-id.c b/liblttng-ust/lttng-context-cpu-id.c index 7cbf3cea..a3252f15 100644 --- a/liblttng-ust/lttng-context-cpu-id.c +++ b/liblttng-ust/lttng-context-cpu-id.c @@ -61,10 +61,7 @@ static void cpu_id_get_value(struct lttng_ctx_field *field, struct lttng_ctx_value *value) { - int cpu; - - cpu = lttng_ust_get_cpu(); - value->u.s64 = cpu; + value->u.s64 = lttng_ust_get_cpu(); } int lttng_add_cpu_id_to_ctx(struct lttng_ctx **ctx) diff --git a/liblttng-ust/lttng-context-perf-counters.c b/liblttng-ust/lttng-context-perf-counters.c index a15417cc..4816f89b 100644 --- a/liblttng-ust/lttng-context-perf-counters.c +++ b/liblttng-ust/lttng-context-perf-counters.c @@ -367,10 +367,7 @@ static void perf_counter_get_value(struct lttng_ctx_field *field, struct lttng_ctx_value *value) { - uint64_t v; - - v = wrapper_perf_counter_read(field); - value->u.s64 = v; + value->u.s64 = wrapper_perf_counter_read(field); } /* Called with UST lock held */ diff --git a/liblttng-ust/lttng-context-procname.c b/liblttng-ust/lttng-context-procname.c index 8c1520ad..c6d02cf6 100644 --- a/liblttng-ust/lttng-context-procname.c +++ b/liblttng-ust/lttng-context-procname.c @@ -78,10 +78,7 @@ void lttng_context_procname_reset(void) static size_t procname_get_size(struct lttng_ctx_field *field, size_t offset) { - size_t size = 0; - - size += LTTNG_UST_PROCNAME_LEN; - return size; + return LTTNG_UST_PROCNAME_LEN; } static @@ -99,10 +96,7 @@ static void procname_get_value(struct lttng_ctx_field *field, struct lttng_ctx_value *value) { - char *procname; - - procname = wrapper_getprocname(); - value->u.str = procname; + value->u.str = wrapper_getprocname(); } int lttng_add_procname_to_ctx(struct lttng_ctx **ctx) diff --git a/liblttng-ust/lttng-context-pthread-id.c b/liblttng-ust/lttng-context-pthread-id.c index 552100de..5f9faf85 100644 --- a/liblttng-ust/lttng-context-pthread-id.c +++ b/liblttng-ust/lttng-context-pthread-id.c @@ -52,10 +52,7 @@ static void pthread_id_get_value(struct lttng_ctx_field *field, struct lttng_ctx_value *value) { - unsigned long pthread_id; - - pthread_id = (unsigned long) pthread_self(); - value->u.s64 = pthread_id; + value->u.s64 = (unsigned long) pthread_self(); } int lttng_add_pthread_id_to_ctx(struct lttng_ctx **ctx) -- 2.34.1 From 5de7c318804a7b1edce8562d4891b4c74aac0677 Mon Sep 17 00:00:00 2001 From: Michael Jeanson Date: Wed, 20 Mar 2019 11:07:35 -0400 Subject: [PATCH 07/16] compat: work around broken _SC_NPROCESSORS_CONF on MUSL libc On MUSL libc the _SC_NPROCESSORS_CONF sysconf will report the number of CPUs allocated to the task based on the affinity mask instead of the total number of CPUs configured on the system. Signed-off-by: Michael Jeanson Signed-off-by: Mathieu Desnoyers --- libringbuffer/smp.c | 66 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/libringbuffer/smp.c b/libringbuffer/smp.c index 9e7114be..656a75da 100644 --- a/libringbuffer/smp.c +++ b/libringbuffer/smp.c @@ -2,6 +2,7 @@ * libringbuffer/smp.c * * Copyright (C) 2011-2012 Mathieu Desnoyers + * Copyright (C) 2019 Michael Jeanson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,6 +27,7 @@ int __num_possible_cpus; +#if (defined(__GLIBC__) || defined( __UCLIBC__)) void _get_num_possible_cpus(void) { int result; @@ -43,3 +45,67 @@ void _get_num_possible_cpus(void) return; __num_possible_cpus = result; } + +#else + +/* + * The MUSL libc implementation of the _SC_NPROCESSORS_CONF sysconf does not + * return the number of configured CPUs in the system but relies on the cpu + * affinity mask of the current task. + * + * So instead we use a strategy similar to GLIBC's, counting the cpu + * directories in "/sys/devices/system/cpu" and fallback on the value from + * sysconf if it fails. + */ + +#include +#include +#include +#include +#include + +#define __max(a,b) ((a)>(b)?(a):(b)) + +void _get_num_possible_cpus(void) +{ + int result, count = 0; + DIR *cpudir; + struct dirent *entry; + + cpudir = opendir("/sys/devices/system/cpu"); + if (cpudir == NULL) + goto end; + + /* + * Count the number of directories named "cpu" followed by and + * integer. This is the same strategy as glibc uses. + */ + while ((entry = readdir(cpudir))) { + if (entry->d_type == DT_DIR && + strncmp(entry->d_name, "cpu", 3) == 0) { + + char *endptr; + unsigned long cpu_num; + + cpu_num = strtoul(entry->d_name + 3, &endptr, 10); + if ((cpu_num < ULONG_MAX) && (endptr != entry->d_name + 3) + && (*endptr == '\0')) { + count++; + } + } + } + +end: + /* + * Get the sysconf value as a fallback. Keep the highest number. + */ + result = __max(sysconf(_SC_NPROCESSORS_CONF), count); + + /* + * If both methods failed, don't store the value. + */ + if (result < 1) + return; + __num_possible_cpus = result; +} +#endif -- 2.34.1 From 3207efeef9d6550e2c811c814c574e7cabb6f368 Mon Sep 17 00:00:00 2001 From: Michael Jeanson Date: Wed, 20 Mar 2019 17:02:25 -0400 Subject: [PATCH 08/16] Report perf integration status at configure Signed-off-by: Michael Jeanson Signed-off-by: Mathieu Desnoyers --- configure.ac | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configure.ac b/configure.ac index 9ab76501..3e443132 100644 --- a/configure.ac +++ b/configure.ac @@ -615,6 +615,9 @@ PPRINT_PROP_BOOL_CUSTOM([JNI interface (JNI)], $value, [use --enable-jni-interfa test "x$python_agent" = xyes && value=1 || value=0 PPRINT_PROP_BOOL_CUSTOM([Python agent], $value, [use --enable-python-agent]) +test "x$have_perf_event" = "xyes" && value=1 || value=0 +PPRINT_PROP_BOOL_CUSTOM([Perf event integration], $value) + test "x$enable_numa" = xyes && value=1 || value=0 PPRINT_PROP_BOOL([NUMA], $value) -- 2.34.1 From db56acaff475812dfd774a52b3d54eae5c115315 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 26 Mar 2019 12:41:30 -0400 Subject: [PATCH 09/16] Add LTTNG_PACKED ifdefs to validate that it is defined If LTTNG_PACKED is used to specify whether a structure is packed, but we end up forgetting inclusion of lttng/ust-compiler.h (which defines it), we end up silently _not_ packing the data structure, because LTTNG_PACKED will be considered to be an identifier by the compiler, and therefore simply ignored. There are no such instances in lttng-ust, but let's add a ifdef check. Signed-off-by: Mathieu Desnoyers --- include/lttng/ust-abi.h | 4 ++++ include/lttng/ust-ctl.h | 4 ++++ include/lttng/ust-events.h | 4 ++++ include/ust-comm.h | 4 ++++ liblttng-ust/filter-bytecode.h | 4 ++++ 5 files changed, 20 insertions(+) diff --git a/include/lttng/ust-abi.h b/include/lttng/ust-abi.h index 4976b1bf..01e9daf4 100644 --- a/include/lttng/ust-abi.h +++ b/include/lttng/ust-abi.h @@ -30,6 +30,10 @@ #include #include +#ifndef LTTNG_PACKED +#error "LTTNG_PACKED should be defined" +#endif + #ifndef __ust_stringify #define __ust_stringify1(x) #x #define __ust_stringify(x) __ust_stringify1(x) diff --git a/include/lttng/ust-ctl.h b/include/lttng/ust-ctl.h index f83124d1..57758edb 100644 --- a/include/lttng/ust-ctl.h +++ b/include/lttng/ust-ctl.h @@ -23,6 +23,10 @@ #include #include +#ifndef LTTNG_PACKED +#error "LTTNG_PACKED should be defined" +#endif + #ifndef LTTNG_UST_UUID_LEN #define LTTNG_UST_UUID_LEN 16 #endif diff --git a/include/lttng/ust-events.h b/include/lttng/ust-events.h index 902f2b2f..fefb8585 100644 --- a/include/lttng/ust-events.h +++ b/include/lttng/ust-events.h @@ -39,6 +39,10 @@ #include #include +#ifndef LTTNG_PACKED +#error "LTTNG_PACKED should be defined" +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/include/ust-comm.h b/include/ust-comm.h index 6a08b306..10dbca21 100644 --- a/include/ust-comm.h +++ b/include/ust-comm.h @@ -34,6 +34,10 @@ #include #include +#ifndef LTTNG_PACKED +#error "LTTNG_PACKED should be defined" +#endif + /* * Default timeout the application waits for the sessiond to send its * "register done" command. Can be overridden with the environment diff --git a/liblttng-ust/filter-bytecode.h b/liblttng-ust/filter-bytecode.h index 9a2d4c0a..7df0288a 100644 --- a/liblttng-ust/filter-bytecode.h +++ b/liblttng-ust/filter-bytecode.h @@ -29,6 +29,10 @@ #include +#ifndef LTTNG_PACKED +#error "LTTNG_PACKED should be defined" +#endif + /* * offsets are absolute from start of bytecode. */ -- 2.34.1 From db95cf8bf1be068238f12e248f13ed103d86d1e5 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Wed, 10 Apr 2019 10:31:47 -0400 Subject: [PATCH 10/16] Fix: don't access packet header for stream_id and stream_instance_id getters The stream ID and stream instance ID are invariant for a stream, so there is no point reading them from the packet header currently owned by the consumer (between get/put subbuf). Actually, the consumer try to access the stream_id from the live timer when sending a live beacon without getting the reader subbuffer first. Doing so is racy against producers. In typical live scenarios (non-overwrite channels), the producers will always write the same stream id and stream instance id values at the same header offsets, which will "work", except for the initial state of an empty buffer: the value "0" will be returned (erroneously). For the less frequently used scenario of a live session with "overwrite" channels, this is handled by issuing a CHAN_WARN_ON, which disables tracing for the channel, and prints warning to the consumerd console when running consumerd with LTTNG_UST_DEBUG=1. In the case where a ring buffer does not have any data ready, it makes no sense to try to get a subbuffer for reading anyway, so the approach was broken. So return the stream id and stream instance id from the internal data structures rather than reading it from the ring buffer. Signed-off-by: Mathieu Desnoyers --- liblttng-ust/lttng-ring-buffer-client.h | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/liblttng-ust/lttng-ring-buffer-client.h b/liblttng-ust/lttng-ring-buffer-client.h index 0fae8878..ab472352 100644 --- a/liblttng-ust/lttng-ring-buffer-client.h +++ b/liblttng-ust/lttng-ring-buffer-client.h @@ -580,12 +580,11 @@ static int client_stream_id(struct lttng_ust_lib_ring_buffer *buf, struct lttng_ust_shm_handle *handle, uint64_t *stream_id) { - struct packet_header *header; + struct channel *chan = shmp(handle, buf->backend.chan); + struct lttng_channel *lttng_chan = channel_get_private(chan); + + *stream_id = lttng_chan->id; - header = client_packet_header(buf, handle); - if (!header) - return -1; - *stream_id = header->stream_id; return 0; } @@ -616,10 +615,8 @@ static int client_instance_id(struct lttng_ust_lib_ring_buffer *buf, struct lttng_ust_shm_handle *handle, uint64_t *id) { - struct packet_header *header; + *id = buf->backend.cpu; - header = client_packet_header(buf, handle); - *id = header->stream_instance_id; return 0; } -- 2.34.1 From 82df14e46c733a9e0906cf7a11299d83d160e1a0 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Wed, 10 Apr 2019 11:14:03 -0400 Subject: [PATCH 11/16] ust-ctl API: clarify getter usage requirements Signed-off-by: Mathieu Desnoyers --- include/lttng/ust-ctl.h | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/include/lttng/ust-ctl.h b/include/lttng/ust-ctl.h index 57758edb..3404d9c7 100644 --- a/include/lttng/ust-ctl.h +++ b/include/lttng/ust-ctl.h @@ -244,6 +244,12 @@ void ustctl_flush_buffer(struct ustctl_consumer_stream *stream, int producer_active); /* index */ + +/* + * Getters which need to be used on the current packet (between get/put + * or get_next/put_next. + */ + int ustctl_get_timestamp_begin(struct ustctl_consumer_stream *stream, uint64_t *timestamp_begin); int ustctl_get_timestamp_end(struct ustctl_consumer_stream *stream, @@ -254,15 +260,26 @@ int ustctl_get_content_size(struct ustctl_consumer_stream *stream, uint64_t *content_size); int ustctl_get_packet_size(struct ustctl_consumer_stream *stream, uint64_t *packet_size); -int ustctl_get_stream_id(struct ustctl_consumer_stream *stream, - uint64_t *stream_id); -int ustctl_get_current_timestamp(struct ustctl_consumer_stream *stream, - uint64_t *ts); int ustctl_get_sequence_number(struct ustctl_consumer_stream *stream, uint64_t *seq); + +/* + * Getter returning state invariant for the stream, which can be used + * without "get" operation. + */ + +int ustctl_get_stream_id(struct ustctl_consumer_stream *stream, + uint64_t *stream_id); int ustctl_get_instance_id(struct ustctl_consumer_stream *stream, uint64_t *id); +/* + * Getter returning the current timestamp as perceived from the + * tracer. + */ +int ustctl_get_current_timestamp(struct ustctl_consumer_stream *stream, + uint64_t *ts); + /* returns whether UST has perf counters support. */ int ustctl_has_perf_counters(void); -- 2.34.1 From e465639ea30d128bc6dd59448a5bf6551a5da222 Mon Sep 17 00:00:00 2001 From: Michael Jeanson Date: Tue, 16 Apr 2019 16:17:30 -0400 Subject: [PATCH 12/16] Update macros from the autoconf archive Signed-off-by: Michael Jeanson Signed-off-by: Mathieu Desnoyers --- m4/ax_c___attribute__.m4 | 6 ++-- m4/ax_check_class.m4 | 75 +++------------------------------------ m4/ax_check_classpath.m4 | 6 ++-- m4/ax_check_rqrd_class.m4 | 6 ++-- m4/ax_java_options.m4 | 4 +-- m4/ax_jni_include_dir.m4 | 57 ++++++++++++++++++++--------- m4/ax_prog_jar.m4 | 4 +-- m4/ax_prog_java.m4 | 6 ++-- m4/ax_prog_java_works.m4 | 51 +++----------------------- m4/ax_prog_javac.m4 | 6 ++-- m4/ax_prog_javac_works.m4 | 6 ++-- m4/ax_prog_javah.m4 | 35 +++++++++++++----- m4/ax_sys_weak_alias.m4 | 8 ++--- m4/ax_try_compile_java.m4 | 8 ++--- m4/ax_try_run_java.m4 | 4 +-- 15 files changed, 108 insertions(+), 174 deletions(-) diff --git a/m4/ax_c___attribute__.m4 b/m4/ax_c___attribute__.m4 index cf3d62bb..6a1ede15 100644 --- a/m4/ax_c___attribute__.m4 +++ b/m4/ax_c___attribute__.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_c___attribute__.html +# https://www.gnu.org/software/autoconf-archive/ax_c___attribute__.html # =========================================================================== # # SYNOPSIS @@ -28,7 +28,7 @@ # Public License for more details. # # You should have received a copy of the GNU General Public License along -# with this program. If not, see . +# with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure @@ -43,7 +43,7 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 8 +#serial 9 AC_DEFUN([AX_C___ATTRIBUTE__], [ AC_CACHE_CHECK([for __attribute__], [ax_cv___attribute__], diff --git a/m4/ax_check_class.m4 b/m4/ax_check_class.m4 index 42b51d72..e673c2d3 100644 --- a/m4/ax_check_class.m4 +++ b/m4/ax_check_class.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_check_class.html +# https://www.gnu.org/software/autoconf-archive/ax_check_class.html # =========================================================================== # # SYNOPSIS @@ -36,7 +36,7 @@ # Public License for more details. # # You should have received a copy of the GNU General Public License along -# with this program. If not, see . +# with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure @@ -51,83 +51,18 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 7 +#serial 12 AU_ALIAS([AC_CHECK_CLASS], [AX_CHECK_CLASS]) AC_DEFUN([AX_CHECK_CLASS],[ AC_REQUIRE([AX_PROG_JAVA]) ac_var_name=`echo $1 | sed 's/\./_/g'` -dnl Normaly I'd use a AC_CACHE_CHECK here but since the variable name is +dnl Normally I'd use a AC_CACHE_CHECK here but since the variable name is dnl dynamic I need an extra level of extraction AC_MSG_CHECKING([for $1 class]) AC_CACHE_VAL(ax_cv_class_$ac_var_name, [ -if test x$ac_cv_prog_uudecode_base64 = xyes; then -dnl /** -dnl * Test.java: used to test dynamicaly if a class exists. -dnl */ -dnl public class Test -dnl { -dnl -dnl public static void -dnl main( String[] argv ) -dnl { -dnl Class lib; -dnl if (argv.length < 1) -dnl { -dnl System.err.println ("Missing argument"); -dnl System.exit (77); -dnl } -dnl try -dnl { -dnl lib = Class.forName (argv[0]); -dnl } -dnl catch (ClassNotFoundException e) -dnl { -dnl System.exit (1); -dnl } -dnl lib = null; -dnl System.exit (0); -dnl } -dnl -dnl } -cat << \EOF > Test.uue -begin-base64 644 Test.class -yv66vgADAC0AKQcAAgEABFRlc3QHAAQBABBqYXZhL2xhbmcvT2JqZWN0AQAE -bWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARDb2RlAQAPTGluZU51 -bWJlclRhYmxlDAAKAAsBAANlcnIBABVMamF2YS9pby9QcmludFN0cmVhbTsJ -AA0ACQcADgEAEGphdmEvbGFuZy9TeXN0ZW0IABABABBNaXNzaW5nIGFyZ3Vt -ZW50DAASABMBAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWCgAV -ABEHABYBABNqYXZhL2lvL1ByaW50U3RyZWFtDAAYABkBAARleGl0AQAEKEkp -VgoADQAXDAAcAB0BAAdmb3JOYW1lAQAlKExqYXZhL2xhbmcvU3RyaW5nOylM -amF2YS9sYW5nL0NsYXNzOwoAHwAbBwAgAQAPamF2YS9sYW5nL0NsYXNzBwAi -AQAgamF2YS9sYW5nL0NsYXNzTm90Rm91bmRFeGNlcHRpb24BAAY8aW5pdD4B -AAMoKVYMACMAJAoAAwAlAQAKU291cmNlRmlsZQEACVRlc3QuamF2YQAhAAEA -AwAAAAAAAgAJAAUABgABAAcAAABtAAMAAwAAACkqvgSiABCyAAwSD7YAFBBN -uAAaKgMyuAAeTKcACE0EuAAaAUwDuAAasQABABMAGgAdACEAAQAIAAAAKgAK -AAAACgAAAAsABgANAA4ADgATABAAEwASAB4AFgAiABgAJAAZACgAGgABACMA -JAABAAcAAAAhAAEAAQAAAAUqtwAmsQAAAAEACAAAAAoAAgAAAAQABAAEAAEA -JwAAAAIAKA== -==== -EOF - if $UUDECODE Test.uue; then - : - else - echo "configure: __oline__: uudecode had trouble decoding base 64 file 'Test.uue'" >&AS_MESSAGE_LOG_FD - echo "configure: failed file was:" >&AS_MESSAGE_LOG_FD - cat Test.uue >&AS_MESSAGE_LOG_FD - ac_cv_prog_uudecode_base64=no - fi - rm -f Test.uue - if AC_TRY_COMMAND($JAVA -classpath ".:$CLASSPATH" $JAVAFLAGS Test $1) >/dev/null 2>&1; then - eval "ac_cv_class_$ac_var_name=yes" - else - eval "ac_cv_class_$ac_var_name=no" - fi - rm -f Test.class -else AX_TRY_COMPILE_JAVA([$1], , [eval "ac_cv_class_$ac_var_name=yes"], [eval "ac_cv_class_$ac_var_name=no"]) -fi eval "ac_var_val=$`eval echo ac_cv_class_$ac_var_name`" eval "HAVE_$ac_var_name=$`echo ac_cv_class_$ac_var_val`" HAVE_LAST_CLASS=$ac_var_val @@ -137,7 +72,7 @@ else ifelse([$3], , :, [$3]) fi ]) -dnl for some reason the above statment didn't fall though here? +dnl for some reason the above statement didn't fall though here? dnl do scripts have variable scoping? eval "ac_var_val=$`eval echo ac_cv_class_$ac_var_name`" AC_MSG_RESULT($ac_var_val) diff --git a/m4/ax_check_classpath.m4 b/m4/ax_check_classpath.m4 index 3c9081a0..e08a253d 100644 --- a/m4/ax_check_classpath.m4 +++ b/m4/ax_check_classpath.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_check_classpath.html +# https://www.gnu.org/software/autoconf-archive/ax_check_classpath.html # =========================================================================== # # SYNOPSIS @@ -33,7 +33,7 @@ # Public License for more details. # # You should have received a copy of the GNU General Public License along -# with this program. If not, see . +# with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure @@ -48,7 +48,7 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 5 +#serial 6 AU_ALIAS([AC_CHECK_CLASSPATH], [AX_CHECK_CLASSPATH]) AC_DEFUN([AX_CHECK_CLASSPATH],[ diff --git a/m4/ax_check_rqrd_class.m4 b/m4/ax_check_rqrd_class.m4 index 8f14241b..baa041ac 100644 --- a/m4/ax_check_rqrd_class.m4 +++ b/m4/ax_check_rqrd_class.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_check_rqrd_class.html +# https://www.gnu.org/software/autoconf-archive/ax_check_rqrd_class.html # =========================================================================== # # SYNOPSIS @@ -35,7 +35,7 @@ # Public License for more details. # # You should have received a copy of the GNU General Public License along -# with this program. If not, see . +# with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure @@ -50,7 +50,7 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 5 +#serial 6 AU_ALIAS([AC_CHECK_RQRD_CLASS], [AX_CHECK_RQRD_CLASS]) AC_DEFUN([AX_CHECK_RQRD_CLASS],[ diff --git a/m4/ax_java_options.m4 b/m4/ax_java_options.m4 index 36c10d92..722d7880 100644 --- a/m4/ax_java_options.m4 +++ b/m4/ax_java_options.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_java_options.html +# https://www.gnu.org/software/autoconf-archive/ax_java_options.html # =========================================================================== # # SYNOPSIS @@ -27,7 +27,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 6 +#serial 7 AU_ALIAS([AC_JAVA_OPTIONS], [AX_JAVA_OPTIONS]) AC_DEFUN([AX_JAVA_OPTIONS],[ diff --git a/m4/ax_jni_include_dir.m4 b/m4/ax_jni_include_dir.m4 index b664d80b..ae7a5f04 100644 --- a/m4/ax_jni_include_dir.m4 +++ b/m4/ax_jni_include_dir.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html +# https://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html # =========================================================================== # # SYNOPSIS @@ -32,6 +32,10 @@ # # - at the configure level, setenv JAVAC # +# This macro depends on AC_CANONICAL_HOST which requires that config.guess +# and config.sub be distributed along with the source code. See autoconf +# manual for details. +# # Note: This macro can work with the autoconf M4 macros for Java programs. # This particular macro is not part of the original set of macros. # @@ -44,11 +48,13 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 10 +#serial 15 AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR]) AC_DEFUN([AX_JNI_INCLUDE_DIR],[ +AC_REQUIRE([AC_CANONICAL_HOST]) + JNI_INCLUDE_DIRS="" if test "x$JAVA_HOME" != x; then @@ -66,9 +72,17 @@ else fi case "$host_os" in - darwin*) _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'` - _JINC="$_JTOPDIR/Headers";; - *) _JINC="$_JTOPDIR/include";; + darwin*) # Apple Java headers are inside the Xcode bundle. + macos_version=$(sw_vers -productVersion | sed -n -e 's/^@<:@0-9@:>@*.\(@<:@0-9@:>@*\).@<:@0-9@:>@*/\1/p') + if @<:@ "$macos_version" -gt "7" @:>@; then + _JTOPDIR="$(xcrun --show-sdk-path)/System/Library/Frameworks/JavaVM.framework" + _JINC="$_JTOPDIR/Headers" + else + _JTOPDIR="/System/Library/Frameworks/JavaVM.framework" + _JINC="$_JTOPDIR/Headers" + fi + ;; + *) _JINC="$_JTOPDIR/include";; esac _AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR]) _AS_ECHO_LOG([_JINC=$_JINC]) @@ -76,18 +90,27 @@ _AS_ECHO_LOG([_JINC=$_JINC]) # On Mac OS X 10.6.4, jni.h is a symlink: # /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h # -> ../../CurrentJDK/Headers/jni.h. -AC_CHECK_FILE([$_JINC/jni.h], - [JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JINC"], - [_JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'` - AC_CHECK_FILE([$_JTOPDIR/include/jni.h], - [JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include"], - AC_MSG_ERROR([cannot find JDK header files])) - ]) +AC_CACHE_CHECK(jni headers, ac_cv_jni_header_path, +[ + if test -f "$_JINC/jni.h"; then + ac_cv_jni_header_path="$_JINC" + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path" + else + _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'` + if test -f "$_JTOPDIR/include/jni.h"; then + ac_cv_jni_header_path="$_JTOPDIR/include" + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path" + else + ac_cv_jni_header_path=none + fi + fi +]) # get the likely subdirectories for system specific java includes case "$host_os" in bsdi*) _JNI_INC_SUBDIRS="bsdos";; freebsd*) _JNI_INC_SUBDIRS="freebsd";; +darwin*) _JNI_INC_SUBDIRS="darwin";; linux*) _JNI_INC_SUBDIRS="linux genunix";; osf*) _JNI_INC_SUBDIRS="alpha";; solaris*) _JNI_INC_SUBDIRS="solaris";; @@ -96,13 +119,15 @@ cygwin*) _JNI_INC_SUBDIRS="win32";; *) _JNI_INC_SUBDIRS="genunix";; esac -# add any subdirectories that are present -for JINCSUBDIR in $_JNI_INC_SUBDIRS -do +if test "x$ac_cv_jni_header_path" != "xnone"; then + # add any subdirectories that are present + for JINCSUBDIR in $_JNI_INC_SUBDIRS + do if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR" fi -done + done +fi ]) # _ACJNI_FOLLOW_SYMLINKS diff --git a/m4/ax_prog_jar.m4 b/m4/ax_prog_jar.m4 index 3c60fcaf..d474912a 100644 --- a/m4/ax_prog_jar.m4 +++ b/m4/ax_prog_jar.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_prog_jar.html +# https://www.gnu.org/software/autoconf-archive/ax_prog_jar.html # =========================================================================== # # SYNOPSIS @@ -37,7 +37,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 7 +#serial 8 AU_ALIAS([AC_PROG_JAR], [AX_PROG_JAR]) AC_DEFUN([AX_PROG_JAR],[ diff --git a/m4/ax_prog_java.m4 b/m4/ax_prog_java.m4 index 03961db5..c2e6964e 100644 --- a/m4/ax_prog_java.m4 +++ b/m4/ax_prog_java.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_prog_java.html +# https://www.gnu.org/software/autoconf-archive/ax_prog_java.html # =========================================================================== # # SYNOPSIS @@ -85,7 +85,7 @@ # Public License for more details. # # You should have received a copy of the GNU General Public License along -# with this program. If not, see . +# with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure @@ -100,7 +100,7 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 9 +#serial 10 AU_ALIAS([AC_PROG_JAVA], [AX_PROG_JAVA]) AC_DEFUN([AX_PROG_JAVA],[ diff --git a/m4/ax_prog_java_works.m4 b/m4/ax_prog_java_works.m4 index 54e132af..bc705261 100644 --- a/m4/ax_prog_java_works.m4 +++ b/m4/ax_prog_java_works.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_prog_java_works.html +# https://www.gnu.org/software/autoconf-archive/ax_prog_java_works.html # =========================================================================== # # SYNOPSIS @@ -32,7 +32,7 @@ # Public License for more details. # # You should have received a copy of the GNU General Public License along -# with this program. If not, see . +# with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure @@ -47,57 +47,16 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 9 +#serial 11 AU_ALIAS([AC_PROG_JAVA_WORKS], [AX_PROG_JAVA_WORKS]) AC_DEFUN([AX_PROG_JAVA_WORKS], [ -AC_PATH_PROG(UUDECODE, uudecode, [no]) -if test x$UUDECODE != xno; then -AC_CACHE_CHECK([if uudecode can decode base 64 file], ac_cv_prog_uudecode_base64, [ -dnl /** -dnl * Test.java: used to test if java compiler works. -dnl */ -dnl public class Test -dnl { -dnl -dnl public static void -dnl main( String[] argv ) -dnl { -dnl System.exit (0); -dnl } -dnl -dnl } -cat << \EOF > Test.uue -begin-base64 644 Test.class -yv66vgADAC0AFQcAAgEABFRlc3QHAAQBABBqYXZhL2xhbmcvT2JqZWN0AQAE -bWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARDb2RlAQAPTGluZU51 -bWJlclRhYmxlDAAKAAsBAARleGl0AQAEKEkpVgoADQAJBwAOAQAQamF2YS9s -YW5nL1N5c3RlbQEABjxpbml0PgEAAygpVgwADwAQCgADABEBAApTb3VyY2VG -aWxlAQAJVGVzdC5qYXZhACEAAQADAAAAAAACAAkABQAGAAEABwAAACEAAQAB -AAAABQO4AAyxAAAAAQAIAAAACgACAAAACgAEAAsAAQAPABAAAQAHAAAAIQAB -AAEAAAAFKrcAErEAAAABAAgAAAAKAAIAAAAEAAQABAABABMAAAACABQ= -==== -EOF -if $UUDECODE Test.uue; then - ac_cv_prog_uudecode_base64=yes -else - echo "configure: __oline__: uudecode had trouble decoding base 64 file 'Test.uue'" >&AS_MESSAGE_LOG_FD - echo "configure: failed file was:" >&AS_MESSAGE_LOG_FD - cat Test.uue >&AS_MESSAGE_LOG_FD - ac_cv_prog_uudecode_base64=no -fi -rm -f Test.uue]) -fi -if test x$ac_cv_prog_uudecode_base64 != xyes; then - rm -f Test.class - AC_MSG_WARN([I have to compile Test.class from scratch]) if test x$ac_cv_prog_javac_works = xno; then AC_MSG_ERROR([Cannot compile java source. $JAVAC does not work properly]) fi if test x$ac_cv_prog_javac_works = x; then AX_PROG_JAVAC fi -fi AC_CACHE_CHECK(if $JAVA works, ac_cv_prog_java_works, [ JAVA_TEST=Test.java CLASS_TEST=Test.class @@ -111,7 +70,6 @@ public static void main (String args[]) { } } EOF changequote([, ])dnl -if test x$ac_cv_prog_uudecode_base64 != xyes; then if AC_TRY_COMMAND($JAVAC $JAVACFLAGS $JAVA_TEST) && test -s $CLASS_TEST; then : else @@ -119,7 +77,6 @@ if test x$ac_cv_prog_uudecode_base64 != xyes; then cat $JAVA_TEST >&AS_MESSAGE_LOG_FD AC_MSG_ERROR(The Java compiler $JAVAC failed (see config.log, check the CLASSPATH?)) fi -fi if AC_TRY_COMMAND($JAVA -classpath . $JAVAFLAGS $TEST) >/dev/null 2>&1; then ac_cv_prog_java_works=yes else @@ -127,7 +84,7 @@ else cat $JAVA_TEST >&AS_MESSAGE_LOG_FD AC_MSG_ERROR(The Java VM $JAVA failed (see config.log, check the CLASSPATH?)) fi -rm -fr $JAVA_TEST $CLASS_TEST Test.uue +rm -f $JAVA_TEST $CLASS_TEST ]) AC_PROVIDE([$0])dnl ] diff --git a/m4/ax_prog_javac.m4 b/m4/ax_prog_javac.m4 index d061243c..8abb733f 100644 --- a/m4/ax_prog_javac.m4 +++ b/m4/ax_prog_javac.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_prog_javac.html +# https://www.gnu.org/software/autoconf-archive/ax_prog_javac.html # =========================================================================== # # SYNOPSIS @@ -49,7 +49,7 @@ # Public License for more details. # # You should have received a copy of the GNU General Public License along -# with this program. If not, see . +# with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure @@ -64,7 +64,7 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 7 +#serial 8 AU_ALIAS([AC_PROG_JAVAC], [AX_PROG_JAVAC]) AC_DEFUN([AX_PROG_JAVAC],[ diff --git a/m4/ax_prog_javac_works.m4 b/m4/ax_prog_javac_works.m4 index 7dfa1e37..9b48149d 100644 --- a/m4/ax_prog_javac_works.m4 +++ b/m4/ax_prog_javac_works.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_prog_javac_works.html +# https://www.gnu.org/software/autoconf-archive/ax_prog_javac_works.html # =========================================================================== # # SYNOPSIS @@ -32,7 +32,7 @@ # Public License for more details. # # You should have received a copy of the GNU General Public License along -# with this program. If not, see . +# with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure @@ -47,7 +47,7 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 6 +#serial 7 AU_ALIAS([AC_PROG_JAVAC_WORKS], [AX_PROG_JAVAC_WORKS]) AC_DEFUN([AX_PROG_JAVAC_WORKS],[ diff --git a/m4/ax_prog_javah.m4 b/m4/ax_prog_javah.m4 index 2809f29c..935ec896 100644 --- a/m4/ax_prog_javah.m4 +++ b/m4/ax_prog_javah.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_prog_javah.html +# https://www.gnu.org/software/autoconf-archive/ax_prog_javah.html # =========================================================================== # # SYNOPSIS @@ -21,7 +21,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 7 +#serial 11 AU_ALIAS([AC_PROG_JAVAH], [AX_PROG_JAVAH]) AC_DEFUN([AX_PROG_JAVAH],[ @@ -30,18 +30,35 @@ AC_REQUIRE([AC_PROG_CPP])dnl AC_PATH_PROG(JAVAH,javah) AS_IF([test -n "$ac_cv_path_JAVAH"], [ - AC_TRY_CPP([#include ],,[ + AC_PREPROC_IFELSE([AC_LANG_SOURCE([[#include ]])],[],[ ac_save_CPPFLAGS="$CPPFLAGS" - ax_prog_javah_bin_dir=`AS_DIRNAME([$ac_cv_path_JAVAH])` - ac_dir="`AS_DIRNAME([$ax_prog_javah_bin])`/include" + _ACJAVAH_FOLLOW_SYMLINKS("$ac_cv_path_JAVAH") + ax_prog_javah_bin_dir=`AS_DIRNAME([$_ACJAVAH_FOLLOWED])` + ac_dir="`AS_DIRNAME([$ax_prog_javah_bin_dir])`/include" AS_CASE([$build_os], - [cygwin*], + [cygwin*|mingw*], [ac_machdep=win32], [ac_machdep=`AS_ECHO($build_os) | sed 's,[[-0-9]].*,,'`]) CPPFLAGS="$ac_save_CPPFLAGS -I$ac_dir -I$ac_dir/$ac_machdep" - AC_TRY_CPP([#include ], - ac_save_CPPFLAGS="$CPPFLAGS", - AC_MSG_WARN([unable to include ])) + AC_PREPROC_IFELSE([AC_LANG_SOURCE([[#include ]])], + [ac_save_CPPFLAGS="$CPPFLAGS"], + [AC_MSG_WARN([unable to include ])]) CPPFLAGS="$ac_save_CPPFLAGS"]) ]) ]) + +AC_DEFUN([_ACJAVAH_FOLLOW_SYMLINKS],[ +# find the include directory relative to the javac executable +_cur="$1" +while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do + AC_MSG_CHECKING([symlink for $_cur]) + _slink=`ls -ld "$_cur" | sed 's/.* -> //'` + case "$_slink" in + /*) _cur="$_slink";; + # 'X' avoids triggering unwanted echo options. + *) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";; + esac + AC_MSG_RESULT([$_cur]) +done +_ACJAVAH_FOLLOWED="$_cur" +]) diff --git a/m4/ax_sys_weak_alias.m4 b/m4/ax_sys_weak_alias.m4 index e1bfd336..733b1ddd 100644 --- a/m4/ax_sys_weak_alias.m4 +++ b/m4/ax_sys_weak_alias.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_sys_weak_alias.html +# https://www.gnu.org/software/autoconf-archive/ax_sys_weak_alias.html # =========================================================================== # # SYNOPSIS @@ -22,8 +22,8 @@ # another object file. # # There are four known schemes of declaring weak symbols; each scheme is -# checked in turn, and the first one found is prefered. Note that only one -# of the mentioned preprocessor macros will be defined! +# checked in turn, and the first one found is preferred. Note that only +# one of the mentioned preprocessor macros will be defined! # # 1. Function attributes # @@ -110,7 +110,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 6 +#serial 8 AU_ALIAS([KLM_SYS_WEAK_ALIAS], [AX_SYS_WEAK_ALIAS]) AC_DEFUN([AX_SYS_WEAK_ALIAS], [ diff --git a/m4/ax_try_compile_java.m4 b/m4/ax_try_compile_java.m4 index a8ed6b2a..245c36c4 100644 --- a/m4/ax_try_compile_java.m4 +++ b/m4/ax_try_compile_java.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_try_compile_java.html +# https://www.gnu.org/software/autoconf-archive/ax_try_compile_java.html # =========================================================================== # # SYNOPSIS @@ -29,7 +29,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 8 +#serial 10 AU_ALIAS([AC_TRY_COMPILE_JAVA], [AX_TRY_COMPILE_JAVA]) AC_DEFUN([AX_TRY_COMPILE_JAVA],[ @@ -48,8 +48,8 @@ dnl Don't remove the temporary files here, so they can be examined. else echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD cat Test.java >&AS_MESSAGE_LOG_FD -ifelse([$4], , , [ rm -fr Test.java Test.class +ifelse([$4], , , [ rm -f Test.java Test.class $4 ])dnl fi -rm -fr Test.java Test.class]) +rm -f Test.java Test.class]) diff --git a/m4/ax_try_run_java.m4 b/m4/ax_try_run_java.m4 index c680f03f..2ebb86d6 100644 --- a/m4/ax_try_run_java.m4 +++ b/m4/ax_try_run_java.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_try_run_java.html +# https://www.gnu.org/software/autoconf-archive/ax_try_run_java.html # =========================================================================== # # SYNOPSIS @@ -29,7 +29,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 2 +#serial 3 AU_ALIAS([AC_TRY_RUN_JAVA], [AX_TRY_RUN_JAVA]) AC_DEFUN([AX_TRY_RUN_JAVA],[ -- 2.34.1 From b8a1677cb28a65001cbafcdf3c69339c48d8c652 Mon Sep 17 00:00:00 2001 From: Michael Jeanson Date: Tue, 16 Apr 2019 16:17:31 -0400 Subject: [PATCH 13/16] Harmonize rw_prog_cxx_works macro across projects Signed-off-by: Michael Jeanson Signed-off-by: Mathieu Desnoyers --- configure.ac | 2 +- m4/rw_prog_cxx_works.m4 | 26 ++++++++++++++++++++------ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index 3e443132..52fc3f68 100644 --- a/configure.ac +++ b/configure.ac @@ -55,7 +55,7 @@ AC_SYS_LARGEFILE AC_PROG_CC AC_PROG_CC_STDC AC_PROG_CXX -rw_PROG_CXX_WORKS +RW_PROG_CXX_WORKS AM_CONDITIONAL([CXX_WORKS], [test "x$rw_cv_prog_cxx_works" = "xyes"]) # Check if the compiler support weak symbols diff --git a/m4/rw_prog_cxx_works.m4 b/m4/rw_prog_cxx_works.m4 index 086af254..f3d6bde6 100644 --- a/m4/rw_prog_cxx_works.m4 +++ b/m4/rw_prog_cxx_works.m4 @@ -1,11 +1,25 @@ -# rw_PROG_CXX_WORKS +# SYNOPSIS # -# Check whether the C++ compiler works. There's a bit of oversight in -# autoconf that will set the C++ compiler to g++ if no compiler is found, -# even if g++ is not present! So we need an extra test to make sure that -# the compiler works. +# RW_PROG_CXX_WORKS # -AC_DEFUN([rw_PROG_CXX_WORKS], [ +# DESCRIPTION +# +# RW_PROG_CXX_WORKS checks whether the C++ compiler works. +# +# There's a bit of oversight in autoconf that will set the C++ compiler to +# g++ if no compiler is found, even if g++ is not present! So we need an +# extra test to make sure that the compiler works. +# +# LICENSE +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 1 + +AC_DEFUN([RW_PROG_CXX_WORKS], [ AC_REQUIRE([AC_PROG_CXX]) AC_CACHE_CHECK([whether the C++ compiler works], [rw_cv_prog_cxx_works], -- 2.34.1 From 6c737d0594cac0d969e1948ea1ed55c15be9cec8 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 30 Apr 2019 11:23:44 -0400 Subject: [PATCH 14/16] Fix: timestamp_end field should include all events within sub-buffer Fix for timestamp_end not including all events within sub-buffer. This happens if a thread is preempted/interrupted for a long time between reserve and commit (e.g. in the middle of a packet), which causes the timestamp used for timestamp_end field of the packet header to be lower than the timestamp of the last events in the buffer (those following the event that was preempted/interrupted between reserve and commit). The fix involves sampling the timestamp when doing the last space reservation in a sub-buffer (which necessarily happens before doing the delivery after its last commit). Save this timestamp temporarily in a per-sub-buffer control area (we have exclusive access to that area until we increment the commit counter). Then, that timestamp value will be read when delivering the sub-buffer, whichever event or switch happens to be the last to increment the commit counter to perform delivery. The timestamp value can be read without worrying about concurrent access, because at that point sub-buffer delivery has exclusive access to the sub-buffer. This ensures the timestamp_end value is always larger or equal to the timestamp of the last event, always below or equal the timestamp_begin of the following packet, and always below or equal the timestamp of the first event in the following packet. This changes the layout of the ring buffer shared memory area, so we need to bump the LTTNG_UST_ABI version from 7.2 to 8.0, thus requiring locked-step upgrade between liblttng-ust in applications, session daemon, and consumer daemon. This fix therefore cannot be backported to existing stable releases. Fixes: #1183 Signed-off-by: Mathieu Desnoyers --- include/lttng/ust-abi.h | 4 +- libringbuffer/frontend_types.h | 14 +++++++ libringbuffer/ring_buffer_frontend.c | 62 ++++++++++++++++++++++++++-- 3 files changed, 75 insertions(+), 5 deletions(-) diff --git a/include/lttng/ust-abi.h b/include/lttng/ust-abi.h index 01e9daf4..c1e13085 100644 --- a/include/lttng/ust-abi.h +++ b/include/lttng/ust-abi.h @@ -46,8 +46,8 @@ #define LTTNG_UST_COMM_MAGIC 0xC57C57C5 /* Version for ABI between liblttng-ust, sessiond, consumerd */ -#define LTTNG_UST_ABI_MAJOR_VERSION 7 -#define LTTNG_UST_ABI_MINOR_VERSION 2 +#define LTTNG_UST_ABI_MAJOR_VERSION 8 +#define LTTNG_UST_ABI_MINOR_VERSION 0 enum lttng_ust_instrumentation { LTTNG_UST_TRACEPOINT = 0, diff --git a/libringbuffer/frontend_types.h b/libringbuffer/frontend_types.h index 629abcbd..d0890408 100644 --- a/libringbuffer/frontend_types.h +++ b/libringbuffer/frontend_types.h @@ -202,6 +202,20 @@ struct lttng_ust_lib_ring_buffer { DECLARE_SHMP(struct commit_counters_cold, commit_cold); /* Commit count per sub-buffer */ + DECLARE_SHMP(uint64_t, ts_end); /* + * timestamp_end per sub-buffer. + * Time is sampled by the + * switch_*_end() callbacks + * which are the last space + * reservation performed in the + * sub-buffer before it can be + * fully committed and + * delivered. This time value is + * then read by the deliver + * callback, performed by the + * last commit before the buffer + * becomes readable. + */ long active_readers; /* * Active readers count * standard atomic access (shared) diff --git a/libringbuffer/ring_buffer_frontend.c b/libringbuffer/ring_buffer_frontend.c index 9721df16..ce759ff1 100644 --- a/libringbuffer/ring_buffer_frontend.c +++ b/libringbuffer/ring_buffer_frontend.c @@ -194,6 +194,7 @@ void lib_ring_buffer_reset(struct lttng_ust_lib_ring_buffer *buf, for (i = 0; i < chan->backend.num_subbuf; i++) { struct commit_counters_hot *cc_hot; struct commit_counters_cold *cc_cold; + uint64_t *ts_end; cc_hot = shmp_index(handle, buf->commit_hot, i); if (!cc_hot) @@ -201,9 +202,13 @@ void lib_ring_buffer_reset(struct lttng_ust_lib_ring_buffer *buf, cc_cold = shmp_index(handle, buf->commit_cold, i); if (!cc_cold) return; + ts_end = shmp_index(handle, buf->ts_end, i); + if (!ts_end) + return; v_set(config, &cc_hot->cc, 0); v_set(config, &cc_hot->seq, 0); v_set(config, &cc_cold->cc_sb, 0); + *ts_end = 0; } uatomic_set(&buf->consumed, 0); uatomic_set(&buf->record_disabled, 0); @@ -368,6 +373,16 @@ int lib_ring_buffer_create(struct lttng_ust_lib_ring_buffer *buf, goto free_commit; } + align_shm(shmobj, __alignof__(uint64_t)); + set_shmp(buf->ts_end, + zalloc_shm(shmobj, + sizeof(uint64_t) * chan->backend.num_subbuf)); + if (!shmp(handle, buf->ts_end)) { + ret = -ENOMEM; + goto free_commit_cold; + } + + ret = lib_ring_buffer_backend_create(&buf->backend, &chan->backend, cpu, handle, shmobj); if (ret) { @@ -414,6 +429,8 @@ int lib_ring_buffer_create(struct lttng_ust_lib_ring_buffer *buf, /* Error handling */ free_init: + /* ts_end will be freed by shm teardown */ +free_commit_cold: /* commit_cold will be freed by shm teardown */ free_commit: /* commit_hot will be freed by shm teardown */ @@ -1795,15 +1812,29 @@ void lib_ring_buffer_switch_old_end(struct lttng_ust_lib_ring_buffer *buf, unsigned long oldidx = subbuf_index(offsets->old - 1, chan); unsigned long commit_count, padding_size, data_size; struct commit_counters_hot *cc_hot; + uint64_t *ts_end; data_size = subbuf_offset(offsets->old - 1, chan) + 1; padding_size = chan->backend.subbuf_size - data_size; subbuffer_set_data_size(config, &buf->backend, oldidx, data_size, handle); + ts_end = shmp_index(handle, buf->ts_end, oldidx); + if (!ts_end) + return; /* - * Order all writes to buffer before the commit count update that will - * determine that the subbuffer is full. + * This is the last space reservation in that sub-buffer before + * it gets delivered. This provides exclusive access to write to + * this sub-buffer's ts_end. There are also no concurrent + * readers of that ts_end because delivery of that sub-buffer is + * postponed until the commit counter is incremented for the + * current space reservation. + */ + *ts_end = tsc; + + /* + * Order all writes to buffer and store to ts_end before the commit + * count update that will determine that the subbuffer is full. */ cmm_smp_wmb(); cc_hot = shmp_index(handle, buf->commit_hot, oldidx); @@ -1874,11 +1905,24 @@ void lib_ring_buffer_switch_new_end(struct lttng_ust_lib_ring_buffer *buf, { const struct lttng_ust_lib_ring_buffer_config *config = &chan->backend.config; unsigned long endidx, data_size; + uint64_t *ts_end; endidx = subbuf_index(offsets->end - 1, chan); data_size = subbuf_offset(offsets->end - 1, chan) + 1; subbuffer_set_data_size(config, &buf->backend, endidx, data_size, handle); + ts_end = shmp_index(handle, buf->ts_end, endidx); + if (!ts_end) + return; + /* + * This is the last space reservation in that sub-buffer before + * it gets delivered. This provides exclusive access to write to + * this sub-buffer's ts_end. There are also no concurrent + * readers of that ts_end because delivery of that sub-buffer is + * postponed until the commit counter is incremented for the + * current space reservation. + */ + *ts_end = tsc; } /* @@ -2445,14 +2489,26 @@ void lib_ring_buffer_check_deliver_slow(const struct lttng_ust_lib_ring_buffer_c if (caa_likely(v_cmpxchg(config, &cc_cold->cc_sb, old_commit_count, old_commit_count + 1) == old_commit_count)) { + uint64_t *ts_end; + /* * Start of exclusive subbuffer access. We are * guaranteed to be the last writer in this subbuffer * and any other writer trying to access this subbuffer * in this state is required to drop records. + * + * We can read the ts_end for the current sub-buffer + * which has been saved by the very last space + * reservation for the current sub-buffer. + * + * Order increment of commit counter before reading ts_end. */ + cmm_smp_mb(); + ts_end = shmp_index(handle, buf->ts_end, idx); + if (!ts_end) + return; deliver_count_events(config, buf, idx, handle); - config->cb.buffer_end(buf, tsc, idx, + config->cb.buffer_end(buf, *ts_end, idx, lib_ring_buffer_get_data_size(config, buf, idx, -- 2.34.1 From 4b5f26af4d267f5e5a1eb9dbfd8ca4fd5f5896fb Mon Sep 17 00:00:00 2001 From: Michael Jeanson Date: Tue, 12 Feb 2019 10:38:25 -0500 Subject: [PATCH 15/16] Add userspace namespace contexts Add a context for each available kernel namespace which currently are : cgroup, ipc, mnt, net, pid, user and uts. The id chosen to identify the namespaces is the inode number of the file representing each one of them in the proc filesystem. This was introduced in kernel v3.8.0, if any of these context are enabled on a system running an older kernel, zero will be returned. Signed-off-by: Michael Jeanson --- doc/man/lttng-ust.3.txt | 34 ++++- include/lttng/ust-abi.h | 7 ++ include/lttng/ust-events.h | 14 +++ include/lttng/ust.h | 2 + liblttng-ust-fork/ustfork.c | 50 ++++++++ liblttng-ust/Makefile.am | 10 +- liblttng-ust/lttng-context-cgroup-ns.c | 164 +++++++++++++++++++++++++ liblttng-ust/lttng-context-ipc-ns.c | 164 +++++++++++++++++++++++++ liblttng-ust/lttng-context-mnt-ns.c | 139 +++++++++++++++++++++ liblttng-ust/lttng-context-net-ns.c | 164 +++++++++++++++++++++++++ liblttng-ust/lttng-context-pid-ns.c | 142 +++++++++++++++++++++ liblttng-ust/lttng-context-user-ns.c | 139 +++++++++++++++++++++ liblttng-ust/lttng-context-uts-ns.c | 164 +++++++++++++++++++++++++ liblttng-ust/lttng-context.c | 35 ++++++ liblttng-ust/lttng-events.c | 14 +++ liblttng-ust/lttng-tracer-core.h | 12 ++ liblttng-ust/lttng-ust-comm.c | 27 ++++ liblttng-ust/ns.h | 40 ++++++ 18 files changed, 1318 insertions(+), 3 deletions(-) create mode 100644 liblttng-ust/lttng-context-cgroup-ns.c create mode 100644 liblttng-ust/lttng-context-ipc-ns.c create mode 100644 liblttng-ust/lttng-context-mnt-ns.c create mode 100644 liblttng-ust/lttng-context-net-ns.c create mode 100644 liblttng-ust/lttng-context-pid-ns.c create mode 100644 liblttng-ust/lttng-context-user-ns.c create mode 100644 liblttng-ust/lttng-context-uts-ns.c create mode 100644 liblttng-ust/ns.h diff --git a/doc/man/lttng-ust.3.txt b/doc/man/lttng-ust.3.txt index 5c9c9f5d..ad87f403 100644 --- a/doc/man/lttng-ust.3.txt +++ b/doc/man/lttng-ust.3.txt @@ -790,11 +790,41 @@ Only available on IA-32 and x86-64 architectures. `vpid`:: Virtual process ID: process ID as seen from the point of view of - the process namespace. + the current man:pid_namespaces(7). `vtid`:: Virtual thread ID: thread ID as seen from the point of view of - the process namespace. + the current man:pid_namespaces(7). + +The following man:namespaces(7) context fields are supported by LTTng-UST: + +`cgroup_ns`:: + Cgroup root directory namespace: inode number of the current + man:cgroup_namespaces(7) in the proc filesystem. + +`ipc_ns`:: + System V IPC, POSIX message queues namespace: inode number of the + current IPC namespace in the proc filesystem. + +`mnt_ns`:: + Mount points namespace: inode number of the current Mount namespace + in the proc filesystem. + +`net_ns`:: + Network devices, stacks, ports namespace: inode number of the + current Network namespace in the proc filesystem. + +`pid_ns`:: + Process IDs namespace: inode number of the current + man:pid_namespaces(7) in the proc filesystem. + +`user_ns`:: + User and group IDs namespace: inode number of the current + man:user_namespaces(7) in the proc filesystem. + +`uts_ns`:: + Hostname and NIS domain name namespace: inode number of the + current UTS namespace in the proc filesystem. [[state-dump]] diff --git a/include/lttng/ust-abi.h b/include/lttng/ust-abi.h index c1e13085..d299b7de 100644 --- a/include/lttng/ust-abi.h +++ b/include/lttng/ust-abi.h @@ -145,6 +145,13 @@ enum lttng_ust_context_type { LTTNG_UST_CONTEXT_PERF_THREAD_COUNTER = 5, LTTNG_UST_CONTEXT_CPU_ID = 6, LTTNG_UST_CONTEXT_APP_CONTEXT = 7, + LTTNG_UST_CONTEXT_CGROUP_NS = 8, + LTTNG_UST_CONTEXT_IPC_NS = 9, + LTTNG_UST_CONTEXT_MNT_NS = 10, + LTTNG_UST_CONTEXT_NET_NS = 11, + LTTNG_UST_CONTEXT_PID_NS = 12, + LTTNG_UST_CONTEXT_USER_NS = 13, + LTTNG_UST_CONTEXT_UTS_NS = 14, }; struct lttng_ust_perf_counter_ctx { diff --git a/include/lttng/ust-events.h b/include/lttng/ust-events.h index fefb8585..c0ec3860 100644 --- a/include/lttng/ust-events.h +++ b/include/lttng/ust-events.h @@ -679,9 +679,23 @@ int lttng_add_procname_to_ctx(struct lttng_ctx **ctx); int lttng_add_ip_to_ctx(struct lttng_ctx **ctx); int lttng_add_cpu_id_to_ctx(struct lttng_ctx **ctx); int lttng_add_dyntest_to_ctx(struct lttng_ctx **ctx); +int lttng_add_cgroup_ns_to_ctx(struct lttng_ctx **ctx); +int lttng_add_ipc_ns_to_ctx(struct lttng_ctx **ctx); +int lttng_add_mnt_ns_to_ctx(struct lttng_ctx **ctx); +int lttng_add_net_ns_to_ctx(struct lttng_ctx **ctx); +int lttng_add_pid_ns_to_ctx(struct lttng_ctx **ctx); +int lttng_add_user_ns_to_ctx(struct lttng_ctx **ctx); +int lttng_add_uts_ns_to_ctx(struct lttng_ctx **ctx); void lttng_context_vtid_reset(void); void lttng_context_vpid_reset(void); void lttng_context_procname_reset(void); +void lttng_context_cgroup_ns_reset(void); +void lttng_context_ipc_ns_reset(void); +void lttng_context_mnt_ns_reset(void); +void lttng_context_net_ns_reset(void); +void lttng_context_pid_ns_reset(void); +void lttng_context_user_ns_reset(void); +void lttng_context_uts_ns_reset(void); #ifdef LTTNG_UST_HAVE_PERF_EVENT int lttng_add_perf_counter_to_ctx(uint32_t type, diff --git a/include/lttng/ust.h b/include/lttng/ust.h index 2779d7a7..0b2a8979 100644 --- a/include/lttng/ust.h +++ b/include/lttng/ust.h @@ -32,6 +32,8 @@ extern "C" { extern void ust_before_fork(sigset_t *save_sigset); extern void ust_after_fork_parent(sigset_t *restore_sigset); extern void ust_after_fork_child(sigset_t *restore_sigset); +extern void ust_after_setns(void); +extern void ust_after_unshare(void); #ifdef __cplusplus } diff --git a/liblttng-ust-fork/ustfork.c b/liblttng-ust-fork/ustfork.c index 71c4b86c..25f9d4cc 100644 --- a/liblttng-ust-fork/ustfork.c +++ b/liblttng-ust-fork/ustfork.c @@ -160,6 +160,56 @@ int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...) return retval; } +int setns(int fd, int nstype) +{ + static int (*plibc_func)(int fd, int nstype) = NULL; + int retval; + int saved_errno; + + if (plibc_func == NULL) { + plibc_func = dlsym(RTLD_NEXT, "setns"); + if (plibc_func == NULL) { + fprintf(stderr, "libustfork: unable to find \"setns\" symbol\n"); + errno = ENOSYS; + return -1; + } + } + + /* Do the real setns */ + retval = plibc_func(fd, nstype); + saved_errno = errno; + + ust_after_setns(); + + errno = saved_errno; + return retval; +} + +int unshare(int flags) +{ + static int (*plibc_func)(int flags) = NULL; + int retval; + int saved_errno; + + if (plibc_func == NULL) { + plibc_func = dlsym(RTLD_NEXT, "unshare"); + if (plibc_func == NULL) { + fprintf(stderr, "libustfork: unable to find \"unshare\" symbol\n"); + errno = ENOSYS; + return -1; + } + } + + /* Do the real setns */ + retval = plibc_func(flags); + saved_errno = errno; + + ust_after_unshare(); + + errno = saved_errno; + return retval; +} + #elif defined (__FreeBSD__) pid_t rfork(int flags) diff --git a/liblttng-ust/Makefile.am b/liblttng-ust/Makefile.am index 15655280..1f167218 100644 --- a/liblttng-ust/Makefile.am +++ b/liblttng-ust/Makefile.am @@ -33,6 +33,13 @@ liblttng_ust_runtime_la_SOURCES = \ lttng-context-procname.c \ lttng-context-ip.c \ lttng-context-cpu-id.c \ + lttng-context-cgroup-ns.c \ + lttng-context-ipc-ns.c \ + lttng-context-mnt-ns.c \ + lttng-context-net-ns.c \ + lttng-context-pid-ns.c \ + lttng-context-user-ns.c \ + lttng-context-uts-ns.c \ lttng-context.c \ lttng-events.c \ lttng-filter.c \ @@ -61,7 +68,8 @@ liblttng_ust_runtime_la_SOURCES = \ lttng-ust-tracelog-provider.h \ getenv.h \ string-utils.c \ - string-utils.h + string-utils.h \ + ns.h if HAVE_PERF_EVENT liblttng_ust_runtime_la_SOURCES += \ diff --git a/liblttng-ust/lttng-context-cgroup-ns.c b/liblttng-ust/lttng-context-cgroup-ns.c new file mode 100644 index 00000000..5a527498 --- /dev/null +++ b/liblttng-ust/lttng-context-cgroup-ns.c @@ -0,0 +1,164 @@ +/* + * lttng-context-cgroup-ns.c + * + * LTTng UST cgroup namespace context. + * + * Copyright (C) 2009-2012 Mathieu Desnoyers + * 2019 Michael Jeanson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _LGPL_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include "lttng-tracer-core.h" +#include "ns.h" + + +/* + * We cache the result to ensure we don't stat(2) the proc filesystem on + * each event. + */ +static DEFINE_URCU_TLS(ino_t, cached_cgroup_ns) = NS_INO_UNINITIALIZED; + +static +ino_t get_cgroup_ns(void) +{ + struct stat sb; + ino_t cgroup_ns; + + cgroup_ns = CMM_LOAD_SHARED(URCU_TLS(cached_cgroup_ns)); + + /* + * If the cache is populated, do nothing and return the + * cached inode number. + */ + if (caa_likely(cgroup_ns != NS_INO_UNINITIALIZED)) + return cgroup_ns; + + /* + * At this point we have to populate the cache, set the initial + * value to NS_INO_UNAVAILABLE (0), if we fail to get the inode + * number from the proc filesystem, this is the value we will + * cache. + */ + cgroup_ns = NS_INO_UNAVAILABLE; + + /* + * /proc/thread-self was introduced in kernel v3.17 + */ + if (stat("/proc/thread-self/ns/cgroup", &sb) == 0) { + cgroup_ns = sb.st_ino; + } else { + char proc_ns_path[LTTNG_PROC_NS_PATH_MAX]; + + if (snprintf(proc_ns_path, LTTNG_PROC_NS_PATH_MAX, + "/proc/self/task/%d/ns/cgroup", + gettid()) >= 0) { + + if (stat(proc_ns_path, &sb) == 0) { + cgroup_ns = sb.st_ino; + } + } + } + + /* + * And finally, store the inode number in the cache. + */ + CMM_STORE_SHARED(URCU_TLS(cached_cgroup_ns), cgroup_ns); + + return cgroup_ns; +} + +/* + * The cgroup namespace can change for 3 reasons + * * clone(2) called with CLONE_NEWCGROUP + * * setns(2) called with the fd of a different cgroup ns + * * unshare(2) called with CLONE_NEWCGROUP + */ +void lttng_context_cgroup_ns_reset(void) +{ + CMM_STORE_SHARED(URCU_TLS(cached_cgroup_ns), NS_INO_UNINITIALIZED); +} + +static +size_t cgroup_ns_get_size(struct lttng_ctx_field *field, size_t offset) +{ + size_t size = 0; + + size += lib_ring_buffer_align(offset, lttng_alignof(ino_t)); + size += sizeof(ino_t); + return size; +} + +static +void cgroup_ns_record(struct lttng_ctx_field *field, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + struct lttng_channel *chan) +{ + ino_t cgroup_ns; + + cgroup_ns = get_cgroup_ns(); + lib_ring_buffer_align_ctx(ctx, lttng_alignof(cgroup_ns)); + chan->ops->event_write(ctx, &cgroup_ns, sizeof(cgroup_ns)); +} + +static +void cgroup_ns_get_value(struct lttng_ctx_field *field, + struct lttng_ctx_value *value) +{ + value->u.s64 = get_cgroup_ns(); +} + +int lttng_add_cgroup_ns_to_ctx(struct lttng_ctx **ctx) +{ + struct lttng_ctx_field *field; + + field = lttng_append_context(ctx); + if (!field) + return -ENOMEM; + if (lttng_find_context(*ctx, "cgroup_ns")) { + lttng_remove_context_field(ctx, field); + return -EEXIST; + } + field->event_field.name = "cgroup_ns"; + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(ino_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = lttng_alignof(ino_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(ino_t); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; + field->get_size = cgroup_ns_get_size; + field->record = cgroup_ns_record; + field->get_value = cgroup_ns_get_value; + lttng_context_update(*ctx); + return 0; +} + +/* + * * Force a read (imply TLS fixup for dlopen) of TLS variables. + * */ +void lttng_fixup_cgroup_ns_tls(void) +{ + asm volatile ("" : : "m" (URCU_TLS(cached_cgroup_ns))); +} diff --git a/liblttng-ust/lttng-context-ipc-ns.c b/liblttng-ust/lttng-context-ipc-ns.c new file mode 100644 index 00000000..5227bd10 --- /dev/null +++ b/liblttng-ust/lttng-context-ipc-ns.c @@ -0,0 +1,164 @@ +/* + * lttng-context-ipc-ns.c + * + * LTTng UST ipc namespace context. + * + * Copyright (C) 2009-2012 Mathieu Desnoyers + * 2019 Michael Jeanson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _LGPL_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include "lttng-tracer-core.h" +#include "ns.h" + + +/* + * We cache the result to ensure we don't stat(2) the proc filesystem on + * each event. + */ +static DEFINE_URCU_TLS(ino_t, cached_ipc_ns) = NS_INO_UNINITIALIZED; + +static +ino_t get_ipc_ns(void) +{ + struct stat sb; + ino_t ipc_ns; + + ipc_ns = CMM_LOAD_SHARED(URCU_TLS(cached_ipc_ns)); + + /* + * If the cache is populated, do nothing and return the + * cached inode number. + */ + if (caa_likely(ipc_ns != NS_INO_UNINITIALIZED)) + return ipc_ns; + + /* + * At this point we have to populate the cache, set the initial + * value to NS_INO_UNAVAILABLE (0), if we fail to get the inode + * number from the proc filesystem, this is the value we will + * cache. + */ + ipc_ns = NS_INO_UNAVAILABLE; + + /* + * /proc/thread-self was introduced in kernel v3.17 + */ + if (stat("/proc/thread-self/ns/ipc", &sb) == 0) { + ipc_ns = sb.st_ino; + } else { + char proc_ns_path[LTTNG_PROC_NS_PATH_MAX]; + + if (snprintf(proc_ns_path, LTTNG_PROC_NS_PATH_MAX, + "/proc/self/task/%d/ns/ipc", + gettid()) >= 0) { + + if (stat(proc_ns_path, &sb) == 0) { + ipc_ns = sb.st_ino; + } + } + } + + /* + * And finally, store the inode number in the cache. + */ + CMM_STORE_SHARED(URCU_TLS(cached_ipc_ns), ipc_ns); + + return ipc_ns; +} + +/* + * The ipc namespace can change for 3 reasons + * * clone(2) called with CLONE_NEWIPC + * * setns(2) called with the fd of a different ipc ns + * * unshare(2) called with CLONE_NEWIPC + */ +void lttng_context_ipc_ns_reset(void) +{ + CMM_STORE_SHARED(URCU_TLS(cached_ipc_ns), NS_INO_UNINITIALIZED); +} + +static +size_t ipc_ns_get_size(struct lttng_ctx_field *field, size_t offset) +{ + size_t size = 0; + + size += lib_ring_buffer_align(offset, lttng_alignof(ino_t)); + size += sizeof(ino_t); + return size; +} + +static +void ipc_ns_record(struct lttng_ctx_field *field, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + struct lttng_channel *chan) +{ + ino_t ipc_ns; + + ipc_ns = get_ipc_ns(); + lib_ring_buffer_align_ctx(ctx, lttng_alignof(ipc_ns)); + chan->ops->event_write(ctx, &ipc_ns, sizeof(ipc_ns)); +} + +static +void ipc_ns_get_value(struct lttng_ctx_field *field, + struct lttng_ctx_value *value) +{ + value->u.s64 = get_ipc_ns(); +} + +int lttng_add_ipc_ns_to_ctx(struct lttng_ctx **ctx) +{ + struct lttng_ctx_field *field; + + field = lttng_append_context(ctx); + if (!field) + return -ENOMEM; + if (lttng_find_context(*ctx, "ipc_ns")) { + lttng_remove_context_field(ctx, field); + return -EEXIST; + } + field->event_field.name = "ipc_ns"; + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(ino_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = lttng_alignof(ino_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(ino_t); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; + field->get_size = ipc_ns_get_size; + field->record = ipc_ns_record; + field->get_value = ipc_ns_get_value; + lttng_context_update(*ctx); + return 0; +} + +/* + * * Force a read (imply TLS fixup for dlopen) of TLS variables. + * */ +void lttng_fixup_ipc_ns_tls(void) +{ + asm volatile ("" : : "m" (URCU_TLS(cached_ipc_ns))); +} diff --git a/liblttng-ust/lttng-context-mnt-ns.c b/liblttng-ust/lttng-context-mnt-ns.c new file mode 100644 index 00000000..d54c42aa --- /dev/null +++ b/liblttng-ust/lttng-context-mnt-ns.c @@ -0,0 +1,139 @@ +/* + * lttng-context-mnt-ns.c + * + * LTTng UST mnt namespace context. + * + * Copyright (C) 2009-2012 Mathieu Desnoyers + * 2019 Michael Jeanson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _LGPL_SOURCE +#include +#include +#include +#include +#include +#include + +#include "ns.h" + +/* + * We cache the result to ensure we don't stat(2) the proc filesystem on + * each event. The mount namespace is global to the process. + */ +static ino_t cached_mnt_ns = NS_INO_UNINITIALIZED; + +static +ino_t get_mnt_ns(void) +{ + struct stat sb; + ino_t mnt_ns; + + mnt_ns = CMM_LOAD_SHARED(cached_mnt_ns); + + /* + * If the cache is populated, do nothing and return the + * cached inode number. + */ + if (caa_likely(mnt_ns != NS_INO_UNINITIALIZED)) + return mnt_ns; + + /* + * At this point we have to populate the cache, set the initial + * value to NS_INO_UNAVAILABLE (0), if we fail to get the inode + * number from the proc filesystem, this is the value we will + * cache. + */ + mnt_ns = NS_INO_UNAVAILABLE; + + if (stat("/proc/self/ns/mnt", &sb) == 0) { + mnt_ns = sb.st_ino; + } + + /* + * And finally, store the inode number in the cache. + */ + CMM_STORE_SHARED(cached_mnt_ns, mnt_ns); + + return mnt_ns; +} + +/* + * The mnt namespace can change for 3 reasons + * * clone(2) called with CLONE_NEWNS + * * setns(2) called with the fd of a different mnt ns + * * unshare(2) called with CLONE_NEWNS + */ +void lttng_context_mnt_ns_reset(void) +{ + CMM_STORE_SHARED(cached_mnt_ns, NS_INO_UNINITIALIZED); +} + +static +size_t mnt_ns_get_size(struct lttng_ctx_field *field, size_t offset) +{ + size_t size = 0; + + size += lib_ring_buffer_align(offset, lttng_alignof(ino_t)); + size += sizeof(ino_t); + return size; +} + +static +void mnt_ns_record(struct lttng_ctx_field *field, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + struct lttng_channel *chan) +{ + ino_t mnt_ns; + + mnt_ns = get_mnt_ns(); + lib_ring_buffer_align_ctx(ctx, lttng_alignof(mnt_ns)); + chan->ops->event_write(ctx, &mnt_ns, sizeof(mnt_ns)); +} + +static +void mnt_ns_get_value(struct lttng_ctx_field *field, + struct lttng_ctx_value *value) +{ + value->u.s64 = get_mnt_ns(); +} + +int lttng_add_mnt_ns_to_ctx(struct lttng_ctx **ctx) +{ + struct lttng_ctx_field *field; + + field = lttng_append_context(ctx); + if (!field) + return -ENOMEM; + if (lttng_find_context(*ctx, "mnt_ns")) { + lttng_remove_context_field(ctx, field); + return -EEXIST; + } + field->event_field.name = "mnt_ns"; + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(ino_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = lttng_alignof(ino_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(ino_t); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; + field->get_size = mnt_ns_get_size; + field->record = mnt_ns_record; + field->get_value = mnt_ns_get_value; + lttng_context_update(*ctx); + return 0; +} diff --git a/liblttng-ust/lttng-context-net-ns.c b/liblttng-ust/lttng-context-net-ns.c new file mode 100644 index 00000000..3a38668f --- /dev/null +++ b/liblttng-ust/lttng-context-net-ns.c @@ -0,0 +1,164 @@ +/* + * lttng-context-net-ns.c + * + * LTTng UST net namespace context. + * + * Copyright (C) 2009-2012 Mathieu Desnoyers + * 2019 Michael Jeanson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _LGPL_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include "lttng-tracer-core.h" +#include "ns.h" + + +/* + * We cache the result to ensure we don't stat(2) the proc filesystem on + * each event. + */ +static DEFINE_URCU_TLS(ino_t, cached_net_ns) = NS_INO_UNINITIALIZED; + +static +ino_t get_net_ns(void) +{ + struct stat sb; + ino_t net_ns; + + net_ns = CMM_LOAD_SHARED(URCU_TLS(cached_net_ns)); + + /* + * If the cache is populated, do nothing and return the + * cached inode number. + */ + if (caa_likely(net_ns != NS_INO_UNINITIALIZED)) + return net_ns; + + /* + * At this point we have to populate the cache, set the initial + * value to NS_INO_UNAVAILABLE (0), if we fail to get the inode + * number from the proc filesystem, this is the value we will + * cache. + */ + net_ns = NS_INO_UNAVAILABLE; + + /* + * /proc/thread-self was introduced in kernel v3.17 + */ + if (stat("/proc/thread-self/ns/net", &sb) == 0) { + net_ns = sb.st_ino; + } else { + char proc_ns_path[LTTNG_PROC_NS_PATH_MAX]; + + if (snprintf(proc_ns_path, LTTNG_PROC_NS_PATH_MAX, + "/proc/self/task/%d/ns/net", + gettid()) >= 0) { + + if (stat(proc_ns_path, &sb) == 0) { + net_ns = sb.st_ino; + } + } + } + + /* + * And finally, store the inode number in the cache. + */ + CMM_STORE_SHARED(URCU_TLS(cached_net_ns), net_ns); + + return net_ns; +} + +/* + * The net namespace can change for 3 reasons + * * clone(2) called with CLONE_NEWNET + * * setns(2) called with the fd of a different net ns + * * unshare(2) called with CLONE_NEWNET + */ +void lttng_context_net_ns_reset(void) +{ + CMM_STORE_SHARED(URCU_TLS(cached_net_ns), NS_INO_UNINITIALIZED); +} + +static +size_t net_ns_get_size(struct lttng_ctx_field *field, size_t offset) +{ + size_t size = 0; + + size += lib_ring_buffer_align(offset, lttng_alignof(ino_t)); + size += sizeof(ino_t); + return size; +} + +static +void net_ns_record(struct lttng_ctx_field *field, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + struct lttng_channel *chan) +{ + ino_t net_ns; + + net_ns = get_net_ns(); + lib_ring_buffer_align_ctx(ctx, lttng_alignof(net_ns)); + chan->ops->event_write(ctx, &net_ns, sizeof(net_ns)); +} + +static +void net_ns_get_value(struct lttng_ctx_field *field, + struct lttng_ctx_value *value) +{ + value->u.s64 = get_net_ns(); +} + +int lttng_add_net_ns_to_ctx(struct lttng_ctx **ctx) +{ + struct lttng_ctx_field *field; + + field = lttng_append_context(ctx); + if (!field) + return -ENOMEM; + if (lttng_find_context(*ctx, "net_ns")) { + lttng_remove_context_field(ctx, field); + return -EEXIST; + } + field->event_field.name = "net_ns"; + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(ino_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = lttng_alignof(ino_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(ino_t); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; + field->get_size = net_ns_get_size; + field->record = net_ns_record; + field->get_value = net_ns_get_value; + lttng_context_update(*ctx); + return 0; +} + +/* + * * Force a read (imply TLS fixup for dlopen) of TLS variables. + * */ +void lttng_fixup_net_ns_tls(void) +{ + asm volatile ("" : : "m" (URCU_TLS(cached_net_ns))); +} diff --git a/liblttng-ust/lttng-context-pid-ns.c b/liblttng-ust/lttng-context-pid-ns.c new file mode 100644 index 00000000..1581fb3d --- /dev/null +++ b/liblttng-ust/lttng-context-pid-ns.c @@ -0,0 +1,142 @@ +/* + * lttng-context-pid-ns.c + * + * LTTng UST pid namespace context. + * + * Copyright (C) 2009-2012 Mathieu Desnoyers + * 2019 Michael Jeanson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _LGPL_SOURCE +#include +#include +#include +#include +#include +#include + +#include "ns.h" + +/* + * We cache the result to ensure we don't stat(2) the proc filesystem on + * each event. The PID namespace is global to the process. + */ +static ino_t cached_pid_ns = NS_INO_UNINITIALIZED; + +static +ino_t get_pid_ns(void) +{ + struct stat sb; + ino_t pid_ns; + + pid_ns = CMM_LOAD_SHARED(cached_pid_ns); + + /* + * If the cache is populated, do nothing and return the + * cached inode number. + */ + if (caa_likely(pid_ns != NS_INO_UNINITIALIZED)) + return pid_ns; + + /* + * At this point we have to populate the cache, set the initial + * value to NS_INO_UNAVAILABLE (0), if we fail to get the inode + * number from the proc filesystem, this is the value we will + * cache. + */ + pid_ns = NS_INO_UNAVAILABLE; + + if (stat("/proc/self/ns/pid", &sb) == 0) { + pid_ns = sb.st_ino; + } + + /* + * And finally, store the inode number in the cache. + */ + CMM_STORE_SHARED(cached_pid_ns, pid_ns); + + return pid_ns; +} + +/* + * A process's PID namespace membership is determined when the process is + * created and cannot be changed thereafter. + * + * The pid namespace can change only on clone(2) / fork(2) : + * - clone(2) with the CLONE_NEWPID flag + * - clone(2) / fork(2) after a call to unshare(2) with the CLONE_NEWPID flag + * - clone(2) / fork(2) after a call to setns(2) with a PID namespace fd + */ +void lttng_context_pid_ns_reset(void) +{ + CMM_STORE_SHARED(cached_pid_ns, NS_INO_UNINITIALIZED); +} + +static +size_t pid_ns_get_size(struct lttng_ctx_field *field, size_t offset) +{ + size_t size = 0; + + size += lib_ring_buffer_align(offset, lttng_alignof(ino_t)); + size += sizeof(ino_t); + return size; +} + +static +void pid_ns_record(struct lttng_ctx_field *field, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + struct lttng_channel *chan) +{ + ino_t pid_ns; + + pid_ns = get_pid_ns(); + lib_ring_buffer_align_ctx(ctx, lttng_alignof(pid_ns)); + chan->ops->event_write(ctx, &pid_ns, sizeof(pid_ns)); +} + +static +void pid_ns_get_value(struct lttng_ctx_field *field, + struct lttng_ctx_value *value) +{ + value->u.s64 = get_pid_ns(); +} + +int lttng_add_pid_ns_to_ctx(struct lttng_ctx **ctx) +{ + struct lttng_ctx_field *field; + + field = lttng_append_context(ctx); + if (!field) + return -ENOMEM; + if (lttng_find_context(*ctx, "pid_ns")) { + lttng_remove_context_field(ctx, field); + return -EEXIST; + } + field->event_field.name = "pid_ns"; + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(ino_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = lttng_alignof(ino_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(ino_t); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; + field->get_size = pid_ns_get_size; + field->record = pid_ns_record; + field->get_value = pid_ns_get_value; + lttng_context_update(*ctx); + return 0; +} diff --git a/liblttng-ust/lttng-context-user-ns.c b/liblttng-ust/lttng-context-user-ns.c new file mode 100644 index 00000000..04b940f6 --- /dev/null +++ b/liblttng-ust/lttng-context-user-ns.c @@ -0,0 +1,139 @@ +/* + * lttng-context-user-ns.c + * + * LTTng UST user namespace context. + * + * Copyright (C) 2009-2012 Mathieu Desnoyers + * 2019 Michael Jeanson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _LGPL_SOURCE +#include +#include +#include +#include +#include +#include + +#include "ns.h" + +/* + * We cache the result to ensure we don't stat(2) the proc filesystem on + * each event. The user namespace is global to the process. + */ +static ino_t cached_user_ns = NS_INO_UNINITIALIZED; + +static +ino_t get_user_ns(void) +{ + struct stat sb; + ino_t user_ns; + + user_ns = CMM_LOAD_SHARED(cached_user_ns); + + /* + * If the cache is populated, do nothing and return the + * cached inode number. + */ + if (caa_likely(user_ns != NS_INO_UNINITIALIZED)) + return user_ns; + + /* + * At this point we have to populate the cache, set the initial + * value to NS_INO_UNAVAILABLE (0), if we fail to get the inode + * number from the proc filesystem, this is the value we will + * cache. + */ + user_ns = NS_INO_UNAVAILABLE; + + if (stat("/proc/self/ns/user", &sb) == 0) { + user_ns = sb.st_ino; + } + + /* + * And finally, store the inode number in the cache. + */ + CMM_STORE_SHARED(cached_user_ns, user_ns); + + return user_ns; +} + +/* + * The user namespace can change for 3 reasons + * * clone(2) called with CLONE_NEWUSER + * * setns(2) called with the fd of a different user ns + * * unshare(2) called with CLONE_NEWUSER + */ +void lttng_context_user_ns_reset(void) +{ + CMM_STORE_SHARED(cached_user_ns, NS_INO_UNINITIALIZED); +} + +static +size_t user_ns_get_size(struct lttng_ctx_field *field, size_t offset) +{ + size_t size = 0; + + size += lib_ring_buffer_align(offset, lttng_alignof(ino_t)); + size += sizeof(ino_t); + return size; +} + +static +void user_ns_record(struct lttng_ctx_field *field, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + struct lttng_channel *chan) +{ + ino_t user_ns; + + user_ns = get_user_ns(); + lib_ring_buffer_align_ctx(ctx, lttng_alignof(user_ns)); + chan->ops->event_write(ctx, &user_ns, sizeof(user_ns)); +} + +static +void user_ns_get_value(struct lttng_ctx_field *field, + struct lttng_ctx_value *value) +{ + value->u.s64 = get_user_ns(); +} + +int lttng_add_user_ns_to_ctx(struct lttng_ctx **ctx) +{ + struct lttng_ctx_field *field; + + field = lttng_append_context(ctx); + if (!field) + return -ENOMEM; + if (lttng_find_context(*ctx, "user_ns")) { + lttng_remove_context_field(ctx, field); + return -EEXIST; + } + field->event_field.name = "user_ns"; + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(ino_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = lttng_alignof(ino_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(ino_t); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; + field->get_size = user_ns_get_size; + field->record = user_ns_record; + field->get_value = user_ns_get_value; + lttng_context_update(*ctx); + return 0; +} diff --git a/liblttng-ust/lttng-context-uts-ns.c b/liblttng-ust/lttng-context-uts-ns.c new file mode 100644 index 00000000..976bc2a1 --- /dev/null +++ b/liblttng-ust/lttng-context-uts-ns.c @@ -0,0 +1,164 @@ +/* + * lttng-context-uts-ns.c + * + * LTTng UST uts namespace context. + * + * Copyright (C) 2009-2012 Mathieu Desnoyers + * 2019 Michael Jeanson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _LGPL_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include "lttng-tracer-core.h" +#include "ns.h" + + +/* + * We cache the result to ensure we don't stat(2) the proc filesystem on + * each event. + */ +static DEFINE_URCU_TLS(ino_t, cached_uts_ns) = NS_INO_UNINITIALIZED; + +static +ino_t get_uts_ns(void) +{ + struct stat sb; + ino_t uts_ns; + + uts_ns = CMM_LOAD_SHARED(URCU_TLS(cached_uts_ns)); + + /* + * If the cache is populated, do nothing and return the + * cached inode number. + */ + if (caa_likely(uts_ns != NS_INO_UNINITIALIZED)) + return uts_ns; + + /* + * At this point we have to populate the cache, set the initial + * value to NS_INO_UNAVAILABLE (0), if we fail to get the inode + * number from the proc filesystem, this is the value we will + * cache. + */ + uts_ns = NS_INO_UNAVAILABLE; + + /* + * /proc/thread-self was introduced in kernel v3.17 + */ + if (stat("/proc/thread-self/ns/uts", &sb) == 0) { + uts_ns = sb.st_ino; + } else { + char proc_ns_path[LTTNG_PROC_NS_PATH_MAX]; + + if (snprintf(proc_ns_path, LTTNG_PROC_NS_PATH_MAX, + "/proc/self/task/%d/ns/uts", + gettid()) >= 0) { + + if (stat(proc_ns_path, &sb) == 0) { + uts_ns = sb.st_ino; + } + } + } + + /* + * And finally, store the inode number in the cache. + */ + CMM_STORE_SHARED(URCU_TLS(cached_uts_ns), uts_ns); + + return uts_ns; +} + +/* + * The uts namespace can change for 3 reasons + * * clone(2) called with CLONE_NEWUTS + * * setns(2) called with the fd of a different uts ns + * * unshare(2) called with CLONE_NEWUTS + */ +void lttng_context_uts_ns_reset(void) +{ + CMM_STORE_SHARED(URCU_TLS(cached_uts_ns), NS_INO_UNINITIALIZED); +} + +static +size_t uts_ns_get_size(struct lttng_ctx_field *field, size_t offset) +{ + size_t size = 0; + + size += lib_ring_buffer_align(offset, lttng_alignof(ino_t)); + size += sizeof(ino_t); + return size; +} + +static +void uts_ns_record(struct lttng_ctx_field *field, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + struct lttng_channel *chan) +{ + ino_t uts_ns; + + uts_ns = get_uts_ns(); + lib_ring_buffer_align_ctx(ctx, lttng_alignof(uts_ns)); + chan->ops->event_write(ctx, &uts_ns, sizeof(uts_ns)); +} + +static +void uts_ns_get_value(struct lttng_ctx_field *field, + struct lttng_ctx_value *value) +{ + value->u.s64 = get_uts_ns(); +} + +int lttng_add_uts_ns_to_ctx(struct lttng_ctx **ctx) +{ + struct lttng_ctx_field *field; + + field = lttng_append_context(ctx); + if (!field) + return -ENOMEM; + if (lttng_find_context(*ctx, "uts_ns")) { + lttng_remove_context_field(ctx, field); + return -EEXIST; + } + field->event_field.name = "uts_ns"; + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(ino_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = lttng_alignof(ino_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(ino_t); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; + field->get_size = uts_ns_get_size; + field->record = uts_ns_record; + field->get_value = uts_ns_get_value; + lttng_context_update(*ctx); + return 0; +} + +/* + * * Force a read (imply TLS fixup for dlopen) of TLS variables. + * */ +void lttng_fixup_uts_ns_tls(void) +{ + asm volatile ("" : : "m" (URCU_TLS(cached_uts_ns))); +} diff --git a/liblttng-ust/lttng-context.c b/liblttng-ust/lttng-context.c index eeaaae43..ad6c38f0 100644 --- a/liblttng-ust/lttng-context.c +++ b/liblttng-ust/lttng-context.c @@ -372,6 +372,41 @@ int lttng_session_context_init(struct lttng_ctx **ctx) WARN("Cannot add context lttng_add_cpu_id_to_ctx"); goto error; } + ret = lttng_add_cgroup_ns_to_ctx(ctx); + if (ret) { + WARN("Cannot add context lttng_add_cgroup_ns_to_ctx"); + goto error; + } + ret = lttng_add_ipc_ns_to_ctx(ctx); + if (ret) { + WARN("Cannot add context lttng_add_ipc_ns_to_ctx"); + goto error; + } + ret = lttng_add_mnt_ns_to_ctx(ctx); + if (ret) { + WARN("Cannot add context lttng_add_mnt_ns_to_ctx"); + goto error; + } + ret = lttng_add_net_ns_to_ctx(ctx); + if (ret) { + WARN("Cannot add context lttng_add_net_ns_to_ctx"); + goto error; + } + ret = lttng_add_pid_ns_to_ctx(ctx); + if (ret) { + WARN("Cannot add context lttng_add_pid_ns_to_ctx"); + goto error; + } + ret = lttng_add_user_ns_to_ctx(ctx); + if (ret) { + WARN("Cannot add context lttng_add_user_ns_to_ctx"); + goto error; + } + ret = lttng_add_uts_ns_to_ctx(ctx); + if (ret) { + WARN("Cannot add context lttng_add_uts_ns_to_ctx"); + goto error; + } lttng_context_update(*ctx); return 0; diff --git a/liblttng-ust/lttng-events.c b/liblttng-ust/lttng-events.c index 7aa288c7..855f8d87 100644 --- a/liblttng-ust/lttng-events.c +++ b/liblttng-ust/lttng-events.c @@ -1112,6 +1112,20 @@ int lttng_attach_context(struct lttng_ust_context *context_param, case LTTNG_UST_CONTEXT_APP_CONTEXT: return lttng_ust_add_app_context_to_ctx_rcu(uargs->app_context.ctxname, ctx); + case LTTNG_UST_CONTEXT_CGROUP_NS: + return lttng_add_cgroup_ns_to_ctx(ctx); + case LTTNG_UST_CONTEXT_IPC_NS: + return lttng_add_ipc_ns_to_ctx(ctx); + case LTTNG_UST_CONTEXT_MNT_NS: + return lttng_add_mnt_ns_to_ctx(ctx); + case LTTNG_UST_CONTEXT_NET_NS: + return lttng_add_net_ns_to_ctx(ctx); + case LTTNG_UST_CONTEXT_PID_NS: + return lttng_add_pid_ns_to_ctx(ctx); + case LTTNG_UST_CONTEXT_USER_NS: + return lttng_add_user_ns_to_ctx(ctx); + case LTTNG_UST_CONTEXT_UTS_NS: + return lttng_add_uts_ns_to_ctx(ctx); default: return -EINVAL; } diff --git a/liblttng-ust/lttng-tracer-core.h b/liblttng-ust/lttng-tracer-core.h index ba232f32..7afa888d 100644 --- a/liblttng-ust/lttng-tracer-core.h +++ b/liblttng-ust/lttng-tracer-core.h @@ -30,6 +30,14 @@ #include #include +/* + * The longuest possible namespace proc path is with the cgroup ns + * and the maximum theoretical linux pid of 536870912 : + * + * /proc/self/task/536870912/ns/cgroup + */ +#define LTTNG_PROC_NS_PATH_MAX 40 + struct lttng_session; struct lttng_channel; struct lttng_event; @@ -44,6 +52,10 @@ void ust_unlock(void); void lttng_fixup_event_tls(void); void lttng_fixup_vtid_tls(void); void lttng_fixup_procname_tls(void); +void lttng_fixup_cgroup_ns_tls(void); +void lttng_fixup_ipc_ns_tls(void); +void lttng_fixup_net_ns_tls(void); +void lttng_fixup_uts_ns_tls(void); const char *lttng_ust_obj_get_name(int id); diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index 61dbb41b..09a25bd6 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -413,6 +413,10 @@ void lttng_ust_fixup_tls(void) lttng_fixup_procname_tls(); lttng_fixup_ust_mutex_nest_tls(); lttng_ust_fixup_fd_tracker_tls(); + lttng_fixup_cgroup_ns_tls(); + lttng_fixup_ipc_ns_tls(); + lttng_fixup_net_ns_tls(); + lttng_fixup_uts_ns_tls(); } int lttng_get_notify_socket(void *owner) @@ -1980,6 +1984,18 @@ void __attribute__((destructor)) lttng_ust_exit(void) lttng_ust_cleanup(1); } +static +void ust_context_ns_reset(void) +{ + lttng_context_pid_ns_reset(); + lttng_context_cgroup_ns_reset(); + lttng_context_ipc_ns_reset(); + lttng_context_mnt_ns_reset(); + lttng_context_net_ns_reset(); + lttng_context_user_ns_reset(); + lttng_context_uts_ns_reset(); +} + /* * We exclude the worker threads across fork and clone (except * CLONE_VM), because these system calls only keep the forking thread @@ -2058,6 +2074,7 @@ void ust_after_fork_child(sigset_t *restore_sigset) lttng_context_vpid_reset(); lttng_context_vtid_reset(); lttng_context_procname_reset(); + ust_context_ns_reset(); DBG("process %d", getpid()); /* Release urcu mutexes */ urcu_bp_after_fork_child(); @@ -2067,6 +2084,16 @@ void ust_after_fork_child(sigset_t *restore_sigset) lttng_ust_init(); } +void ust_after_setns(void) +{ + ust_context_ns_reset(); +} + +void ust_after_unshare(void) +{ + ust_context_ns_reset(); +} + void lttng_ust_sockinfo_session_enabled(void *owner) { struct sock_info *sock_info = owner; diff --git a/liblttng-ust/ns.h b/liblttng-ust/ns.h new file mode 100644 index 00000000..4793f3e0 --- /dev/null +++ b/liblttng-ust/ns.h @@ -0,0 +1,40 @@ +#ifndef _LTTNG_NS_H +#define _LTTNG_NS_H + +/* + * Copyright (c) 2019 - Michael Jeanson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +/* + * The lowest valid inode number that can be allocated in the proc filesystem + * is 0xF0000000. Any number below can be used internally as an error code. + * + * Zero is used in the kernel as an error code, it's the value we will return + * when we fail to read the proper inode number. + * + * One is used internally to identify an uninitialized cache entry, it should + * never be returned. + */ + +enum ns_ino_state { + NS_INO_UNAVAILABLE = 0x0, + NS_INO_UNINITIALIZED = 0x1, + NS_INO_MIN = 0xF0000000, +}; + +#endif /* _LTTNG_NS_H */ -- 2.34.1 From e4215fb7fae0ffd2ea4f69b2013ecebbf401fc0c Mon Sep 17 00:00:00 2001 From: Michael Jeanson Date: Tue, 12 Feb 2019 10:40:48 -0500 Subject: [PATCH 16/16] Add userspace vuid/vgid contexts Add a context for each available namespaced user and group IDs * vuid : real user ID * veuid : effective user ID * vsuid : saved set-user ID These are the IDs as seen in the current user namespace, see user_namespaces(7) and credentials(7) for details on each type. Signed-off-by: Michael Jeanson --- doc/man/lttng-ust.3.txt | 26 ++++ include/lttng/ust-abi.h | 6 + include/lttng/ust-events.h | 12 ++ include/lttng/ust.h | 8 ++ liblttng-ust-fork/ustfork.c | 200 +++++++++++++++++++++++++++++ liblttng-ust/Makefile.am | 9 +- liblttng-ust/creds.h | 29 +++++ liblttng-ust/lttng-context-vegid.c | 127 ++++++++++++++++++ liblttng-ust/lttng-context-veuid.c | 127 ++++++++++++++++++ liblttng-ust/lttng-context-vgid.c | 127 ++++++++++++++++++ liblttng-ust/lttng-context-vsgid.c | 132 +++++++++++++++++++ liblttng-ust/lttng-context-vsuid.c | 132 +++++++++++++++++++ liblttng-ust/lttng-context-vuid.c | 127 ++++++++++++++++++ liblttng-ust/lttng-context.c | 30 +++++ liblttng-ust/lttng-events.c | 12 ++ liblttng-ust/lttng-ust-comm.c | 62 +++++++++ 16 files changed, 1165 insertions(+), 1 deletion(-) create mode 100644 liblttng-ust/creds.h create mode 100644 liblttng-ust/lttng-context-vegid.c create mode 100644 liblttng-ust/lttng-context-veuid.c create mode 100644 liblttng-ust/lttng-context-vgid.c create mode 100644 liblttng-ust/lttng-context-vsgid.c create mode 100644 liblttng-ust/lttng-context-vsuid.c create mode 100644 liblttng-ust/lttng-context-vuid.c diff --git a/doc/man/lttng-ust.3.txt b/doc/man/lttng-ust.3.txt index ad87f403..44583fe2 100644 --- a/doc/man/lttng-ust.3.txt +++ b/doc/man/lttng-ust.3.txt @@ -826,6 +826,32 @@ The following man:namespaces(7) context fields are supported by LTTng-UST: Hostname and NIS domain name namespace: inode number of the current UTS namespace in the proc filesystem. +The following man:credentials(7) context fields are supported by LTTng-UST: + +`vuid`:: + Virtual real user ID: real user ID as seen from the point of view of + the current man:user_namespaces(7). + +`vgid`:: + Virtual real group ID: real group ID as seen from the point of view of + the current man:user_namespaces(7). + +`veuid`:: + Virtual effective user ID: effective user ID as seen from the point of + view of the current man:user_namespaces(7). + +`vegid`:: + Virtual effective group ID: effective group ID as seen from the point of + view of the current man:user_namespaces(7). + +`vsuid`:: + Virtual saved set-user ID: saved set-user ID as seen from the point of + view of the current man:user_namespaces(7). + +`vsgid`:: + Virtual saved set-group ID: saved set-group ID as seen from the point of + view of the current man:user_namespaces(7). + [[state-dump]] LTTng-UST state dump diff --git a/include/lttng/ust-abi.h b/include/lttng/ust-abi.h index d299b7de..5c934daf 100644 --- a/include/lttng/ust-abi.h +++ b/include/lttng/ust-abi.h @@ -152,6 +152,12 @@ enum lttng_ust_context_type { LTTNG_UST_CONTEXT_PID_NS = 12, LTTNG_UST_CONTEXT_USER_NS = 13, LTTNG_UST_CONTEXT_UTS_NS = 14, + LTTNG_UST_CONTEXT_VUID = 15, + LTTNG_UST_CONTEXT_VEUID = 16, + LTTNG_UST_CONTEXT_VSUID = 17, + LTTNG_UST_CONTEXT_VGID = 18, + LTTNG_UST_CONTEXT_VEGID = 19, + LTTNG_UST_CONTEXT_VSGID = 20, }; struct lttng_ust_perf_counter_ctx { diff --git a/include/lttng/ust-events.h b/include/lttng/ust-events.h index c0ec3860..89309682 100644 --- a/include/lttng/ust-events.h +++ b/include/lttng/ust-events.h @@ -686,6 +686,12 @@ int lttng_add_net_ns_to_ctx(struct lttng_ctx **ctx); int lttng_add_pid_ns_to_ctx(struct lttng_ctx **ctx); int lttng_add_user_ns_to_ctx(struct lttng_ctx **ctx); int lttng_add_uts_ns_to_ctx(struct lttng_ctx **ctx); +int lttng_add_vuid_to_ctx(struct lttng_ctx **ctx); +int lttng_add_veuid_to_ctx(struct lttng_ctx **ctx); +int lttng_add_vsuid_to_ctx(struct lttng_ctx **ctx); +int lttng_add_vgid_to_ctx(struct lttng_ctx **ctx); +int lttng_add_vegid_to_ctx(struct lttng_ctx **ctx); +int lttng_add_vsgid_to_ctx(struct lttng_ctx **ctx); void lttng_context_vtid_reset(void); void lttng_context_vpid_reset(void); void lttng_context_procname_reset(void); @@ -696,6 +702,12 @@ void lttng_context_net_ns_reset(void); void lttng_context_pid_ns_reset(void); void lttng_context_user_ns_reset(void); void lttng_context_uts_ns_reset(void); +void lttng_context_vuid_reset(void); +void lttng_context_veuid_reset(void); +void lttng_context_vsuid_reset(void); +void lttng_context_vgid_reset(void); +void lttng_context_vegid_reset(void); +void lttng_context_vsgid_reset(void); #ifdef LTTNG_UST_HAVE_PERF_EVENT int lttng_add_perf_counter_to_ctx(uint32_t type, diff --git a/include/lttng/ust.h b/include/lttng/ust.h index 0b2a8979..7befe83c 100644 --- a/include/lttng/ust.h +++ b/include/lttng/ust.h @@ -34,6 +34,14 @@ extern void ust_after_fork_parent(sigset_t *restore_sigset); extern void ust_after_fork_child(sigset_t *restore_sigset); extern void ust_after_setns(void); extern void ust_after_unshare(void); +extern void ust_after_setuid(void); +extern void ust_after_setgid(void); +extern void ust_after_seteuid(void); +extern void ust_after_setegid(void); +extern void ust_after_setreuid(void); +extern void ust_after_setregid(void); +extern void ust_after_setresuid(void); +extern void ust_after_setresgid(void); #ifdef __cplusplus } diff --git a/liblttng-ust-fork/ustfork.c b/liblttng-ust-fork/ustfork.c index 25f9d4cc..983ed04f 100644 --- a/liblttng-ust-fork/ustfork.c +++ b/liblttng-ust-fork/ustfork.c @@ -89,6 +89,156 @@ int daemon(int nochdir, int noclose) return retval; } +int setuid(uid_t uid) +{ + static int (*plibc_func)(uid_t uid) = NULL; + int retval; + int saved_errno; + + if (plibc_func == NULL) { + plibc_func = dlsym(RTLD_NEXT, "setuid"); + if (plibc_func == NULL) { + fprintf(stderr, "libustfork: unable to find \"setuid\" symbol\n"); + errno = ENOSYS; + return -1; + } + } + + /* Do the real setuid */ + retval = plibc_func(uid); + saved_errno = errno; + + ust_after_setuid(); + + errno = saved_errno; + return retval; +} + +int setgid(gid_t gid) +{ + static int (*plibc_func)(gid_t gid) = NULL; + int retval; + int saved_errno; + + if (plibc_func == NULL) { + plibc_func = dlsym(RTLD_NEXT, "setgid"); + if (plibc_func == NULL) { + fprintf(stderr, "libustfork: unable to find \"setgid\" symbol\n"); + errno = ENOSYS; + return -1; + } + } + + /* Do the real setgid */ + retval = plibc_func(gid); + saved_errno = errno; + + ust_after_setgid(); + + errno = saved_errno; + return retval; +} + +int seteuid(uid_t euid) +{ + static int (*plibc_func)(uid_t euid) = NULL; + int retval; + int saved_errno; + + if (plibc_func == NULL) { + plibc_func = dlsym(RTLD_NEXT, "seteuid"); + if (plibc_func == NULL) { + fprintf(stderr, "libustfork: unable to find \"seteuid\" symbol\n"); + errno = ENOSYS; + return -1; + } + } + + /* Do the real seteuid */ + retval = plibc_func(euid); + saved_errno = errno; + + ust_after_seteuid(); + + errno = saved_errno; + return retval; +} + +int setegid(gid_t egid) +{ + static int (*plibc_func)(gid_t egid) = NULL; + int retval; + int saved_errno; + + if (plibc_func == NULL) { + plibc_func = dlsym(RTLD_NEXT, "setegid"); + if (plibc_func == NULL) { + fprintf(stderr, "libustfork: unable to find \"setegid\" symbol\n"); + errno = ENOSYS; + return -1; + } + } + + /* Do the real setegid */ + retval = plibc_func(egid); + saved_errno = errno; + + ust_after_setegid(); + + errno = saved_errno; + return retval; +} + +int setreuid(uid_t ruid, uid_t euid) +{ + static int (*plibc_func)(uid_t ruid, uid_t euid) = NULL; + int retval; + int saved_errno; + + if (plibc_func == NULL) { + plibc_func = dlsym(RTLD_NEXT, "setreuid"); + if (plibc_func == NULL) { + fprintf(stderr, "libustfork: unable to find \"setreuid\" symbol\n"); + errno = ENOSYS; + return -1; + } + } + + /* Do the real setreuid */ + retval = plibc_func(ruid, euid); + saved_errno = errno; + + ust_after_setreuid(); + + errno = saved_errno; + return retval; +} + +int setregid(gid_t rgid, gid_t egid) +{ + static int (*plibc_func)(gid_t rgid, gid_t egid) = NULL; + int retval; + int saved_errno; + + if (plibc_func == NULL) { + plibc_func = dlsym(RTLD_NEXT, "setregid"); + if (plibc_func == NULL) { + fprintf(stderr, "libustfork: unable to find \"setregid\" symbol\n"); + errno = ENOSYS; + return -1; + } + } + + /* Do the real setregid */ + retval = plibc_func(rgid, egid); + saved_errno = errno; + + ust_after_setregid(); + + errno = saved_errno; + return retval; +} + #ifdef __linux__ struct user_desc; @@ -210,6 +360,56 @@ int unshare(int flags) return retval; } +int setresuid(uid_t ruid, uid_t euid, uid_t suid) +{ + static int (*plibc_func)(uid_t ruid, uid_t euid, uid_t suid) = NULL; + int retval; + int saved_errno; + + if (plibc_func == NULL) { + plibc_func = dlsym(RTLD_NEXT, "setresuid"); + if (plibc_func == NULL) { + fprintf(stderr, "libustfork: unable to find \"setresuid\" symbol\n"); + errno = ENOSYS; + return -1; + } + } + + /* Do the real setresuid */ + retval = plibc_func(ruid, euid, suid); + saved_errno = errno; + + ust_after_setresuid(); + + errno = saved_errno; + return retval; +} + +int setresgid(gid_t rgid, gid_t egid, gid_t sgid) +{ + static int (*plibc_func)(gid_t rgid, gid_t egid, gid_t sgid) = NULL; + int retval; + int saved_errno; + + if (plibc_func == NULL) { + plibc_func = dlsym(RTLD_NEXT, "setresgid"); + if (plibc_func == NULL) { + fprintf(stderr, "libustfork: unable to find \"setresgid\" symbol\n"); + errno = ENOSYS; + return -1; + } + } + + /* Do the real setresgid */ + retval = plibc_func(rgid, egid, sgid); + saved_errno = errno; + + ust_after_setresgid(); + + errno = saved_errno; + return retval; +} + #elif defined (__FreeBSD__) pid_t rfork(int flags) diff --git a/liblttng-ust/Makefile.am b/liblttng-ust/Makefile.am index 1f167218..abb7a8dc 100644 --- a/liblttng-ust/Makefile.am +++ b/liblttng-ust/Makefile.am @@ -40,6 +40,12 @@ liblttng_ust_runtime_la_SOURCES = \ lttng-context-pid-ns.c \ lttng-context-user-ns.c \ lttng-context-uts-ns.c \ + lttng-context-vuid.c \ + lttng-context-veuid.c \ + lttng-context-vsuid.c \ + lttng-context-vgid.c \ + lttng-context-vegid.c \ + lttng-context-vsgid.c \ lttng-context.c \ lttng-events.c \ lttng-filter.c \ @@ -69,7 +75,8 @@ liblttng_ust_runtime_la_SOURCES = \ getenv.h \ string-utils.c \ string-utils.h \ - ns.h + ns.h \ + creds.h if HAVE_PERF_EVENT liblttng_ust_runtime_la_SOURCES += \ diff --git a/liblttng-ust/creds.h b/liblttng-ust/creds.h new file mode 100644 index 00000000..b29319e0 --- /dev/null +++ b/liblttng-ust/creds.h @@ -0,0 +1,29 @@ +#ifndef _LTTNG_CREDS_H +#define _LTTNG_CREDS_H + +/* + * Copyright (c) 2019 - Michael Jeanson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * This is used in the kernel as an invalid value. + */ + +#define INVALID_UID (uid_t) -1 +#define INVALID_GID (gid_t) -1 + +#endif /* _LTTNG_CREDS_H */ diff --git a/liblttng-ust/lttng-context-vegid.c b/liblttng-ust/lttng-context-vegid.c new file mode 100644 index 00000000..70855688 --- /dev/null +++ b/liblttng-ust/lttng-context-vegid.c @@ -0,0 +1,127 @@ +/* + * lttng-context-vegid.c + * + * LTTng UST namespaced effective group ID context. + * + * Copyright (C) 2009-2012 Mathieu Desnoyers + * 2019 Michael Jeanson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _LGPL_SOURCE +#include +#include +#include +#include +#include +#include +#include "creds.h" + + +/* + * At the kernel level, user IDs and group IDs are a per-thread attribute. + * However, POSIX requires that all threads in a process share the same + * credentials. The NPTL threading implementation handles the POSIX + * requirements by providing wrapper functions for the various system calls + * that change process UIDs and GIDs. These wrapper functions (including those + * for setreuid() and setregid()) employ a signal-based technique to ensure + * that when one thread changes credentials, all of the other threads in the + * process also change their credentials. + */ + +/* + * We cache the result to ensure we don't trigger a system call for + * each event. User / group IDs are global to the process. + */ +static gid_t cached_vegid = INVALID_GID; + +static +gid_t get_vegid(void) +{ + gid_t vegid; + + vegid = CMM_LOAD_SHARED(cached_vegid); + + if (caa_unlikely(vegid == INVALID_GID)) { + vegid = getegid(); + CMM_STORE_SHARED(cached_vegid, vegid); + } + + return vegid; +} + +/* + * The vegid can change on setuid, setreuid, setresuid and seteuid. + */ +void lttng_context_vegid_reset(void) +{ + CMM_STORE_SHARED(cached_vegid, INVALID_GID); +} + +static +size_t vegid_get_size(struct lttng_ctx_field *field, size_t offset) +{ + size_t size = 0; + + size += lib_ring_buffer_align(offset, lttng_alignof(gid_t)); + size += sizeof(gid_t); + return size; +} + +static +void vegid_record(struct lttng_ctx_field *field, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + struct lttng_channel *chan) +{ + gid_t vegid; + + vegid = get_vegid(); + lib_ring_buffer_align_ctx(ctx, lttng_alignof(vegid)); + chan->ops->event_write(ctx, &vegid, sizeof(vegid)); +} + +static +void vegid_get_value(struct lttng_ctx_field *field, + struct lttng_ctx_value *value) +{ + value->u.s64 = get_vegid(); +} + +int lttng_add_vegid_to_ctx(struct lttng_ctx **ctx) +{ + struct lttng_ctx_field *field; + + field = lttng_append_context(ctx); + if (!field) + return -ENOMEM; + if (lttng_find_context(*ctx, "vegid")) { + lttng_remove_context_field(ctx, field); + return -EEXIST; + } + field->event_field.name = "vegid"; + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(gid_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = lttng_alignof(gid_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(gid_t); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; + field->get_size = vegid_get_size; + field->record = vegid_record; + field->get_value = vegid_get_value; + lttng_context_update(*ctx); + return 0; +} diff --git a/liblttng-ust/lttng-context-veuid.c b/liblttng-ust/lttng-context-veuid.c new file mode 100644 index 00000000..b627a974 --- /dev/null +++ b/liblttng-ust/lttng-context-veuid.c @@ -0,0 +1,127 @@ +/* + * lttng-context-veuid.c + * + * LTTng UST namespaced effective user ID context. + * + * Copyright (C) 2009-2012 Mathieu Desnoyers + * 2019 Michael Jeanson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _LGPL_SOURCE +#include +#include +#include +#include +#include +#include +#include "creds.h" + + +/* + * At the kernel level, user IDs and group IDs are a per-thread attribute. + * However, POSIX requires that all threads in a process share the same + * credentials. The NPTL threading implementation handles the POSIX + * requirements by providing wrapper functions for the various system calls + * that change process UIDs and GIDs. These wrapper functions (including those + * for setreuid() and setregid()) employ a signal-based technique to ensure + * that when one thread changes credentials, all of the other threads in the + * process also change their credentials. + */ + +/* + * We cache the result to ensure we don't trigger a system call for + * each event. User / group IDs are global to the process. + */ +static uid_t cached_veuid = INVALID_UID; + +static +uid_t get_veuid(void) +{ + uid_t veuid; + + veuid = CMM_LOAD_SHARED(cached_veuid); + + if (caa_unlikely(veuid == INVALID_UID)) { + veuid = geteuid(); + CMM_STORE_SHARED(cached_veuid, veuid); + } + + return veuid; +} + +/* + * The veuid can change on setuid, setreuid, setresuid and seteuid. + */ +void lttng_context_veuid_reset(void) +{ + CMM_STORE_SHARED(cached_veuid, INVALID_UID); +} + +static +size_t veuid_get_size(struct lttng_ctx_field *field, size_t offset) +{ + size_t size = 0; + + size += lib_ring_buffer_align(offset, lttng_alignof(uid_t)); + size += sizeof(uid_t); + return size; +} + +static +void veuid_record(struct lttng_ctx_field *field, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + struct lttng_channel *chan) +{ + uid_t veuid; + + veuid = get_veuid(); + lib_ring_buffer_align_ctx(ctx, lttng_alignof(veuid)); + chan->ops->event_write(ctx, &veuid, sizeof(veuid)); +} + +static +void veuid_get_value(struct lttng_ctx_field *field, + struct lttng_ctx_value *value) +{ + value->u.s64 = get_veuid(); +} + +int lttng_add_veuid_to_ctx(struct lttng_ctx **ctx) +{ + struct lttng_ctx_field *field; + + field = lttng_append_context(ctx); + if (!field) + return -ENOMEM; + if (lttng_find_context(*ctx, "veuid")) { + lttng_remove_context_field(ctx, field); + return -EEXIST; + } + field->event_field.name = "veuid"; + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(uid_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = lttng_alignof(uid_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(uid_t); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; + field->get_size = veuid_get_size; + field->record = veuid_record; + field->get_value = veuid_get_value; + lttng_context_update(*ctx); + return 0; +} diff --git a/liblttng-ust/lttng-context-vgid.c b/liblttng-ust/lttng-context-vgid.c new file mode 100644 index 00000000..7ffaf683 --- /dev/null +++ b/liblttng-ust/lttng-context-vgid.c @@ -0,0 +1,127 @@ +/* + * lttng-context-vgid.c + * + * LTTng UST namespaced real group ID context. + * + * Copyright (C) 2009-2012 Mathieu Desnoyers + * 2019 Michael Jeanson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _LGPL_SOURCE +#include +#include +#include +#include +#include +#include +#include "creds.h" + + +/* + * At the kernel level, user IDs and group IDs are a per-thread attribute. + * However, POSIX requires that all threads in a process share the same + * credentials. The NPTL threading implementation handles the POSIX + * requirements by providing wrapper functions for the various system calls + * that change process UIDs and GIDs. These wrapper functions (including those + * for setreuid() and setregid()) employ a signal-based technique to ensure + * that when one thread changes credentials, all of the other threads in the + * process also change their credentials. + */ + +/* + * We cache the result to ensure we don't trigger a system call for + * each event. User / group IDs are global to the process. + */ +static gid_t cached_vgid = INVALID_GID; + +static +gid_t get_vgid(void) +{ + gid_t vgid; + + vgid = CMM_LOAD_SHARED(cached_vgid); + + if (caa_unlikely(cached_vgid == (gid_t) -1)) { + vgid = getgid(); + CMM_STORE_SHARED(cached_vgid, vgid); + } + + return vgid; +} + +/* + * The vgid can change on setuid, setreuid and setresuid. + */ +void lttng_context_vgid_reset(void) +{ + CMM_STORE_SHARED(cached_vgid, INVALID_GID); +} + +static +size_t vgid_get_size(struct lttng_ctx_field *field, size_t offset) +{ + size_t size = 0; + + size += lib_ring_buffer_align(offset, lttng_alignof(gid_t)); + size += sizeof(gid_t); + return size; +} + +static +void vgid_record(struct lttng_ctx_field *field, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + struct lttng_channel *chan) +{ + gid_t vgid; + + vgid = get_vgid(); + lib_ring_buffer_align_ctx(ctx, lttng_alignof(vgid)); + chan->ops->event_write(ctx, &vgid, sizeof(vgid)); +} + +static +void vgid_get_value(struct lttng_ctx_field *field, + struct lttng_ctx_value *value) +{ + value->u.s64 = get_vgid(); +} + +int lttng_add_vgid_to_ctx(struct lttng_ctx **ctx) +{ + struct lttng_ctx_field *field; + + field = lttng_append_context(ctx); + if (!field) + return -ENOMEM; + if (lttng_find_context(*ctx, "vgid")) { + lttng_remove_context_field(ctx, field); + return -EEXIST; + } + field->event_field.name = "vgid"; + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(gid_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = lttng_alignof(gid_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(gid_t); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; + field->get_size = vgid_get_size; + field->record = vgid_record; + field->get_value = vgid_get_value; + lttng_context_update(*ctx); + return 0; +} diff --git a/liblttng-ust/lttng-context-vsgid.c b/liblttng-ust/lttng-context-vsgid.c new file mode 100644 index 00000000..437b01e4 --- /dev/null +++ b/liblttng-ust/lttng-context-vsgid.c @@ -0,0 +1,132 @@ +/* + * lttng-context-vsgid.c + * + * LTTng UST namespaced saved set-group ID context. + * + * Copyright (C) 2009-2012 Mathieu Desnoyers + * 2019 Michael Jeanson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _GNU_SOURCE +#define _LGPL_SOURCE +#include +#include +#include +#include +#include +#include +#include "creds.h" + + +/* + * At the kernel level, user IDs and group IDs are a per-thread attribute. + * However, POSIX requires that all threads in a process share the same + * credentials. The NPTL threading implementation handles the POSIX + * requirements by providing wrapper functions for the various system calls + * that change process UIDs and GIDs. These wrapper functions (including those + * for setreuid() and setregid()) employ a signal-based technique to ensure + * that when one thread changes credentials, all of the other threads in the + * process also change their credentials. + */ + +/* + * We cache the result to ensure we don't trigger a system call for + * each event. User / group IDs are global to the process. + */ +static gid_t cached_vsgid = INVALID_GID; + +static +gid_t get_vsgid(void) +{ + gid_t vsgid; + + vsgid = CMM_LOAD_SHARED(cached_vsgid); + + if (caa_unlikely(vsgid == INVALID_GID)) { + gid_t gid, egid, sgid; + + if (getresgid(&gid, &egid, &sgid) == 0) { + vsgid = sgid; + CMM_STORE_SHARED(cached_vsgid, vsgid); + } + } + + return vsgid; +} + +/* + * The vsgid can change on setuid, setreuid and setresuid. + */ +void lttng_context_vsgid_reset(void) +{ + CMM_STORE_SHARED(cached_vsgid, INVALID_GID); +} + +static +size_t vsgid_get_size(struct lttng_ctx_field *field, size_t offset) +{ + size_t size = 0; + + size += lib_ring_buffer_align(offset, lttng_alignof(gid_t)); + size += sizeof(gid_t); + return size; +} + +static +void vsgid_record(struct lttng_ctx_field *field, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + struct lttng_channel *chan) +{ + gid_t vsgid; + + vsgid = get_vsgid(); + lib_ring_buffer_align_ctx(ctx, lttng_alignof(vsgid)); + chan->ops->event_write(ctx, &vsgid, sizeof(vsgid)); +} + +static +void vsgid_get_value(struct lttng_ctx_field *field, + struct lttng_ctx_value *value) +{ + value->u.s64 = get_vsgid(); +} + +int lttng_add_vsgid_to_ctx(struct lttng_ctx **ctx) +{ + struct lttng_ctx_field *field; + + field = lttng_append_context(ctx); + if (!field) + return -ENOMEM; + if (lttng_find_context(*ctx, "vsgid")) { + lttng_remove_context_field(ctx, field); + return -EEXIST; + } + field->event_field.name = "vsgid"; + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(gid_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = lttng_alignof(gid_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(gid_t); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; + field->get_size = vsgid_get_size; + field->record = vsgid_record; + field->get_value = vsgid_get_value; + lttng_context_update(*ctx); + return 0; +} diff --git a/liblttng-ust/lttng-context-vsuid.c b/liblttng-ust/lttng-context-vsuid.c new file mode 100644 index 00000000..56f3d073 --- /dev/null +++ b/liblttng-ust/lttng-context-vsuid.c @@ -0,0 +1,132 @@ +/* + * lttng-context-vsuid.c + * + * LTTng UST namespaced saved set-user ID context. + * + * Copyright (C) 2009-2012 Mathieu Desnoyers + * 2019 Michael Jeanson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _GNU_SOURCE +#define _LGPL_SOURCE +#include +#include +#include +#include +#include +#include +#include "creds.h" + + +/* + * At the kernel level, user IDs and group IDs are a per-thread attribute. + * However, POSIX requires that all threads in a process share the same + * credentials. The NPTL threading implementation handles the POSIX + * requirements by providing wrapper functions for the various system calls + * that change process UIDs and GIDs. These wrapper functions (including those + * for setreuid() and setregid()) employ a signal-based technique to ensure + * that when one thread changes credentials, all of the other threads in the + * process also change their credentials. + */ + +/* + * We cache the result to ensure we don't trigger a system call for + * each event. User / group IDs are global to the process. + */ +static uid_t cached_vsuid = INVALID_UID; + +static +uid_t get_vsuid(void) +{ + uid_t vsuid; + + vsuid = CMM_LOAD_SHARED(cached_vsuid); + + if (caa_unlikely(vsuid == INVALID_UID)) { + uid_t uid, euid, suid; + + if (getresuid(&uid, &euid, &suid) == 0) { + vsuid = suid; + CMM_STORE_SHARED(cached_vsuid, vsuid); + } + } + + return vsuid; +} + +/* + * The vsuid can change on setuid, setreuid and setresuid. + */ +void lttng_context_vsuid_reset(void) +{ + CMM_STORE_SHARED(cached_vsuid, INVALID_UID); +} + +static +size_t vsuid_get_size(struct lttng_ctx_field *field, size_t offset) +{ + size_t size = 0; + + size += lib_ring_buffer_align(offset, lttng_alignof(uid_t)); + size += sizeof(uid_t); + return size; +} + +static +void vsuid_record(struct lttng_ctx_field *field, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + struct lttng_channel *chan) +{ + uid_t vsuid; + + vsuid = get_vsuid(); + lib_ring_buffer_align_ctx(ctx, lttng_alignof(vsuid)); + chan->ops->event_write(ctx, &vsuid, sizeof(vsuid)); +} + +static +void vsuid_get_value(struct lttng_ctx_field *field, + struct lttng_ctx_value *value) +{ + value->u.s64 = get_vsuid(); +} + +int lttng_add_vsuid_to_ctx(struct lttng_ctx **ctx) +{ + struct lttng_ctx_field *field; + + field = lttng_append_context(ctx); + if (!field) + return -ENOMEM; + if (lttng_find_context(*ctx, "vsuid")) { + lttng_remove_context_field(ctx, field); + return -EEXIST; + } + field->event_field.name = "vsuid"; + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(uid_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = lttng_alignof(uid_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(uid_t); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; + field->get_size = vsuid_get_size; + field->record = vsuid_record; + field->get_value = vsuid_get_value; + lttng_context_update(*ctx); + return 0; +} diff --git a/liblttng-ust/lttng-context-vuid.c b/liblttng-ust/lttng-context-vuid.c new file mode 100644 index 00000000..54167519 --- /dev/null +++ b/liblttng-ust/lttng-context-vuid.c @@ -0,0 +1,127 @@ +/* + * lttng-context-vuid.c + * + * LTTng UST namespaced real user ID context. + * + * Copyright (C) 2009-2012 Mathieu Desnoyers + * 2019 Michael Jeanson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _LGPL_SOURCE +#include +#include +#include +#include +#include +#include +#include "creds.h" + + +/* + * At the kernel level, user IDs and group IDs are a per-thread attribute. + * However, POSIX requires that all threads in a process share the same + * credentials. The NPTL threading implementation handles the POSIX + * requirements by providing wrapper functions for the various system calls + * that change process UIDs and GIDs. These wrapper functions (including those + * for setreuid() and setregid()) employ a signal-based technique to ensure + * that when one thread changes credentials, all of the other threads in the + * process also change their credentials. + */ + +/* + * We cache the result to ensure we don't trigger a system call for + * each event. User / group IDs are global to the process. + */ +static uid_t cached_vuid = INVALID_UID; + +static +uid_t get_vuid(void) +{ + uid_t vuid; + + vuid = CMM_LOAD_SHARED(cached_vuid); + + if (caa_unlikely(vuid == INVALID_UID)) { + vuid = getuid(); + CMM_STORE_SHARED(cached_vuid, vuid); + } + + return vuid; +} + +/* + * The vuid can change on setuid, setreuid and setresuid. + */ +void lttng_context_vuid_reset(void) +{ + CMM_STORE_SHARED(cached_vuid, INVALID_UID); +} + +static +size_t vuid_get_size(struct lttng_ctx_field *field, size_t offset) +{ + size_t size = 0; + + size += lib_ring_buffer_align(offset, lttng_alignof(uid_t)); + size += sizeof(uid_t); + return size; +} + +static +void vuid_record(struct lttng_ctx_field *field, + struct lttng_ust_lib_ring_buffer_ctx *ctx, + struct lttng_channel *chan) +{ + uid_t vuid; + + vuid = get_vuid(); + lib_ring_buffer_align_ctx(ctx, lttng_alignof(vuid)); + chan->ops->event_write(ctx, &vuid, sizeof(vuid)); +} + +static +void vuid_get_value(struct lttng_ctx_field *field, + struct lttng_ctx_value *value) +{ + value->u.s64 = get_vuid(); +} + +int lttng_add_vuid_to_ctx(struct lttng_ctx **ctx) +{ + struct lttng_ctx_field *field; + + field = lttng_append_context(ctx); + if (!field) + return -ENOMEM; + if (lttng_find_context(*ctx, "vuid")) { + lttng_remove_context_field(ctx, field); + return -EEXIST; + } + field->event_field.name = "vuid"; + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(uid_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = lttng_alignof(uid_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(uid_t); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; + field->get_size = vuid_get_size; + field->record = vuid_record; + field->get_value = vuid_get_value; + lttng_context_update(*ctx); + return 0; +} diff --git a/liblttng-ust/lttng-context.c b/liblttng-ust/lttng-context.c index ad6c38f0..e408defc 100644 --- a/liblttng-ust/lttng-context.c +++ b/liblttng-ust/lttng-context.c @@ -407,6 +407,36 @@ int lttng_session_context_init(struct lttng_ctx **ctx) WARN("Cannot add context lttng_add_uts_ns_to_ctx"); goto error; } + ret = lttng_add_vuid_to_ctx(ctx); + if (ret) { + WARN("Cannot add context lttng_add_vuid_to_ctx"); + goto error; + } + ret = lttng_add_veuid_to_ctx(ctx); + if (ret) { + WARN("Cannot add context lttng_add_veuid_to_ctx"); + goto error; + } + ret = lttng_add_vsuid_to_ctx(ctx); + if (ret) { + WARN("Cannot add context lttng_add_vsuid_to_ctx"); + goto error; + } + ret = lttng_add_vgid_to_ctx(ctx); + if (ret) { + WARN("Cannot add context lttng_add_vgid_to_ctx"); + goto error; + } + ret = lttng_add_vegid_to_ctx(ctx); + if (ret) { + WARN("Cannot add context lttng_add_vegid_to_ctx"); + goto error; + } + ret = lttng_add_vsgid_to_ctx(ctx); + if (ret) { + WARN("Cannot add context lttng_add_vsgid_to_ctx"); + goto error; + } lttng_context_update(*ctx); return 0; diff --git a/liblttng-ust/lttng-events.c b/liblttng-ust/lttng-events.c index 855f8d87..047759b7 100644 --- a/liblttng-ust/lttng-events.c +++ b/liblttng-ust/lttng-events.c @@ -1126,6 +1126,18 @@ int lttng_attach_context(struct lttng_ust_context *context_param, return lttng_add_user_ns_to_ctx(ctx); case LTTNG_UST_CONTEXT_UTS_NS: return lttng_add_uts_ns_to_ctx(ctx); + case LTTNG_UST_CONTEXT_VUID: + return lttng_add_vuid_to_ctx(ctx); + case LTTNG_UST_CONTEXT_VEUID: + return lttng_add_veuid_to_ctx(ctx); + case LTTNG_UST_CONTEXT_VSUID: + return lttng_add_vsuid_to_ctx(ctx); + case LTTNG_UST_CONTEXT_VGID: + return lttng_add_vgid_to_ctx(ctx); + case LTTNG_UST_CONTEXT_VEGID: + return lttng_add_vegid_to_ctx(ctx); + case LTTNG_UST_CONTEXT_VSGID: + return lttng_add_vsgid_to_ctx(ctx); default: return -EINVAL; } diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index 09a25bd6..1c846047 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -1996,6 +1996,22 @@ void ust_context_ns_reset(void) lttng_context_uts_ns_reset(); } +static +void ust_context_vuids_reset(void) +{ + lttng_context_vuid_reset(); + lttng_context_veuid_reset(); + lttng_context_vsuid_reset(); +} + +static +void ust_context_vgids_reset(void) +{ + lttng_context_vgid_reset(); + lttng_context_vegid_reset(); + lttng_context_vsgid_reset(); +} + /* * We exclude the worker threads across fork and clone (except * CLONE_VM), because these system calls only keep the forking thread @@ -2075,6 +2091,8 @@ void ust_after_fork_child(sigset_t *restore_sigset) lttng_context_vtid_reset(); lttng_context_procname_reset(); ust_context_ns_reset(); + ust_context_vuids_reset(); + ust_context_vgids_reset(); DBG("process %d", getpid()); /* Release urcu mutexes */ urcu_bp_after_fork_child(); @@ -2087,11 +2105,55 @@ void ust_after_fork_child(sigset_t *restore_sigset) void ust_after_setns(void) { ust_context_ns_reset(); + ust_context_vuids_reset(); + ust_context_vgids_reset(); } void ust_after_unshare(void) { ust_context_ns_reset(); + ust_context_vuids_reset(); + ust_context_vgids_reset(); +} + +void ust_after_setuid(void) +{ + ust_context_vuids_reset(); +} + +void ust_after_seteuid(void) +{ + ust_context_vuids_reset(); +} + +void ust_after_setreuid(void) +{ + ust_context_vuids_reset(); +} + +void ust_after_setresuid(void) +{ + ust_context_vuids_reset(); +} + +void ust_after_setgid(void) +{ + ust_context_vgids_reset(); +} + +void ust_after_setegid(void) +{ + ust_context_vgids_reset(); +} + +void ust_after_setregid(void) +{ + ust_context_vgids_reset(); +} + +void ust_after_setresgid(void) +{ + ust_context_vgids_reset(); } void lttng_ust_sockinfo_session_enabled(void *owner) -- 2.34.1