Keep track of FD used for UST applications (v2)
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Tue, 20 Mar 2012 18:53:07 +0000 (14:53 -0400)
committerDavid Goulet <dgoulet@ev0ke.net>
Tue, 20 Mar 2012 18:53:35 +0000 (14:53 -0400)
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 <mathieu.desnoyers@efficios.com>
src/bin/lttng-sessiond/Makefile.am
src/bin/lttng-sessiond/fd-limit.c [new file with mode: 0644]
src/bin/lttng-sessiond/fd-limit.h [new file with mode: 0644]
src/bin/lttng-sessiond/main.c
src/bin/lttng-sessiond/ust-app.c

index ccdbe3afc49485af896cad9c5e61918a997ce4d3..8748dd6bb915d6f8420872500c87661b9500f316 100644 (file)
@@ -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 (file)
index 0000000..a886d33
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2012 - Mathieu Desnoyers <mathieu.desnoyers@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/fd-limit.h b/src/bin/lttng-sessiond/fd-limit.h
new file mode 100644 (file)
index 0000000..a3dc1a7
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef _LTTNG_FD_LIMIT_H
+#define _LTTNG_FD_LIMIT_H
+
+/*
+ * Copyright (C) 2012 - Mathieu Desnoyers <mathieu.desnoyers@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.
+ */
+
+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 */
index 4d8851ef813168a8445ad77ef12c1fdc838101d9..3c917b25f51c87f484a33096873f441c0c2da92b 100644 (file)
@@ -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) {
index 79526fceb61f5d712174baaad97562d6cdae889e..7dbea5c182ca4c6e1a54a89c74a3f0f2c737fe23 100644 (file)
@@ -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;
                        }
This page took 0.03004 seconds and 4 git commands to generate.