[lttng-dev] [lttng-tools PATCH] Keep track of FD used for UST applications

Mathieu Desnoyers mathieu.desnoyers at efficios.com
Mon Mar 19 22:55:32 EDT 2012


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.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers at efficios.com>
---
diff --git a/src/bin/lttng-sessiond/Makefile.am b/src/bin/lttng-sessiond/Makefile.am
index ccdbe3a..8748dd6 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 0000000..a886d33
--- /dev/null
+++ b/src/bin/lttng-sessiond/fd-limit.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2012 - Mathieu Desnoyers <mathieu.desnoyers at efficios.com>
+ *
+ * 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 <urcu/uatomic.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <errno.h>
+#include <stdio.h>
+#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/main.c b/src/bin/lttng-sessiond/main.c
index 0c4d4b1..e94d38b 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);
 
@@ -4544,6 +4558,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 79526fc..7dbea5c 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;
 			}
-- 
Mathieu Desnoyers
Operating System Efficiency R&D Consultant
EfficiOS Inc.
http://www.efficios.com



More information about the lttng-dev mailing list