Browse Source

Merge pull request #504 from trapexit/disable_security.capabilities

add security_capability option
pull/505/head
trapexit 6 years ago
committed by GitHub
parent
commit
ff04098319
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      README.md
  2. 16
      man/mergerfs.1
  3. 1
      src/config.cpp
  4. 1
      src/config.hpp
  5. 17
      src/getxattr.cpp
  6. 1
      src/listxattr.cpp
  7. 5
      src/option_parser.cpp
  8. 4
      src/setxattr.cpp

7
README.md

@ -1,6 +1,6 @@
% mergerfs(1) mergerfs user manual % mergerfs(1) mergerfs user manual
% Antonio SJ Musumeci <trapexit@spawn.link> % Antonio SJ Musumeci <trapexit@spawn.link>
% 2018-08-20
% 2018-09-30
# NAME # NAME
@ -71,6 +71,7 @@ mergerfs does **not** support the copy-on-write (CoW) behavior found in **aufs**
* **symlinkify_timeout=value**: time to wait, in seconds, to activate the **symlinkify** behavior. (default: 3600) * **symlinkify_timeout=value**: time to wait, in seconds, to activate the **symlinkify** behavior. (default: 3600)
* **nullrw=true|false**: turns reads and writes into no-ops. The request will succeed but do nothing. Useful for benchmarking mergerfs. (default: false) * **nullrw=true|false**: turns reads and writes into no-ops. The request will succeed but do nothing. Useful for benchmarking mergerfs. (default: false)
* **ignorepponrename=true|false**: ignore path preserving on rename. Typically rename and link act differently depending on the policy of `create` (read below). Enabling this will cause rename and link to always use the non-path preserving behavior. This means files, when renamed or linked, will stay on the same drive. (default: false) * **ignorepponrename=true|false**: ignore path preserving on rename. Typically rename and link act differently depending on the policy of `create` (read below). Enabling this will cause rename and link to always use the non-path preserving behavior. This means files, when renamed or linked, will stay on the same drive. (default: false)
* **security_capability=true|false**: If false return ENOATTR when xattr security.capability is queried. (default: true)
* **threads=num**: number of threads to use in multithreaded mode. When set to zero (the default) it will attempt to discover and use the number of logical cores. If the lookup fails it will fall back to using 4. If the thread count is set negative it will look up the number of cores then divide by the absolute value. ie. threads=-2 on an 8 core machine will result in 8 / 2 = 4 threads. There will always be at least 1 thread. NOTE: higher number of threads increases parallelism but usually decreases throughput. (default: number of cores) *NOTE2:* the option is unavailable when built with system libfuse. * **threads=num**: number of threads to use in multithreaded mode. When set to zero (the default) it will attempt to discover and use the number of logical cores. If the lookup fails it will fall back to using 4. If the thread count is set negative it will look up the number of cores then divide by the absolute value. ie. threads=-2 on an 8 core machine will result in 8 / 2 = 4 threads. There will always be at least 1 thread. NOTE: higher number of threads increases parallelism but usually decreases throughput. (default: number of cores) *NOTE2:* the option is unavailable when built with system libfuse.
* **fsname=name**: sets the name of the filesystem as seen in **mount**, **df**, etc. Defaults to a list of the source paths concatenated together with the longest common prefix removed. * **fsname=name**: sets the name of the filesystem as seen in **mount**, **df**, etc. Defaults to a list of the source paths concatenated together with the longest common prefix removed.
* **func.&lt;func&gt;=&lt;policy&gt;**: sets the specific FUSE function's policy. See below for the list of value types. Example: **func.getattr=newest** * **func.&lt;func&gt;=&lt;policy&gt;**: sets the specific FUSE function's policy. See below for the list of value types. Example: **func.getattr=newest**
@ -736,6 +737,10 @@ Note that this does *not* affect the inode that libfuse
and the kernel use internally (also called the "nodeid"). and the kernel use internally (also called the "nodeid").
``` ```
#### I notice massive slowdowns of writes over NFS
Due to how NFS works and interacts with FUSE when not using `direct_io` its possible that a getxattr for `security.capability` will be issued prior to any write. This will usually result in a massive slowdown for writes. Using `direct_io` will keep this from happening (and generally good to enable unless you need the features it disables) but the `security_capability` option can also help by short circuiting the call and returning `ENOATTR`.
#### It's mentioned that there are some security issues with mhddfs. What are they? How does mergerfs address them? #### It's mentioned that there are some security issues with mhddfs. What are they? How does mergerfs address them?
[mhddfs](https://github.com/trapexit/mhddfs) manages running as **root** by calling [getuid()](https://github.com/trapexit/mhddfs/blob/cae96e6251dd91e2bdc24800b4a18a74044f6672/src/main.c#L319) and if it returns **0** then it will [chown](http://linux.die.net/man/1/chown) the file. Not only is that a race condition but it doesn't handle many other situations. Rather than attempting to simulate POSIX ACL behavior the proper way to manage this is to use [seteuid](http://linux.die.net/man/2/seteuid) and [setegid](http://linux.die.net/man/2/setegid), in effect becoming the user making the original call, and perform the action as them. This is what mergerfs does. [mhddfs](https://github.com/trapexit/mhddfs) manages running as **root** by calling [getuid()](https://github.com/trapexit/mhddfs/blob/cae96e6251dd91e2bdc24800b4a18a74044f6672/src/main.c#L319) and if it returns **0** then it will [chown](http://linux.die.net/man/1/chown) the file. Not only is that a race condition but it doesn't handle many other situations. Rather than attempting to simulate POSIX ACL behavior the proper way to manage this is to use [seteuid](http://linux.die.net/man/2/seteuid) and [setegid](http://linux.die.net/man/2/setegid), in effect becoming the user making the original call, and perform the action as them. This is what mergerfs does.

16
man/mergerfs.1

@ -1,7 +1,7 @@
.\"t .\"t
.\" Automatically generated by Pandoc 1.19.2.4 .\" Automatically generated by Pandoc 1.19.2.4
.\" .\"
.TH "mergerfs" "1" "2018\-08\-20" "mergerfs user manual" ""
.TH "mergerfs" "1" "2018\-09\-30" "mergerfs user manual" ""
.hy .hy
.SH NAME .SH NAME
.PP .PP
@ -152,6 +152,10 @@ preserving behavior.
This means files, when renamed or linked, will stay on the same drive. This means files, when renamed or linked, will stay on the same drive.
(default: false) (default: false)
.IP \[bu] 2 .IP \[bu] 2
\f[B]security_capability=true|false\f[]: If false return ENOATTR when
xattr security.capability is queried.
(default: true)
.IP \[bu] 2
\f[B]threads=num\f[]: number of threads to use in multithreaded mode. \f[B]threads=num\f[]: number of threads to use in multithreaded mode.
When set to zero (the default) it will attempt to discover and use the When set to zero (the default) it will attempt to discover and use the
number of logical cores. number of logical cores.
@ -1536,6 +1540,16 @@ Note\ that\ this\ does\ *not*\ affect\ the\ inode\ that\ libfuse
and\ the\ kernel\ use\ internally\ (also\ called\ the\ "nodeid"). and\ the\ kernel\ use\ internally\ (also\ called\ the\ "nodeid").
\f[] \f[]
.fi .fi
.SS I notice massive slowdowns of writes over NFS
.PP
Due to how NFS works and interacts with FUSE when not using
\f[C]direct_io\f[] its possible that a getxattr for
\f[C]security.capability\f[] will be issued prior to any write.
This will usually result in a massive slowdown for writes.
Using \f[C]direct_io\f[] will keep this from happening (and generally
good to enable unless you need the features it disables) but the
\f[C]security_capability\f[] option can also help by short circuiting
the call and returning \f[C]ENOATTR\f[].
.SS It\[aq]s mentioned that there are some security issues with mhddfs. .SS It\[aq]s mentioned that there are some security issues with mhddfs.
What are they? How does mergerfs address them? What are they? How does mergerfs address them?
.PP .PP

1
src/config.cpp

@ -45,6 +45,7 @@ namespace mergerfs
symlinkify_timeout(3600), symlinkify_timeout(3600),
nullrw(false), nullrw(false),
ignorepponrename(false), ignorepponrename(false),
security_capability(true),
POLICYINIT(access), POLICYINIT(access),
POLICYINIT(chmod), POLICYINIT(chmod),
POLICYINIT(chown), POLICYINIT(chown),

1
src/config.hpp

@ -52,6 +52,7 @@ namespace mergerfs
time_t symlinkify_timeout; time_t symlinkify_timeout;
bool nullrw; bool nullrw;
bool ignorepponrename; bool ignorepponrename;
bool security_capability;
public: public:
const Policy *policies[FuseFunc::Enum::END]; const Policy *policies[FuseFunc::Enum::END];

17
src/getxattr.cpp

@ -1,5 +1,5 @@
/* /*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
Copyright (c) 2018, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted, provided that the above
@ -34,11 +34,20 @@
#include "ugid.hpp" #include "ugid.hpp"
#include "version.hpp" #include "version.hpp"
static const char SECURITY_CAPABILITY[] = "security.capability";
using std::string; using std::string;
using std::vector; using std::vector;
using std::set; using std::set;
using namespace mergerfs; using namespace mergerfs;
static
bool
_is_attrname_security_capability(const char *attrname_)
{
return (strcmp(attrname_,SECURITY_CAPABILITY) == 0);
}
static static
int int
_lgetxattr(const string &path, _lgetxattr(const string &path,
@ -199,6 +208,8 @@ _getxattr_controlfile(const Config &config,
_getxattr_controlfile_bool(config.nullrw,attrvalue); _getxattr_controlfile_bool(config.nullrw,attrvalue);
else if(attr[2] == "ignorepponrename") else if(attr[2] == "ignorepponrename")
_getxattr_controlfile_bool(config.ignorepponrename,attrvalue); _getxattr_controlfile_bool(config.ignorepponrename,attrvalue);
else if(attr[2] == "security_capability")
_getxattr_controlfile_bool(config.security_capability,attrvalue);
else if(attr[2] == "policies") else if(attr[2] == "policies")
_getxattr_controlfile_policies(config,attrvalue); _getxattr_controlfile_policies(config,attrvalue);
else if(attr[2] == "version") else if(attr[2] == "version")
@ -334,6 +345,10 @@ namespace mergerfs
const fuse_context *fc = fuse_get_context(); const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc); const Config &config = Config::get(fc);
if((config.security_capability == false) &&
_is_attrname_security_capability(attrname))
return -ENOATTR;
if(fusepath == config.controlfile) if(fusepath == config.controlfile)
return _getxattr_controlfile(config, return _getxattr_controlfile(config,
attrname, attrname,

1
src/listxattr.cpp

@ -51,6 +51,7 @@ _listxattr_controlfile(char *list,
("user.mergerfs.symlinkify_timeout") ("user.mergerfs.symlinkify_timeout")
("user.mergerfs.nullrw") ("user.mergerfs.nullrw")
("user.mergerfs.ignorepponrename") ("user.mergerfs.ignorepponrename")
("user.mergerfs.security_capability")
("user.mergerfs.policies") ("user.mergerfs.policies")
("user.mergerfs.version") ("user.mergerfs.version")
("user.mergerfs.pid"); ("user.mergerfs.pid");

5
src/option_parser.cpp

@ -194,6 +194,8 @@ parse_and_process_kv_arg(Config &config,
rv = parse_and_process(value,config.nullrw); rv = parse_and_process(value,config.nullrw);
else if(key == "ignorepponrename") else if(key == "ignorepponrename")
rv = parse_and_process(value,config.ignorepponrename); rv = parse_and_process(value,config.ignorepponrename);
else if(key == "security_capability")
rv = parse_and_process(value,config.security_capability);
} }
if(rv == -1) if(rv == -1)
@ -299,6 +301,9 @@ usage(void)
" -o ignorepponrename=<bool>\n" " -o ignorepponrename=<bool>\n"
" Ignore path preserving when performing renames\n" " Ignore path preserving when performing renames\n"
" and links. default = false\n" " and links. default = false\n"
" -o security_capability=<bool>\n"
" When disabled return ENOATTR when the xattr\n"
" security.capability is queried. default = true\n"
<< std::endl; << std::endl;
} }

4
src/setxattr.cpp

@ -297,6 +297,10 @@ _setxattr_controlfile(Config &config,
return _setxattr_bool(attrval, return _setxattr_bool(attrval,
flags, flags,
config.ignorepponrename); config.ignorepponrename);
else if(attr[2] == "security_capability")
return _setxattr_bool(attrval,
flags,
config.security_capability);
break; break;
case 4: case 4:

Loading…
Cancel
Save