From 4063050c0e90b27d34ee8de570b049cc076119a4 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 20 Mar 2012 14:53:07 -0400 Subject: [PATCH 1/1] Keep track of FD used for UST applications (v2) Allow to keep 25% of file descriptors reserved for commands/kernel tracing/internal communication within the sessiond by limiting applications to 75% of the available file descriptors. This ensures traced applications cannot cause a sessiond denial of service. Changelog since v1: - Add missing fd-limit.h Signed-off-by: Mathieu Desnoyers --- src/bin/lttng-sessiond/Makefile.am | 3 +- src/bin/lttng-sessiond/fd-limit.c | 70 ++++++++++++++++++++++++++++++ src/bin/lttng-sessiond/fd-limit.h | 30 +++++++++++++ src/bin/lttng-sessiond/main.c | 16 +++++++ src/bin/lttng-sessiond/ust-app.c | 36 +++++++++++++++ 5 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 src/bin/lttng-sessiond/fd-limit.c create mode 100644 src/bin/lttng-sessiond/fd-limit.h diff --git a/src/bin/lttng-sessiond/Makefile.am b/src/bin/lttng-sessiond/Makefile.am index ccdbe3afc..8748dd6bb 100644 --- a/src/bin/lttng-sessiond/Makefile.am +++ b/src/bin/lttng-sessiond/Makefile.am @@ -16,7 +16,8 @@ lttng_sessiond_SOURCES = utils.c utils.h \ shm.c shm.h \ session.c session.h \ modprobe.c modprobe.h kern-modules.h \ - lttng-ust-ctl.h lttng-ust-abi.h + lttng-ust-ctl.h lttng-ust-abi.h \ + fd-limit.c fd-limit.h if HAVE_LIBLTTNG_UST_CTL lttng_sessiond_SOURCES += trace-ust.c ust-app.c ust-consumer.c ust-consumer.h diff --git a/src/bin/lttng-sessiond/fd-limit.c b/src/bin/lttng-sessiond/fd-limit.c new file mode 100644 index 000000000..a886d33b9 --- /dev/null +++ b/src/bin/lttng-sessiond/fd-limit.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2012 - Mathieu Desnoyers + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include "fd-limit.h" + +/* total count of fd. */ +static long fd_count; + +/* + * threshold in % of number of fd allowed. + */ +static long fd_threshold[LTTNG_FD_NR_TYPES] = { + [LTTNG_FD_APPS] = 75, +}; + +static rlim_t max_nr_fd; + +int lttng_fd_get(enum lttng_fd_type type, unsigned int nr) +{ + long newval; + + if (type >= LTTNG_FD_NR_TYPES) { + return -EINVAL; + } + + newval = uatomic_add_return(&fd_count, (long) nr); + if ((long) (newval * 100) + - (long) (max_nr_fd * fd_threshold[type]) > 0) { + uatomic_sub(&fd_count, (long) nr); + return -EPERM; + } + return 0; +} + +void lttng_fd_put(enum lttng_fd_type type, unsigned int nr) +{ + uatomic_sub(&fd_count, (long) nr); +} + +void lttng_fd_init(void) +{ + struct rlimit rlim; + int ret; + + ret = getrlimit(RLIMIT_NOFILE, &rlim); + if (ret < 0) { + perror("getrlimit"); + } + max_nr_fd = rlim.rlim_cur; +} diff --git a/src/bin/lttng-sessiond/fd-limit.h b/src/bin/lttng-sessiond/fd-limit.h new file mode 100644 index 000000000..a3dc1a7ec --- /dev/null +++ b/src/bin/lttng-sessiond/fd-limit.h @@ -0,0 +1,30 @@ +#ifndef _LTTNG_FD_LIMIT_H +#define _LTTNG_FD_LIMIT_H + +/* + * Copyright (C) 2012 - Mathieu Desnoyers + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +enum lttng_fd_type { + LTTNG_FD_APPS, + LTTNG_FD_NR_TYPES, +}; + +int lttng_fd_get(enum lttng_fd_type type, unsigned int nr); +void lttng_fd_put(enum lttng_fd_type type, unsigned int nr); +void lttng_fd_init(void); + +#endif /* _LTTNG_FD_LIMIT_H */ diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index 4d8851ef8..3c917b25f 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -54,6 +54,7 @@ #include "shm.h" #include "ust-ctl.h" #include "utils.h" +#include "fd-limit.h" #define CONSUMERD_FILE "lttng-consumerd" @@ -1424,6 +1425,17 @@ static void *thread_registration_apps(void *data) * Using message-based transmissions to ensure we don't * have to deal with partially received messages. */ + ret = lttng_fd_get(LTTNG_FD_APPS, 1); + if (ret < 0) { + ERR("Exhausted file descriptors allowed for applications."); + free(ust_cmd); + ret = close(sock); + if (ret) { + PERROR("close"); + } + sock = -1; + continue; + } ret = lttcomm_recv_unix_sock(sock, &ust_cmd->reg_msg, sizeof(struct ust_register_msg)); if (ret < 0 || ret < sizeof(struct ust_register_msg)) { @@ -1437,6 +1449,7 @@ static void *thread_registration_apps(void *data) if (ret) { PERROR("close"); } + lttng_fd_put(LTTNG_FD_APPS, 1); sock = -1; continue; } @@ -1482,6 +1495,7 @@ error: if (ret) { PERROR("close"); } + lttng_fd_put(LTTNG_FD_APPS, 1); } unlink(apps_unix_sock_path); @@ -4556,6 +4570,8 @@ int main(int argc, char **argv) /* Set ulimit for open files */ set_ulimit(); } + /* init lttng_fd tracking must be done after set_ulimit. */ + lttng_fd_init(); ret = set_consumer_sockets(&ustconsumer64_data, rundir); if (ret < 0) { diff --git a/src/bin/lttng-sessiond/ust-app.c b/src/bin/lttng-sessiond/ust-app.c index 79526fceb..7dbea5c18 100644 --- a/src/bin/lttng-sessiond/ust-app.c +++ b/src/bin/lttng-sessiond/ust-app.c @@ -31,6 +31,7 @@ #include "ust-app.h" #include "ust-consumer.h" #include "ust-ctl.h" +#include "fd-limit.h" /* * Delete ust context safely. RCU read lock must be held before calling @@ -82,6 +83,7 @@ void delete_ust_app_stream(int sock, struct ltt_ust_stream *stream) { if (stream->obj) { ustctl_release_object(sock, stream->obj); + lttng_fd_put(LTTNG_FD_APPS, 2); free(stream->obj); } free(stream); @@ -125,6 +127,7 @@ void delete_ust_app_channel(int sock, struct ust_app_channel *ua_chan) if (ua_chan->obj != NULL) { ustctl_release_object(sock, ua_chan->obj); + lttng_fd_put(LTTNG_FD_APPS, 2); free(ua_chan->obj); } free(ua_chan); @@ -144,10 +147,12 @@ void delete_ust_app_session(int sock, struct ust_app_session *ua_sess) if (ua_sess->metadata) { if (ua_sess->metadata->stream_obj) { ustctl_release_object(sock, ua_sess->metadata->stream_obj); + lttng_fd_put(LTTNG_FD_APPS, 2); free(ua_sess->metadata->stream_obj); } if (ua_sess->metadata->obj) { ustctl_release_object(sock, ua_sess->metadata->obj); + lttng_fd_put(LTTNG_FD_APPS, 2); free(ua_sess->metadata->obj); } trace_ust_destroy_metadata(ua_sess->metadata); @@ -210,6 +215,7 @@ void delete_ust_app(struct ust_app *app) if (ret) { PERROR("close"); } + lttng_fd_put(LTTNG_FD_APPS, 1); DBG2("UST app pid %d deleted", app->pid); free(app); @@ -536,6 +542,12 @@ static int open_ust_metadata(struct ust_app *app, ua_sess->metadata->attr.read_timer_interval; uattr.output = ua_sess->metadata->attr.output; + /* We are going to receive 2 fds, we need to reserve them. */ + ret = lttng_fd_get(LTTNG_FD_APPS, 2); + if (ret < 0) { + ERR("Exhausted number of available FD upon metadata open"); + goto error; + } /* UST tracer metadata creation */ ret = ustctl_open_metadata(app->sock, ua_sess->handle, &uattr, &ua_sess->metadata->obj); @@ -559,6 +571,12 @@ static int create_ust_stream(struct ust_app *app, { int ret; + /* We are going to receive 2 fds, we need to reserve them. */ + ret = lttng_fd_get(LTTNG_FD_APPS, 2); + if (ret < 0) { + ERR("Exhausted number of available FD upon metadata stream create"); + goto error; + } ret = ustctl_create_stream(app->sock, ua_sess->metadata->obj, &ua_sess->metadata->stream_obj); if (ret < 0) { @@ -579,6 +597,13 @@ static int create_ust_channel(struct ust_app *app, int ret; /* TODO: remove cast and use lttng-ust-abi.h */ + + /* We are going to receive 2 fds, we need to reserve them. */ + ret = lttng_fd_get(LTTNG_FD_APPS, 2); + if (ret < 0) { + ERR("Exhausted number of available FD upon create channel"); + goto error; + } ret = ustctl_create_channel(app->sock, ua_sess->handle, (struct lttng_ust_channel_attr *)&ua_chan->attr, &ua_chan->obj); if (ret < 0) { @@ -586,6 +611,7 @@ static int create_ust_channel(struct ust_app *app, "and session handle %d with ret %d", ua_chan->name, app->pid, app->sock, ua_sess->handle, ret); + lttng_fd_put(LTTNG_FD_APPS, 2); goto error; } @@ -1281,6 +1307,7 @@ int ust_app_register(struct ust_register_msg *msg, int sock) if (ret) { PERROR("close"); } + lttng_fd_put(LTTNG_FD_APPS, 1); return -EINVAL; } if (msg->major != LTTNG_UST_COMM_MAJOR) { @@ -1291,6 +1318,7 @@ int ust_app_register(struct ust_register_msg *msg, int sock) if (ret) { PERROR("close"); } + lttng_fd_put(LTTNG_FD_APPS, 1); return -EINVAL; } lta = zmalloc(sizeof(struct ust_app)); @@ -1977,10 +2005,18 @@ int ust_app_start_trace(struct ltt_ust_session *usess, struct ust_app *app) goto error_rcu_unlock; } + /* We are going to receive 2 fds, we need to reserve them. */ + ret = lttng_fd_get(LTTNG_FD_APPS, 2); + if (ret < 0) { + ERR("Exhausted number of available FD upon stream create"); + free(ustream); + goto error_rcu_unlock; + } ret = ustctl_create_stream(app->sock, ua_chan->obj, &ustream->obj); if (ret < 0) { /* Got all streams */ + lttng_fd_put(LTTNG_FD_APPS, 2); free(ustream); break; } -- 2.34.1