* [PATCH v2 0/2] virtiofsd: stay under fs.file-max sysctl limit (CVE-2020-10717)
@ 2020-05-01 14:06 Stefan Hajnoczi
2020-05-01 14:06 ` [PATCH v2 1/2] virtiofsd: add --rlimit-nofile=NUM option Stefan Hajnoczi
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Stefan Hajnoczi @ 2020-05-01 14:06 UTC (permalink / raw)
To: qemu-devel
Cc: virtio-fs, Stefan Hajnoczi, Dr. David Alan Gilbert, vgoyal, pjp
This patch series introduces the --rlimit-nofile=NUM option for setting the
number of open files on the virtiofsd process. This gives users and management
tools more control over resource limits.
Previously it was possible for FUSE clients on machines with less than ~10 GB
of RAM to exhaust the system-wide open file limit. This is a denial of service
attack against other processes running on the host.
This patch series updates the default RLIMIT_NOFILE calculation to take the
fs.file-max sysctl value into account. This solves the fs.file-max DoS.
Stefan Hajnoczi (2):
virtiofsd: add --rlimit-nofile=NUM option
virtiofsd: stay below fs.file-max sysctl value (CVE-2020-10717)
tools/virtiofsd/fuse_lowlevel.h | 1 +
tools/virtiofsd/helper.c | 47 ++++++++++++++++++++++++++++++++
tools/virtiofsd/passthrough_ll.c | 22 ++++++---------
3 files changed, 56 insertions(+), 14 deletions(-)
--
2.25.3
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 1/2] virtiofsd: add --rlimit-nofile=NUM option
2020-05-01 14:06 [PATCH v2 0/2] virtiofsd: stay under fs.file-max sysctl limit (CVE-2020-10717) Stefan Hajnoczi
@ 2020-05-01 14:06 ` Stefan Hajnoczi
2020-05-01 14:06 ` [PATCH v2 2/2] virtiofsd: stay below fs.file-max sysctl value (CVE-2020-10717) Stefan Hajnoczi
2020-05-01 17:42 ` [PATCH v2 0/2] virtiofsd: stay under fs.file-max sysctl limit (CVE-2020-10717) Dr. David Alan Gilbert
2 siblings, 0 replies; 4+ messages in thread
From: Stefan Hajnoczi @ 2020-05-01 14:06 UTC (permalink / raw)
To: qemu-devel
Cc: virtio-fs, Stefan Hajnoczi, Dr. David Alan Gilbert, vgoyal, pjp
Make it possible to specify the RLIMIT_NOFILE on the command-line.
Users running multiple virtiofsd processes should allocate a certain
number to each process so that the system-wide limit can never be
exhausted.
When this option is set to 0 the rlimit is left at its current value.
This is useful when a management tool wants to configure the rlimit
itself.
The default behavior remains unchanged: try to set the limit to
1,000,000 file descriptors if the current rlimit is lower.
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
tools/virtiofsd/fuse_lowlevel.h | 1 +
tools/virtiofsd/helper.c | 23 +++++++++++++++++++++++
tools/virtiofsd/passthrough_ll.c | 22 ++++++++--------------
3 files changed, 32 insertions(+), 14 deletions(-)
diff --git a/tools/virtiofsd/fuse_lowlevel.h b/tools/virtiofsd/fuse_lowlevel.h
index 8f6d705b5c..562fd5241e 100644
--- a/tools/virtiofsd/fuse_lowlevel.h
+++ b/tools/virtiofsd/fuse_lowlevel.h
@@ -1777,6 +1777,7 @@ struct fuse_cmdline_opts {
int syslog;
int log_level;
unsigned int max_idle_threads;
+ unsigned long rlimit_nofile;
};
/**
diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
index 819c2bc13c..dc59f38af0 100644
--- a/tools/virtiofsd/helper.c
+++ b/tools/virtiofsd/helper.c
@@ -23,6 +23,8 @@
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
#include <unistd.h>
#define FUSE_HELPER_OPT(t, p) \
@@ -53,6 +55,7 @@ static const struct fuse_opt fuse_helper_opts[] = {
FUSE_HELPER_OPT("subtype=", nodefault_subtype),
FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP),
FUSE_HELPER_OPT("max_idle_threads=%u", max_idle_threads),
+ FUSE_HELPER_OPT("--rlimit-nofile=%lu", rlimit_nofile),
FUSE_HELPER_OPT("--syslog", syslog),
FUSE_HELPER_OPT_VALUE("log_level=debug", log_level, FUSE_LOG_DEBUG),
FUSE_HELPER_OPT_VALUE("log_level=info", log_level, FUSE_LOG_INFO),
@@ -171,6 +174,9 @@ void fuse_cmdline_help(void)
" default: no_writeback\n"
" -o xattr|no_xattr enable/disable xattr\n"
" default: no_xattr\n"
+ " --rlimit-nofile=<num> set maximum number of file descriptors\n"
+ " (0 leaves rlimit unchanged)\n"
+ " default: 1,000,000 if the current rlimit is lower\n"
);
}
@@ -191,11 +197,28 @@ static int fuse_helper_opt_proc(void *data, const char *arg, int key,
}
}
+static unsigned long get_default_rlimit_nofile(void)
+{
+ rlim_t max_fds = 1000000; /* our default RLIMIT_NOFILE target */
+ struct rlimit rlim;
+
+ if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
+ fuse_log(FUSE_LOG_ERR, "getrlimit(RLIMIT_NOFILE): %m\n");
+ exit(1);
+ }
+
+ if (rlim.rlim_cur >= max_fds) {
+ return 0; /* we have more fds available than required! */
+ }
+ return max_fds;
+}
+
int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts)
{
memset(opts, 0, sizeof(struct fuse_cmdline_opts));
opts->max_idle_threads = 10;
+ opts->rlimit_nofile = get_default_rlimit_nofile();
opts->foreground = 1;
if (fuse_opt_parse(args, opts, fuse_helper_opts, fuse_helper_opt_proc) ==
diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
index 4c35c95b25..f7b9c1d20c 100644
--- a/tools/virtiofsd/passthrough_ll.c
+++ b/tools/virtiofsd/passthrough_ll.c
@@ -2707,24 +2707,18 @@ static void setup_sandbox(struct lo_data *lo, struct fuse_session *se,
setup_seccomp(enable_syslog);
}
-/* Raise the maximum number of open file descriptors */
-static void setup_nofile_rlimit(void)
+/* Set the maximum number of open file descriptors */
+static void setup_nofile_rlimit(unsigned long rlimit_nofile)
{
- const rlim_t max_fds = 1000000;
- struct rlimit rlim;
+ struct rlimit rlim = {
+ .rlim_cur = rlimit_nofile,
+ .rlim_max = rlimit_nofile,
+ };
- if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
- fuse_log(FUSE_LOG_ERR, "getrlimit(RLIMIT_NOFILE): %m\n");
- exit(1);
- }
-
- if (rlim.rlim_cur >= max_fds) {
+ if (rlimit_nofile == 0) {
return; /* nothing to do */
}
- rlim.rlim_cur = max_fds;
- rlim.rlim_max = max_fds;
-
if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
/* Ignore SELinux denials */
if (errno == EPERM) {
@@ -2977,7 +2971,7 @@ int main(int argc, char *argv[])
fuse_daemonize(opts.foreground);
- setup_nofile_rlimit();
+ setup_nofile_rlimit(opts.rlimit_nofile);
/* Must be before sandbox since it wants /proc */
setup_capng();
--
2.25.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 2/2] virtiofsd: stay below fs.file-max sysctl value (CVE-2020-10717)
2020-05-01 14:06 [PATCH v2 0/2] virtiofsd: stay under fs.file-max sysctl limit (CVE-2020-10717) Stefan Hajnoczi
2020-05-01 14:06 ` [PATCH v2 1/2] virtiofsd: add --rlimit-nofile=NUM option Stefan Hajnoczi
@ 2020-05-01 14:06 ` Stefan Hajnoczi
2020-05-01 17:42 ` [PATCH v2 0/2] virtiofsd: stay under fs.file-max sysctl limit (CVE-2020-10717) Dr. David Alan Gilbert
2 siblings, 0 replies; 4+ messages in thread
From: Stefan Hajnoczi @ 2020-05-01 14:06 UTC (permalink / raw)
To: qemu-devel
Cc: Dr. David Alan Gilbert, virtio-fs, Stefan Hajnoczi,
Yuval Avrahami, pjp, vgoyal
The system-wide fs.file-max sysctl value determines how many files can
be open. It defaults to a value calculated based on the machine's RAM
size. Previously virtiofsd would try to set RLIMIT_NOFILE to 1,000,000
and this allowed the FUSE client to exhaust the number of open files
system-wide on Linux hosts with less than 10 GB of RAM!
Take fs.file-max into account when choosing the default RLIMIT_NOFILE
value.
Fixes: CVE-2020-10717
Reported-by: Yuval Avrahami <yavrahami@paloaltonetworks.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
tools/virtiofsd/helper.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c
index dc59f38af0..00a1ef666a 100644
--- a/tools/virtiofsd/helper.c
+++ b/tools/virtiofsd/helper.c
@@ -176,7 +176,8 @@ void fuse_cmdline_help(void)
" default: no_xattr\n"
" --rlimit-nofile=<num> set maximum number of file descriptors\n"
" (0 leaves rlimit unchanged)\n"
- " default: 1,000,000 if the current rlimit is lower\n"
+ " default: min(1000000, fs.file-max - 16384)\n"
+ " if the current rlimit is lower\n"
);
}
@@ -199,9 +200,32 @@ static int fuse_helper_opt_proc(void *data, const char *arg, int key,
static unsigned long get_default_rlimit_nofile(void)
{
+ g_autofree gchar *file_max_str = NULL;
+ const rlim_t reserved_fds = 16384; /* leave at least this many fds free */
rlim_t max_fds = 1000000; /* our default RLIMIT_NOFILE target */
+ rlim_t file_max;
struct rlimit rlim;
+ /*
+ * Reduce max_fds below the system-wide maximum, if necessary. This
+ * ensures there are fds available for other processes so we don't
+ * cause resource exhaustion.
+ */
+ if (!g_file_get_contents("/proc/sys/fs/file-max", &file_max_str,
+ NULL, NULL)) {
+ fuse_log(FUSE_LOG_ERR, "can't read /proc/sys/fs/file-max\n");
+ exit(1);
+ }
+ file_max = g_ascii_strtoull(file_max_str, NULL, 10);
+ if (file_max < 2 * reserved_fds) {
+ fuse_log(FUSE_LOG_ERR,
+ "The fs.file-max sysctl is too low (%lu) to allow a "
+ "reasonable number of open files.\n",
+ (unsigned long)file_max);
+ exit(1);
+ }
+ max_fds = MIN(file_max - reserved_fds, max_fds);
+
if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
fuse_log(FUSE_LOG_ERR, "getrlimit(RLIMIT_NOFILE): %m\n");
exit(1);
--
2.25.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v2 0/2] virtiofsd: stay under fs.file-max sysctl limit (CVE-2020-10717)
2020-05-01 14:06 [PATCH v2 0/2] virtiofsd: stay under fs.file-max sysctl limit (CVE-2020-10717) Stefan Hajnoczi
2020-05-01 14:06 ` [PATCH v2 1/2] virtiofsd: add --rlimit-nofile=NUM option Stefan Hajnoczi
2020-05-01 14:06 ` [PATCH v2 2/2] virtiofsd: stay below fs.file-max sysctl value (CVE-2020-10717) Stefan Hajnoczi
@ 2020-05-01 17:42 ` Dr. David Alan Gilbert
2 siblings, 0 replies; 4+ messages in thread
From: Dr. David Alan Gilbert @ 2020-05-01 17:42 UTC (permalink / raw)
To: Stefan Hajnoczi; +Cc: virtio-fs, qemu-devel, vgoyal, pjp
* Stefan Hajnoczi (stefanha@redhat.com) wrote:
> This patch series introduces the --rlimit-nofile=NUM option for setting the
> number of open files on the virtiofsd process. This gives users and management
> tools more control over resource limits.
>
> Previously it was possible for FUSE clients on machines with less than ~10 GB
> of RAM to exhaust the system-wide open file limit. This is a denial of service
> attack against other processes running on the host.
>
> This patch series updates the default RLIMIT_NOFILE calculation to take the
> fs.file-max sysctl value into account. This solves the fs.file-max DoS.
Queued.
> Stefan Hajnoczi (2):
> virtiofsd: add --rlimit-nofile=NUM option
> virtiofsd: stay below fs.file-max sysctl value (CVE-2020-10717)
>
> tools/virtiofsd/fuse_lowlevel.h | 1 +
> tools/virtiofsd/helper.c | 47 ++++++++++++++++++++++++++++++++
> tools/virtiofsd/passthrough_ll.c | 22 ++++++---------
> 3 files changed, 56 insertions(+), 14 deletions(-)
>
> --
> 2.25.3
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2020-05-01 17:43 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-05-01 14:06 [PATCH v2 0/2] virtiofsd: stay under fs.file-max sysctl limit (CVE-2020-10717) Stefan Hajnoczi
2020-05-01 14:06 ` [PATCH v2 1/2] virtiofsd: add --rlimit-nofile=NUM option Stefan Hajnoczi
2020-05-01 14:06 ` [PATCH v2 2/2] virtiofsd: stay below fs.file-max sysctl value (CVE-2020-10717) Stefan Hajnoczi
2020-05-01 17:42 ` [PATCH v2 0/2] virtiofsd: stay under fs.file-max sysctl limit (CVE-2020-10717) Dr. David Alan Gilbert
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).