Browse Source

add security_capability option

pull/504/head
Antonio SJ Musumeci 6 years ago
parent
commit
f8563369bc
  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. 15
      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");

15
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)
@ -282,23 +284,26 @@ usage(void)
" -o use_ino Have mergerfs generate inode values rather than\n" " -o use_ino Have mergerfs generate inode values rather than\n"
" autogenerated by libfuse. Suggested.\n" " autogenerated by libfuse. Suggested.\n"
" -o minfreespace=<int> minimum free space needed for certain policies.\n" " -o minfreespace=<int> minimum free space needed for certain policies.\n"
" default=4G\n"
" default = 4G\n"
" -o moveonenospc=<bool> Try to move file to another drive when ENOSPC\n" " -o moveonenospc=<bool> Try to move file to another drive when ENOSPC\n"
" on write. default=false\n"
" on write. default = false\n"
" -o dropcacheonclose=<bool>\n" " -o dropcacheonclose=<bool>\n"
" When a file is closed suggest to OS it drop\n" " When a file is closed suggest to OS it drop\n"
" the file's cache. This is useful when direct_io\n" " the file's cache. This is useful when direct_io\n"
" is disabled. default=false\n"
" is disabled. default = false\n"
" -o symlinkify=<bool> Read-only files, after a timeout, will be turned\n" " -o symlinkify=<bool> Read-only files, after a timeout, will be turned\n"
" into symlinks. Read docs for limitations and\n" " into symlinks. Read docs for limitations and\n"
" possible issues. default=false\n"
" possible issues. default = false\n"
" -o symlinkify_timeout=<int>\n" " -o symlinkify_timeout=<int>\n"
" timeout in seconds before will turn to symlinks.\n" " timeout in seconds before will turn to symlinks.\n"
" default=3600\n"
" default = 3600\n"
" -o nullrw=<bool> Disables reads and writes. For benchmarking.\n" " -o nullrw=<bool> Disables reads and writes. For benchmarking.\n"
" -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