From 20142124a2e34c287a277bbd7ef5b28697735d10 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Mon, 7 Oct 2019 15:45:46 -0400 Subject: [PATCH 01/16] Fix: lttng perf counter deadlock Using the ust_lock() to lazily setup the perf counters introduces a scenario where this lock is nested within the urcu-bp read-side lock. However, the LTTNG_UST_WAIT_QUIESCENT ust command requires that urcu-bp synchronize_rcu() is performed with the ust_lock() held. This inter-dependency introduces a deadlock: Thread A Thread B rcu_read_lock() ust_lock() synchronize_rcu() (blocked by rcu read-side lock) ust_lock() <-- deadlock Introduce a new lttng_perf_lock to protect the lttng perf context data structures from concurrent modifications and from fork. This lock can be nested within the ust_lock, but never the opposite. This removes the circular locking dependency involving urcu bp. Fixes: #1202 Signed-off-by: Mathieu Desnoyers --- liblttng-ust/lttng-context-perf-counters.c | 109 +++++++++++++++++++-- liblttng-ust/lttng-tracer-core.h | 19 ++++ liblttng-ust/lttng-ust-comm.c | 3 + 3 files changed, 125 insertions(+), 6 deletions(-) diff --git a/liblttng-ust/lttng-context-perf-counters.c b/liblttng-ust/lttng-context-perf-counters.c index 4816f89b..a6ff55b6 100644 --- a/liblttng-ust/lttng-context-perf-counters.c +++ b/liblttng-ust/lttng-context-perf-counters.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "perf_event.h" #include "lttng-tracer-core.h" @@ -71,6 +72,98 @@ struct lttng_perf_counter_field { static pthread_key_t perf_counter_key; +/* + * lttng_perf_lock - Protect lttng-ust perf counter data structures + * + * Nests within the ust_lock, and therefore within the libc dl lock. + * Therefore, we need to fixup the TLS before nesting into this lock. + * Nests inside RCU bp read-side lock. Protects against concurrent + * fork. + */ +static pthread_mutex_t ust_perf_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* + * Cancel state when grabbing the ust_perf_mutex. Saved when locking, + * restored on unlock. Protected by ust_perf_mutex. + */ +static int ust_perf_saved_cancelstate; + +/* + * Track whether we are tracing from a signal handler nested on an + * application thread. + */ +static DEFINE_URCU_TLS(int, ust_perf_mutex_nest); + +/* + * Force a read (imply TLS fixup for dlopen) of TLS variables. + */ +void lttng_ust_fixup_perf_counter_tls(void) +{ + asm volatile ("" : : "m" (URCU_TLS(ust_perf_mutex_nest))); +} + +void lttng_perf_lock(void) +{ + sigset_t sig_all_blocked, orig_mask; + int ret, oldstate; + + ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); + if (ret) { + ERR("pthread_setcancelstate: %s", strerror(ret)); + } + sigfillset(&sig_all_blocked); + ret = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_mask); + if (ret) { + ERR("pthread_sigmask: %s", strerror(ret)); + } + if (!URCU_TLS(ust_perf_mutex_nest)++) { + /* + * Ensure the compiler don't move the store after the close() + * call in case close() would be marked as leaf. + */ + cmm_barrier(); + pthread_mutex_lock(&ust_perf_mutex); + ust_perf_saved_cancelstate = oldstate; + } + ret = pthread_sigmask(SIG_SETMASK, &orig_mask, NULL); + if (ret) { + ERR("pthread_sigmask: %s", strerror(ret)); + } +} + +void lttng_perf_unlock(void) +{ + sigset_t sig_all_blocked, orig_mask; + int ret, newstate, oldstate; + bool restore_cancel = false; + + sigfillset(&sig_all_blocked); + ret = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_mask); + if (ret) { + ERR("pthread_sigmask: %s", strerror(ret)); + } + /* + * Ensure the compiler don't move the store before the close() + * call, in case close() would be marked as leaf. + */ + cmm_barrier(); + if (!--URCU_TLS(ust_perf_mutex_nest)) { + newstate = ust_perf_saved_cancelstate; + restore_cancel = true; + pthread_mutex_unlock(&ust_perf_mutex); + } + ret = pthread_sigmask(SIG_SETMASK, &orig_mask, NULL); + if (ret) { + ERR("pthread_sigmask: %s", strerror(ret)); + } + if (restore_cancel) { + ret = pthread_setcancelstate(newstate, &oldstate); + if (ret) { + ERR("pthread_setcancelstate: %s", strerror(ret)); + } + } +} + static size_t perf_counter_get_size(struct lttng_ctx_field *field, size_t offset) { @@ -308,12 +401,12 @@ struct lttng_perf_counter_thread_field * * Note: thread_field->pc can be NULL if setup_perf() fails. * Also, thread_field->fd can be -1 if open_perf_fd() fails. */ - ust_lock_nocheck(); + lttng_perf_lock(); cds_list_add_rcu(&thread_field->rcu_field_node, &perf_thread->rcu_field_list); cds_list_add(&thread_field->thread_field_node, &perf_field->thread_field_list); - ust_unlock(); + lttng_perf_unlock(); skip: ret = pthread_sigmask(SIG_SETMASK, &oldmask, NULL); if (ret) @@ -370,7 +463,7 @@ void perf_counter_get_value(struct lttng_ctx_field *field, value->u.s64 = wrapper_perf_counter_read(field); } -/* Called with UST lock held */ +/* Called with perf lock held */ static void lttng_destroy_perf_thread_field( struct lttng_perf_counter_thread_field *thread_field) @@ -388,11 +481,11 @@ void lttng_destroy_perf_thread_key(void *_key) struct lttng_perf_counter_thread *perf_thread = _key; struct lttng_perf_counter_thread_field *pos, *p; - ust_lock_nocheck(); + lttng_perf_lock(); cds_list_for_each_entry_safe(pos, p, &perf_thread->rcu_field_list, rcu_field_node) lttng_destroy_perf_thread_field(pos); - ust_unlock(); + lttng_perf_unlock(); free(perf_thread); } @@ -408,11 +501,15 @@ void lttng_destroy_perf_counter_field(struct lttng_ctx_field *field) /* * This put is performed when no threads can concurrently * perform a "get" concurrently, thanks to urcu-bp grace - * period. + * period. Holding the lttng perf lock protects against + * concurrent modification of the per-thread thread field + * list. */ + lttng_perf_lock(); cds_list_for_each_entry_safe(pos, p, &perf_field->thread_field_list, thread_field_node) lttng_destroy_perf_thread_field(pos); + lttng_perf_unlock(); free(perf_field); } diff --git a/liblttng-ust/lttng-tracer-core.h b/liblttng-ust/lttng-tracer-core.h index ba232f32..f750f4b0 100644 --- a/liblttng-ust/lttng-tracer-core.h +++ b/liblttng-ust/lttng-tracer-core.h @@ -64,4 +64,23 @@ void lttng_ust_dummy_get_value(struct lttng_ctx_field *field, int lttng_context_is_app(const char *name); void lttng_ust_fixup_tls(void); +#ifdef LTTNG_UST_HAVE_PERF_EVENT +void lttng_ust_fixup_perf_counter_tls(void); +void lttng_perf_lock(void); +void lttng_perf_unlock(void); +#else /* #ifdef LTTNG_UST_HAVE_PERF_EVENT */ +static inline +void lttng_ust_fixup_perf_counter_tls(void) +{ +} +static inline +void lttng_perf_lock(void) +{ +} +static inline +void lttng_perf_unlock(void) +{ +} +#endif /* #else #ifdef LTTNG_UST_HAVE_PERF_EVENT */ + #endif /* _LTTNG_TRACER_CORE_H */ diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index 47ba36e5..b067b3da 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -423,6 +423,7 @@ void lttng_ust_fixup_tls(void) lttng_fixup_nest_count_tls(); lttng_fixup_procname_tls(); lttng_fixup_ust_mutex_nest_tls(); + lttng_ust_fixup_perf_counter_tls(); lttng_ust_fixup_fd_tracker_tls(); } @@ -2068,6 +2069,7 @@ void ust_before_fork(sigset_t *save_sigset) ust_lock_nocheck(); urcu_bp_before_fork(); lttng_ust_lock_fd_tracker(); + lttng_perf_lock(); } static void ust_after_fork_common(sigset_t *restore_sigset) @@ -2075,6 +2077,7 @@ static void ust_after_fork_common(sigset_t *restore_sigset) int ret; DBG("process %d", getpid()); + lttng_perf_unlock(); lttng_ust_unlock_fd_tracker(); ust_unlock(); -- 2.34.1 From 735bef4705cc42f25d26f25be09ba98f1efb8511 Mon Sep 17 00:00:00 2001 From: Michael Jeanson Date: Tue, 12 Feb 2019 10:38:25 -0500 Subject: [PATCH 02/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 Signed-off-by: Mathieu Desnoyers --- 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 2a3003a7..9865547e 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..d4053150 --- /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", + lttng_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..c973dc86 --- /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", + lttng_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..9d6ded12 --- /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", + lttng_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..fb2d89f9 --- /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", + lttng_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 f750f4b0..52315a8d 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 b067b3da..5a2aacdf 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -425,6 +425,10 @@ void lttng_ust_fixup_tls(void) lttng_fixup_ust_mutex_nest_tls(); lttng_ust_fixup_perf_counter_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) @@ -2034,6 +2038,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 @@ -2116,6 +2132,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(); @@ -2125,6 +2142,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 fca2f1916cd9f22f410d8f22b9a0720c978c2025 Mon Sep 17 00:00:00 2001 From: Michael Jeanson Date: Tue, 12 Feb 2019 10:40:48 -0500 Subject: [PATCH 03/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 Signed-off-by: Mathieu Desnoyers --- 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 9865547e..1bd4d1e0 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 5a2aacdf..79f0f28a 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -2050,6 +2050,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 @@ -2133,6 +2149,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(); @@ -2145,11 +2163,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 From b9c0e605c261aa81738046b7d7a2b571bf3777ed Mon Sep 17 00:00:00 2001 From: Michael Jeanson Date: Mon, 21 Oct 2019 13:04:14 -0400 Subject: [PATCH 04/16] Fix: Add missing files to distribution Signed-off-by: Michael Jeanson Signed-off-by: Mathieu Desnoyers --- Makefile.am | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index 810761ca..73b51909 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,9 +34,18 @@ SUBDIRS += tests doc pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = lttng-ust.pc -dist_doc_DATA = README.md ChangeLog - -dist_noinst_DATA = CodingStyle +dist_doc_DATA = \ + ChangeLog \ + COPYING \ + LICENSE \ + README.md + +dist_noinst_DATA = \ + CodingStyle \ + CONTRIBUTING.md \ + gpl-2.0.txt \ + lgpl-2.1.txt \ + mit-license.txt check-loop: cd tests && $(MAKE) $(AM_MAKEFLAGS) check-loop -- 2.34.1 From 1e1782558131e5669466639d7f28e2f08b0d026d Mon Sep 17 00:00:00 2001 From: Michael Jeanson Date: Mon, 21 Oct 2019 13:04:31 -0400 Subject: [PATCH 05/16] Fix: document proper liburcu version dependency Signed-off-by: Mathieu Desnoyers --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ff491701..fc2cc6c0 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ user space tracing helpers for any application. Prerequisites ------------- -LTTng-UST depends on [liburcu](http://liburcu.org/) v0.7.2 at build and +LTTng-UST depends on **[liburcu](http://liburcu.org/) >= 0.11** at build and run times. It also optionally depends on libnuma. -- 2.34.1 From 730be651d21f3950980fd61e1c65953017c6322e Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 22 Oct 2019 15:29:48 -0400 Subject: [PATCH 06/16] Fix: uninitialized variable in lib_ring_buffer_reserve_committed This internal function implemented in libringbuffer is not used within lttng-ust actually, but uses an uninitialized variable: As reported by clang: ./frontend_internal.h:263:75: warning: variable 'idx' is uninitialized when used here [-Wuninitialized] struct commit_counters_hot *cc_hot = shmp_index(handle, buf->commit_hot, idx); ^~~ ./shm.h:74:86: note: expanded from macro 'shmp_index' ____ptr_ret = (__typeof__(____ptr_ret)) _shmp_offset((handle)->table, &(ref)._ref, index, sizeof(*____ptr_ret)); \ ^~~~~ ./frontend_internal.h:262:27: note: initialize the variable 'idx' to silence this warning unsigned long offset, idx, commit_count; ^ = 0 In file included from ring_buffer_backend.c:29: In file included from ./backend.h:33: ./frontend_internal.h:263:75: warning: variable 'idx' is uninitialized when used here [-Wuninitialized] struct commit_counters_hot *cc_hot = shmp_index(handle, buf->commit_hot, idx); ^~~ ./shm.h:74:86: note: expanded from macro 'shmp_index' ____ptr_ret = (__typeof__(____ptr_ret)) _shmp_offset((handle)->table, &(ref)._ref, index, sizeof(*____ptr_ret)); \ ^~~~~ ./frontend_internal.h:262:27: note: initialize the variable 'idx' to silence this warning unsigned long offset, idx, commit_count; ^ = 0 Signed-off-by: Mathieu Desnoyers --- libringbuffer/frontend_internal.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libringbuffer/frontend_internal.h b/libringbuffer/frontend_internal.h index 4ad921ec..1a9c2d4b 100644 --- a/libringbuffer/frontend_internal.h +++ b/libringbuffer/frontend_internal.h @@ -260,14 +260,11 @@ int lib_ring_buffer_reserve_committed(const struct lttng_ust_lib_ring_buffer_con struct lttng_ust_shm_handle *handle) { unsigned long offset, idx, commit_count; - struct commit_counters_hot *cc_hot = shmp_index(handle, buf->commit_hot, idx); + struct commit_counters_hot *cc_hot; CHAN_WARN_ON(chan, config->alloc != RING_BUFFER_ALLOC_PER_CPU); CHAN_WARN_ON(chan, config->sync != RING_BUFFER_SYNC_PER_CPU); - if (caa_unlikely(!cc_hot)) - return 0; - /* * Read offset and commit count in a loop so they are both read * atomically wrt interrupts. By deal with interrupt concurrency by @@ -279,6 +276,9 @@ int lib_ring_buffer_reserve_committed(const struct lttng_ust_lib_ring_buffer_con do { offset = v_read(config, &buf->offset); idx = subbuf_index(offset, chan); + cc_hot = shmp_index(handle, buf->commit_hot, idx); + if (caa_unlikely(!cc_hot)) + return 0; commit_count = v_read(config, &cc_hot->cc); } while (offset != v_read(config, &buf->offset)); -- 2.34.1 From a1acf2a6a975996aefdae82362c2bda749da2ff4 Mon Sep 17 00:00:00 2001 From: Michael Jeanson Date: Wed, 23 Oct 2019 11:11:30 -0400 Subject: [PATCH 07/16] Add pkgconfig support for liblttng-ust-ctl Signed-off-by: Michael Jeanson Signed-off-by: Mathieu Desnoyers --- Makefile.am | 2 +- configure.ac | 1 + lttng-ust-ctl.pc.in | 12 ++++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 lttng-ust-ctl.pc.in diff --git a/Makefile.am b/Makefile.am index 73b51909..cc923c1d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -32,7 +32,7 @@ SUBDIRS += tests doc # liblttng-ust-malloc pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = lttng-ust.pc +pkgconfig_DATA = lttng-ust.pc lttng-ust-ctl.pc dist_doc_DATA = \ ChangeLog \ diff --git a/configure.ac b/configure.ac index 52fc3f68..580e0ee3 100644 --- a/configure.ac +++ b/configure.ac @@ -555,6 +555,7 @@ AC_CONFIG_FILES([ tests/test-app-ctx/Makefile tests/gcc-weak-hidden/Makefile lttng-ust.pc + lttng-ust-ctl.pc ]) # Create link for python agent for the VPATH guru. diff --git a/lttng-ust-ctl.pc.in b/lttng-ust-ctl.pc.in new file mode 100644 index 00000000..3170b30a --- /dev/null +++ b/lttng-ust-ctl.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: LTTng Userspace Tracer control +Description: The LTTng Userspace Tracer (UST) is a library accompanied by a set of tools to trace userspace code. +Version: @PACKAGE_VERSION@ +Requires: +Libs: -L${libdir} -llttng-ust-ctl +Cflags: -I${includedir} + -- 2.34.1 From f3f8edfa3c51df19ac7369023754af72ba4664fa Mon Sep 17 00:00:00 2001 From: Michael Jeanson Date: Wed, 23 Oct 2019 11:31:32 -0400 Subject: [PATCH 08/16] Set version to 2.12-pre Signed-off-by: Michael Jeanson Signed-off-by: Mathieu Desnoyers --- configure.ac | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 580e0ee3..319cb401 100644 --- a/configure.ac +++ b/configure.ac @@ -1,10 +1,10 @@ dnl Version infos m4_define([V_MAJOR], [2]) -m4_define([V_MINOR], [11]) +m4_define([V_MINOR], [12]) m4_define([V_PATCH], [0]) -m4_define([V_EXTRA], [rc1]) -m4_define([V_NAME], [[Lafontaine]]) -m4_define([V_DESC], [[A modern Saison beer from Montréal's Oshlag microbrewery, Lafontaine is a refreshing, zesty, rice beer with hints of fruit and spices.]]) +m4_define([V_EXTRA], [pre]) +m4_define([V_NAME], [[Codename TBD]]) +m4_define([V_DESC], [[Description TBD]]) m4_define([V_STRING], [V_MAJOR.V_MINOR.V_PATCH]) m4_ifdef([V_EXTRA], [m4_append([V_STRING], [-V_EXTRA])]) -- 2.34.1 From df807054e56e2b476278b1da34de7204e1925452 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Thu, 24 Oct 2019 15:08:28 -0400 Subject: [PATCH 09/16] Docs: LTTNG-UST(3): missing references to some namespace man pages MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The LTTNG-UST(3) manual page is missing references to the mount, network, ipc, and uts namespace man pages. Signed-off-by: Jérémie Galarneau Signed-off-by: Mathieu Desnoyers --- doc/man/lttng-ust.3.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/man/lttng-ust.3.txt b/doc/man/lttng-ust.3.txt index 1bd4d1e0..2534612a 100644 --- a/doc/man/lttng-ust.3.txt +++ b/doc/man/lttng-ust.3.txt @@ -804,15 +804,15 @@ The following man:namespaces(7) context fields are supported by LTTng-UST: `ipc_ns`:: System V IPC, POSIX message queues namespace: inode number of the - current IPC namespace in the proc filesystem. + current man:ipc_namespaces(7) namespace in the proc filesystem. `mnt_ns`:: - Mount points namespace: inode number of the current Mount namespace - in the proc filesystem. + Mount points namespace: inode number of the current + man:mount_namespaces(7) in the proc filesystem. `net_ns`:: Network devices, stacks, ports namespace: inode number of the - current Network namespace in the proc filesystem. + current man:network_namespaces(7) in the proc filesystem. `pid_ns`:: Process IDs namespace: inode number of the current @@ -824,7 +824,7 @@ The following man:namespaces(7) context fields are supported by LTTng-UST: `uts_ns`:: Hostname and NIS domain name namespace: inode number of the - current UTS namespace in the proc filesystem. + current man:uts_namespaces(7) in the proc filesystem. The following man:credentials(7) context fields are supported by LTTng-UST: -- 2.34.1 From 94be38e8fd2d71397f79c0a368ba95678052e32d Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Fri, 28 Jun 2019 17:28:15 -0400 Subject: [PATCH 10/16] Add procname to lttng_ust_statedump information Adding the process procname to the statedump allows users to disable procname context in scenario for which the data and serialization overhead of the procname process is problematic. Users can stitch information in post-processing based on other contexts (pid). Users can skip this statedump via the LTTNG_UST_WITHOUT_PROCNAME_STATEDUMP env variable. Note that the procname statedump value is the procname seen at application start (lttng_ust_init). Subsequent calls to pthread_setname_np or equivalent have no effect on this value. Since we cannot use the current thread name due to the lttng_pthread_setname_np call in ust_listener_thread, we store the process name inside the sock_info struct before the call to lttng_pthread_setname_np. This data structure is already present as the "owner" object in the statedump mechanism. During the statedump, we fetch the procname from the "owner" object. Use LTTNG_HIDDEN to reduce visibility of lttng_ust_sockinfo_get_procname. Signed-off-by: Jonathan Rajotte Signed-off-by: Mathieu Desnoyers --- doc/man/lttng-ust.3.txt | 18 ++++++++++++++++++ include/helper.h | 11 +++++++++++ liblttng-ust/lttng-tracer-core.h | 4 ++++ liblttng-ust/lttng-ust-comm.c | 16 ++++++++++++++++ liblttng-ust/lttng-ust-statedump-provider.h | 11 +++++++++++ liblttng-ust/lttng-ust-statedump.c | 19 +++++++++++++++++++ 6 files changed, 79 insertions(+) diff --git a/doc/man/lttng-ust.3.txt b/doc/man/lttng-ust.3.txt index 2534612a..507aaca5 100644 --- a/doc/man/lttng-ust.3.txt +++ b/doc/man/lttng-ust.3.txt @@ -952,6 +952,20 @@ Fields: |Debug link file name. |=== +`lttng_ust_statedump:procname`:: + The process procname at process start. ++ +Fields: ++ +[options="header"] +|=== +|Field name |Description + +|`procname` +|The process name. + +|=== + [[ust-lib]] Shared library load/unload tracking @@ -1395,6 +1409,10 @@ Default: {lttng_ust_register_timeout}. If set, prevents `liblttng-ust` from performing a base address state dump (see the <> section above). +`LTTNG_UST_WITHOUT_PROCNAME_STATEDUMP`:: + If set, prevents `liblttng-ust` from performing a procname state + dump (see the <> section above). + include::common-footer.txt[] diff --git a/include/helper.h b/include/helper.h index 9873fead..a187b0e7 100644 --- a/include/helper.h +++ b/include/helper.h @@ -55,4 +55,15 @@ void *zmalloc(size_t len) #define LTTNG_UST_CALLER_IP() __builtin_return_address(0) #endif /* #else #if defined(__PPC__) && !defined(__PPC64__) */ +/* + * LTTNG_HIDDEN: set the hidden attribute for internal functions + * On Windows, symbols are local unless explicitly exported, + * see https://gcc.gnu.org/wiki/Visibility + */ +#if defined(_WIN32) || defined(__CYGWIN__) +#define LTTNG_HIDDEN +#else +#define LTTNG_HIDDEN __attribute__((visibility("hidden"))) +#endif + #endif /* _LTTNG_UST_HELPER_H */ diff --git a/liblttng-ust/lttng-tracer-core.h b/liblttng-ust/lttng-tracer-core.h index 52315a8d..bd837237 100644 --- a/liblttng-ust/lttng-tracer-core.h +++ b/liblttng-ust/lttng-tracer-core.h @@ -29,6 +29,7 @@ #include #include #include +#include /* * The longuest possible namespace proc path is with the cgroup ns @@ -61,6 +62,9 @@ const char *lttng_ust_obj_get_name(int id); int lttng_get_notify_socket(void *owner); +LTTNG_HIDDEN +char* lttng_ust_sockinfo_get_procname(void *owner); + void lttng_ust_sockinfo_session_enabled(void *owner); void lttng_ust_malloc_wrapper_init(void); diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index 79f0f28a..9d0c010d 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -263,6 +263,8 @@ struct sock_info { /* Keep track of lazy state dump not performed yet. */ int statedump_pending; int initial_statedump_done; + /* Keep procname for statedump */ + char procname[LTTNG_UST_PROCNAME_LEN]; }; /* Socket from app (connect) to session daemon (listen) for communication */ @@ -283,6 +285,7 @@ struct sock_info global_apps = { .statedump_pending = 0, .initial_statedump_done = 0, + .procname[0] = '\0' }; /* TODO: allow global_apps_sock_path override */ @@ -300,6 +303,7 @@ struct sock_info local_apps = { .statedump_pending = 0, .initial_statedump_done = 0, + .procname[0] = '\0' }; static int wait_poll_fallback; @@ -438,6 +442,15 @@ int lttng_get_notify_socket(void *owner) return info->notify_socket; } + +LTTNG_HIDDEN +char* lttng_ust_sockinfo_get_procname(void *owner) +{ + struct sock_info *info = owner; + + return info->procname; +} + static void print_cmd(int cmd, int handle) { @@ -467,6 +480,7 @@ int setup_global_apps(void) } global_apps.allowed = 1; + lttng_ust_getprocname(global_apps.procname); error: return ret; } @@ -511,6 +525,8 @@ int setup_local_apps(void) ret = -EIO; goto end; } + + lttng_ust_getprocname(local_apps.procname); end: return ret; } diff --git a/liblttng-ust/lttng-ust-statedump-provider.h b/liblttng-ust/lttng-ust-statedump-provider.h index b6a6f7e5..b0c43cf7 100644 --- a/liblttng-ust/lttng-ust-statedump-provider.h +++ b/liblttng-ust/lttng-ust-statedump-provider.h @@ -34,6 +34,7 @@ extern "C" { #include #include #include +#include "compat.h" #define LTTNG_UST_STATEDUMP_PROVIDER #include @@ -91,6 +92,16 @@ TRACEPOINT_EVENT(lttng_ust_statedump, debug_link, ) ) +TRACEPOINT_EVENT(lttng_ust_statedump, procname, + TP_ARGS( + struct lttng_session *, session, + char *, name + ), + TP_FIELDS( + ctf_array_text(char, procname, name, LTTNG_UST_PROCNAME_LEN) + ) +) + TRACEPOINT_EVENT(lttng_ust_statedump, end, TP_ARGS(struct lttng_session *, session), TP_FIELDS() diff --git a/liblttng-ust/lttng-ust-statedump.c b/liblttng-ust/lttng-ust-statedump.c index f40b7195..040223d5 100644 --- a/liblttng-ust/lttng-ust-statedump.c +++ b/liblttng-ust/lttng-ust-statedump.c @@ -35,6 +35,7 @@ #include "lttng-ust-statedump.h" #include "jhash.h" #include "getenv.h" +#include "compat.h" #define TRACEPOINT_DEFINE #include "ust_lib.h" /* Only define. */ @@ -246,6 +247,13 @@ void trace_debug_link_cb(struct lttng_session *session, void *priv) bin_data->dbg_file, bin_data->crc); } +static +void procname_cb(struct lttng_session *session, void *priv) +{ + char *procname = (char *) priv; + tracepoint(lttng_ust_statedump, procname, session, procname); +} + static void trace_start_cb(struct lttng_session *session, void *priv) { @@ -593,6 +601,16 @@ int do_baddr_statedump(void *owner) return 0; } +static +int do_procname_statedump(void *owner) +{ + if (lttng_getenv("LTTNG_UST_WITHOUT_PROCNAME_STATEDUMP")) + return 0; + + trace_statedump_event(procname_cb, owner, lttng_ust_sockinfo_get_procname(owner)); + return 0; +} + /* * Generate a statedump of a given traced application. A statedump is * delimited by start and end events. For a given (process, session) @@ -611,6 +629,7 @@ int do_lttng_ust_statedump(void *owner) trace_statedump_start(owner); ust_unlock(); + do_procname_statedump(owner); do_baddr_statedump(owner); ust_lock_nocheck(); -- 2.34.1 From e8e8357cb5f6d006c60418a047fd17295cde0b3d Mon Sep 17 00:00:00 2001 From: Michael Jeanson Date: Thu, 7 Nov 2019 13:48:52 -0500 Subject: [PATCH 11/16] Require automake >= 1.12 The test suite LOG_DRIVER statement requires that automake >= 1.12 be used during bootstrap. Signed-off-by: Michael Jeanson Signed-off-by: Mathieu Desnoyers --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 319cb401..001c4428 100644 --- a/configure.ac +++ b/configure.ac @@ -41,7 +41,7 @@ AC_CONFIG_SRCDIR([include/lttng/tracepoint.h]) AC_CANONICAL_TARGET AC_CANONICAL_HOST -AM_INIT_AUTOMAKE([1.9 foreign dist-bzip2 no-dist-gzip tar-ustar]) +AM_INIT_AUTOMAKE([1.12 foreign dist-bzip2 no-dist-gzip tar-ustar]) AM_MAINTAINER_MODE([enable]) # Enable silent rules if available (Introduced in AM 1.11) -- 2.34.1 From 8aeb3cae3d7a1c2cf0fb24d8d83c94e32d5622dd Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Mon, 18 Nov 2019 12:07:50 -0500 Subject: [PATCH 12/16] doc: pass AR when building examples As reported here [1], when cross-compiling lttng-ust, the "hello-static-lib" example uses the ar tool made for the --build machine instead of the prefixed one, for the --host machine. The Makefiles in the subdirectories of doc/examples are written by hand, so that they can be easily copied and modified by users. They are therefore not integrated in the automake build system, and any value detected by configure must be passed explicitly when invoking it. For example, the CC value is already explicitly passed, so that the compiler value found by configure is passed down. We just need to do the same for AR. This patch adds AM_PROG_AR in configure.ac, so that configure finds the prefixed version of ar, if cross-compiling. It then sets the AR variable in doc/examples/Makefile.am, when invoking sub-Makefiles. I don't think we really need it in the cmake case, but it doesn't hurt to have it there. [1] https://lists.lttng.org/pipermail/lttng-dev/2019-November/029388.html Reported-by: Rolf Eike Beer Signed-off-by: Simon Marchi Signed-off-by: Mathieu Desnoyers --- configure.ac | 1 + doc/examples/Makefile.am | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 001c4428..e07888c0 100644 --- a/configure.ac +++ b/configure.ac @@ -66,6 +66,7 @@ AS_IF([test "x${ax_cv_sys_weak_alias}" = "xno"], [ ]) # Checks for programs. +AM_PROG_AR AC_PROG_SED AC_PROG_GREP AC_PROG_LN_S diff --git a/doc/examples/Makefile.am b/doc/examples/Makefile.am index d5d00b09..2f9811ea 100644 --- a/doc/examples/Makefile.am +++ b/doc/examples/Makefile.am @@ -123,7 +123,7 @@ all-local: rel_build_subdir="../"; \ fi; \ for subdir in $(SUBDIRS_PROXY); do \ - (cd $$subdir && $(MAKE) CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" AM_CPPFLAGS="$(AM_CPPFLAGS) -I$$rel_src_subdir$(top_srcdir)/include/ -I$$rel_build_subdir$(top_builddir)/include/" CFLAGS='$(CFLAGS)' AM_CFLAGS='$(AM_CFLAGS)' LDFLAGS="$(LDFLAGS)" AM_LDFLAGS='$(AM_LDFLAGS) -L../../../liblttng-ust/.libs -Wl,-rpath="$(PWD)/../../liblttng-ust/.libs/" -Wl,-rpath-link="$(PWD)/../../liblttng-ust/.libs/"' LTTNG_GEN_TP_PATH="../../../tools/" AM_V_P="$(AM_V_P)" AM_V_at="$(AM_V_at)" $(AM_MAKEFLAGS) all && cd ..) || exit 1; \ + (cd $$subdir && $(MAKE) AR="$(AR)" CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" AM_CPPFLAGS="$(AM_CPPFLAGS) -I$$rel_src_subdir$(top_srcdir)/include/ -I$$rel_build_subdir$(top_builddir)/include/" CFLAGS='$(CFLAGS)' AM_CFLAGS='$(AM_CFLAGS)' LDFLAGS="$(LDFLAGS)" AM_LDFLAGS='$(AM_LDFLAGS) -L../../../liblttng-ust/.libs -Wl,-rpath="$(PWD)/../../liblttng-ust/.libs/" -Wl,-rpath-link="$(PWD)/../../liblttng-ust/.libs/"' LTTNG_GEN_TP_PATH="../../../tools/" AM_V_P="$(AM_V_P)" AM_V_at="$(AM_V_at)" $(AM_MAKEFLAGS) all && cd ..) || exit 1; \ done; \ if [ x"$(SUBDIRS_JUL)" != x"" ]; then \ for subdir in $(SUBDIRS_JUL); do \ @@ -141,6 +141,7 @@ all-local: cd $$subdir && \ $(MKDIR_P) build && \ cd build && \ + AR="$(AR)" \ CC="$(CC)" \ CXX="$(CXX)" \ cmake \ -- 2.34.1 From 54435b75df4c16be1ae0e1c86d5ee1f894b97e73 Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Mon, 18 Nov 2019 12:07:51 -0500 Subject: [PATCH 13/16] doc: reformat long lines in doc/examples/Makefile.am Format the long lines in the all-local target a bit like the "cmake" target is formatted already. I think it helps readability to have one argument per line instead of very long lines. At the same time, I removed the "cd .." at the end of parentheses. The parentheses start a new subshell, so it's unnecessary to do "cd .." before the subshell exits. Signed-off-by: Simon Marchi Signed-off-by: Mathieu Desnoyers --- doc/examples/Makefile.am | 56 ++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/doc/examples/Makefile.am b/doc/examples/Makefile.am index 2f9811ea..dc374896 100644 --- a/doc/examples/Makefile.am +++ b/doc/examples/Makefile.am @@ -123,16 +123,45 @@ all-local: rel_build_subdir="../"; \ fi; \ for subdir in $(SUBDIRS_PROXY); do \ - (cd $$subdir && $(MAKE) AR="$(AR)" CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" AM_CPPFLAGS="$(AM_CPPFLAGS) -I$$rel_src_subdir$(top_srcdir)/include/ -I$$rel_build_subdir$(top_builddir)/include/" CFLAGS='$(CFLAGS)' AM_CFLAGS='$(AM_CFLAGS)' LDFLAGS="$(LDFLAGS)" AM_LDFLAGS='$(AM_LDFLAGS) -L../../../liblttng-ust/.libs -Wl,-rpath="$(PWD)/../../liblttng-ust/.libs/" -Wl,-rpath-link="$(PWD)/../../liblttng-ust/.libs/"' LTTNG_GEN_TP_PATH="../../../tools/" AM_V_P="$(AM_V_P)" AM_V_at="$(AM_V_at)" $(AM_MAKEFLAGS) all && cd ..) || exit 1; \ + ( \ + cd $$subdir && \ + $(MAKE) all \ + AR="$(AR)" \ + CC="$(CC)" \ + CPPFLAGS="$(CPPFLAGS)" \ + AM_CPPFLAGS="$(AM_CPPFLAGS) \ + -I$$rel_src_subdir$(top_srcdir)/include/ \ + -I$$rel_build_subdir$(top_builddir)/include/" \ + CFLAGS='$(CFLAGS)' \ + AM_CFLAGS='$(AM_CFLAGS)' \ + LDFLAGS="$(LDFLAGS)" \ + AM_LDFLAGS='$(AM_LDFLAGS) -L../../../liblttng-ust/.libs -Wl,-rpath="$(PWD)/../../liblttng-ust/.libs/" -Wl,-rpath-link="$(PWD)/../../liblttng-ust/.libs/"' \ + LTTNG_GEN_TP_PATH="../../../tools/" \ + AM_V_P="$(AM_V_P)" \ + AM_V_at="$(AM_V_at)" \ + $(AM_MAKEFLAGS) \ + ) || exit 1; \ done; \ if [ x"$(SUBDIRS_JUL)" != x"" ]; then \ for subdir in $(SUBDIRS_JUL); do \ - (cd $$subdir && $(MAKE) JAVA_CLASSPATH_OVERRIDE_JUL="../../../liblttng-ust-java-agent/java/lttng-ust-agent-jul" JAVA_CLASSPATH_OVERRIDE_COMMON="../../../liblttng-ust-java-agent/java/lttng-ust-agent-common" $(AM_MAKEFLAGS) all && cd ..) || exit 1; \ + ( \ + cd $$subdir && \ + $(MAKE) all \ + JAVA_CLASSPATH_OVERRIDE_JUL="../../../liblttng-ust-java-agent/java/lttng-ust-agent-jul" \ + JAVA_CLASSPATH_OVERRIDE_COMMON="../../../liblttng-ust-java-agent/java/lttng-ust-agent-common" \ + $(AM_MAKEFLAGS) \ + ) || exit 1; \ done; \ fi; \ if [ x"$(SUBDIRS_LOG4J)" != x"" ]; then \ for subdir in $(SUBDIRS_LOG4J); do \ - (cd $$subdir && $(MAKE) JAVA_CLASSPATH_OVERRIDE_LOG4J="../../../liblttng-ust-java-agent/java/lttng-ust-agent-log4j" JAVA_CLASSPATH_OVERRIDE_COMMON="../../../liblttng-ust-java-agent/java/lttng-ust-agent-common" $(AM_MAKEFLAGS) all && cd ..) || exit 1; \ + ( \ + cd $$subdir && \ + $(MAKE) all \ + JAVA_CLASSPATH_OVERRIDE_LOG4J="../../../liblttng-ust-java-agent/java/lttng-ust-agent-log4j" \ + JAVA_CLASSPATH_OVERRIDE_COMMON="../../../liblttng-ust-java-agent/java/lttng-ust-agent-common" \ + $(AM_MAKEFLAGS) \ + ) || exit 1; \ done; \ fi; \ if [ x"$(SUBDIRS_CMAKE)" != x"" ]; then \ @@ -142,17 +171,16 @@ all-local: $(MKDIR_P) build && \ cd build && \ AR="$(AR)" \ - CC="$(CC)" \ - CXX="$(CXX)" \ - cmake \ - -DCMAKE_INCLUDE_PATH="$(abs_top_srcdir)/include;$(abs_top_builddir)/include" \ - -DCMAKE_LIBRARY_PATH="$(abs_top_builddir)/liblttng-ust/.libs" \ - -DCMAKE_C_FLAGS="$(AM_CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) $(CFLAGS)" \ - -DCMAKE_CXX_FLAGS="$(AM_CXXFLAGS) $(AM_CPPFLAGS) $(CXXFLAGS) $(CPPFLAGS)" \ - -DCMAKE_EXE_LINKER_FLAGS="$(AM_LDFLAGS) $(LDFLAGS)" \ - .. && \ - $(MAKE) && \ - cd .. \ + CC="$(CC)" \ + CXX="$(CXX)" \ + cmake \ + -DCMAKE_INCLUDE_PATH="$(abs_top_srcdir)/include;$(abs_top_builddir)/include" \ + -DCMAKE_LIBRARY_PATH="$(abs_top_builddir)/liblttng-ust/.libs" \ + -DCMAKE_C_FLAGS="$(AM_CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) $(CFLAGS)" \ + -DCMAKE_CXX_FLAGS="$(AM_CXXFLAGS) $(AM_CPPFLAGS) $(CXXFLAGS) $(CPPFLAGS)" \ + -DCMAKE_EXE_LINKER_FLAGS="$(AM_LDFLAGS) $(LDFLAGS)" \ + .. && \ + $(MAKE) \ ) || exit 1; \ done; \ fi; -- 2.34.1 From b6b4fee0e53907592ae360b975adfd5013bfc8e5 Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Mon, 18 Nov 2019 13:44:14 -0500 Subject: [PATCH 14/16] doc: fix build failure due to wrong whitespace character MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The previous, commit: 54435b75df4c ("doc: reformat long lines in doc/examples/Makefile.am") introduced the following build failure, when the support for JUL is enabled: make[1]: Entering directory '/home/smarchi/build/lttng-ust/doc/examples/java-jul' javac -classpath "../../../liblttng-ust-java-agent/java/lttng-ust-agent-jul/lttng-ust-agent-jul.jar:../../../liblttng-ust-java-agent/java/lttng-ust-agent-common/lttng-ust-agent-common.jar:." -g Hello.java javac -classpath "../../../liblttng-ust-java-agent/java/lttng-ust-agent-jul/lttng-ust-agent-jul.jar:../../../liblttng-ust-java-agent/java/lttng-ust-agent-common/lttng-ust-agent-common.jar:." -g FilterChangeListenerExample.java javac -classpath "../../../liblttng-ust-java-agent/java/lttng-ust-agent-jul/lttng-ust-agent-jul.jar:../../../liblttng-ust-java-agent/java/lttng-ust-agent-common/lttng-ust-agent-common.jar:." -g ApplicationContextExample.java make[1]: *** No rule to make target ' '. Stop. make[1]: Leaving directory '/home/smarchi/build/lttng-ust/doc/examples/java-jul' Makefile:979: recipe for target 'all-local' failed make: *** [all-local] Error 1 I inadvertently inserted a character that looks like a space, but that is not a space. make tries to interpret it as a target name, which obviously fails. Replace it with a proper space. Signed-off-by: Simon Marchi Signed-off-by: Mathieu Desnoyers --- doc/examples/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/examples/Makefile.am b/doc/examples/Makefile.am index dc374896..2ba8cd89 100644 --- a/doc/examples/Makefile.am +++ b/doc/examples/Makefile.am @@ -149,7 +149,7 @@ all-local: $(MAKE) all \ JAVA_CLASSPATH_OVERRIDE_JUL="../../../liblttng-ust-java-agent/java/lttng-ust-agent-jul" \ JAVA_CLASSPATH_OVERRIDE_COMMON="../../../liblttng-ust-java-agent/java/lttng-ust-agent-common" \ - $(AM_MAKEFLAGS) \ + $(AM_MAKEFLAGS) \ ) || exit 1; \ done; \ fi; \ -- 2.34.1 From 4c742ffda878607edf081a8d19effac5dcd983cd Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Wed, 23 Oct 2019 12:57:47 -0400 Subject: [PATCH 15/16] lttng-clear: stop tracing required Require that tracing is stopped when buffers are cleared. Update comments and warning checks to that effect. Signed-off-by: Mathieu Desnoyers --- libringbuffer/frontend_internal.h | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/libringbuffer/frontend_internal.h b/libringbuffer/frontend_internal.h index 1a9c2d4b..7233ed6d 100644 --- a/libringbuffer/frontend_internal.h +++ b/libringbuffer/frontend_internal.h @@ -205,6 +205,15 @@ void lib_ring_buffer_reserve_push_reader(struct lttng_ust_lib_ring_buffer *buf, consumed_new) != consumed_old)); } +/* + * Move consumed position to the beginning of subbuffer in which the + * write offset is. Should only be used on ring buffers that are not + * actively being written into, because clear_reader does not take into + * account the commit counters when moving the consumed position, which + * can make concurrent trace producers or consumers observe consumed + * position further than the write offset, which breaks ring buffer + * algorithm guarantees. + */ static inline void lib_ring_buffer_clear_reader(struct lttng_ust_lib_ring_buffer *buf, struct lttng_ust_shm_handle *handle) @@ -221,12 +230,10 @@ void lib_ring_buffer_clear_reader(struct lttng_ust_lib_ring_buffer *buf, do { offset = v_read(config, &buf->offset); consumed_old = uatomic_read(&buf->consumed); - if (caa_unlikely(subbuf_trunc(offset, chan) - - subbuf_trunc(consumed_old, chan) - > 0)) - consumed_new = subbuf_trunc(offset, chan); - else - return; + CHAN_WARN_ON(chan, (long) (subbuf_trunc(offset, chan) + - subbuf_trunc(consumed_old, chan)) + < 0); + consumed_new = subbuf_trunc(offset, chan); } while (caa_unlikely(uatomic_cmpxchg(&buf->consumed, consumed_old, consumed_new) != consumed_old)); } -- 2.34.1 From 677423ebf26cc17916bddd0334b1a9f7614035c9 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Fri, 20 Dec 2019 10:49:20 -0500 Subject: [PATCH 16/16] Bump LTTNG_UST_ABI_MINOR_VERSION to 1 Increment the minor version of lttng-ust ABI to 1, to take into account that the "clear" command was added in this release cycle. This will allow future LTTng-tools versions to check for this capability. Signed-off-by: Mathieu Desnoyers --- include/lttng/ust-abi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/lttng/ust-abi.h b/include/lttng/ust-abi.h index 5c934daf..461e77c2 100644 --- a/include/lttng/ust-abi.h +++ b/include/lttng/ust-abi.h @@ -47,7 +47,7 @@ /* Version for ABI between liblttng-ust, sessiond, consumerd */ #define LTTNG_UST_ABI_MAJOR_VERSION 8 -#define LTTNG_UST_ABI_MINOR_VERSION 0 +#define LTTNG_UST_ABI_MINOR_VERSION 1 enum lttng_ust_instrumentation { LTTNG_UST_TRACEPOINT = 0, -- 2.34.1