aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Pärtel <martin.partel@gmail.com>2016-07-31 18:15:08 +0100
committerMartin Pärtel <martin.partel@gmail.com>2016-07-31 18:15:08 +0100
commitf2803095dab51c1000bae8c4d7e40a4d16f0c382 (patch)
treea399460905043d8e6def02e248261bcbe4b2a330
parent3fda402c006f63e68e1a72f26f4c3ff3040289af (diff)
downloadbindfs-f2803095dab51c1000bae8c4d7e40a4d16f0c382.tar.gz
Added option --enable-ioctl to forward ioctl() calls.
This should address #37.
-rw-r--r--src/bindfs.18
-rw-r--r--src/bindfs.c28
-rwxr-xr-xtests/test_bindfs.rb21
3 files changed, 57 insertions, 0 deletions
diff --git a/src/bindfs.1 b/src/bindfs.1
index d98cb74..fd2095d 100644
--- a/src/bindfs.1
+++ b/src/bindfs.1
@@ -316,6 +316,14 @@ will be reflected in a mirrored file's ctime.
The underlying file's ctime will still be updated normally.
.TP
+.B \-\-enable\-ioctl, \-o enable\-ioctl
+Enables forwarding of ioctl, which is needed for some advanced features such as
+append-only files (\fBchattr +a\fP). Note that the ioctl action will be
+performed as the mounter, not the calling user. No efforts are made to check
+whether the calling user would ordinarily have the permissions to make the
+ioctl. This may be a security concern, especially when mounting as root.
+
+.TP
.B \-\-multithreaded, \-o multithreaded
Run bindfs in multithreaded mode. While bindfs is designed to be
otherwise thread-safe, there is currently a race condition that may pose
diff --git a/src/bindfs.c b/src/bindfs.c
index d4a77ab..039393b 100644
--- a/src/bindfs.c
+++ b/src/bindfs.c
@@ -53,6 +53,7 @@
#endif
#include <sys/time.h>
#include <sys/statvfs.h>
+#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
@@ -170,6 +171,8 @@ static struct Settings {
int ctime_from_mtime;
+ int enable_ioctl;
+
uid_t uid_offset;
gid_t gid_offset;
@@ -233,6 +236,9 @@ static int bindfs_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi);
static int bindfs_write(const char *path, const char *buf, size_t size,
off_t offset, struct fuse_file_info *fi);
+static int bindfs_ioctl(const char *path, int cmd, void *arg,
+ struct fuse_file_info *fi, unsigned int flags,
+ void *data);
static int bindfs_statfs(const char *path, struct statvfs *stbuf);
static int bindfs_release(const char *path, struct fuse_file_info *fi);
static int bindfs_fsync(const char *path, int isdatasync,
@@ -1090,6 +1096,16 @@ static int bindfs_write(const char *path, const char *buf, size_t size,
return res;
}
+static int bindfs_ioctl(const char *path, int cmd, void *arg,
+ struct fuse_file_info *fi, unsigned int flags,
+ void *data) {
+ int ret = ioctl(fi->fh, cmd, data);
+ if (ret == -1) {
+ return -errno;
+ }
+ return ret;
+}
+
static int bindfs_statfs(const char *path, struct statvfs *stbuf)
{
int res;
@@ -1335,6 +1351,7 @@ static struct fuse_operations bindfs_oper = {
.open = bindfs_open,
.read = bindfs_read,
.write = bindfs_write,
+ .ioctl = bindfs_ioctl,
.statfs = bindfs_statfs,
.release = bindfs_release,
.fsync = bindfs_fsync,
@@ -1450,6 +1467,7 @@ enum OptionKey {
OPTKEY_XATTR_READ_WRITE,
OPTKEY_REALISTIC_PERMISSIONS,
OPTKEY_CTIME_FROM_MTIME,
+ OPTKEY_ENABLE_IOCTL,
OPTKEY_HIDE_HARD_LINKS,
OPTKEY_RESOLVE_SYMLINKS,
OPTKEY_MULTITHREADED
@@ -1530,6 +1548,9 @@ static int process_option(void *data, const char *arg, int key,
case OPTKEY_CTIME_FROM_MTIME:
settings.ctime_from_mtime = 1;
return 0;
+ case OPTKEY_ENABLE_IOCTL:
+ settings.enable_ioctl = 1;
+ return 0;
case OPTKEY_HIDE_HARD_LINKS:
settings.hide_hard_links = 1;
return 0;
@@ -1870,6 +1891,7 @@ int main(int argc, char *argv[])
OPT2("--realistic-permissions", "realistic-permissions", OPTKEY_REALISTIC_PERMISSIONS),
OPT2("--ctime-from-mtime", "ctime-from-mtime", OPTKEY_CTIME_FROM_MTIME),
+ OPT2("--enable-ioctl", "enable-ioctl", OPTKEY_ENABLE_IOCTL),
OPT_OFFSET2("--multithreaded", "multithreaded", multithreaded, -1),
OPT_OFFSET2("--uid-offset=%s", "uid-offset=%s", uid_offset, 0),
@@ -1914,6 +1936,7 @@ int main(int argc, char *argv[])
settings.resolved_symlink_deletion_policy = RESOLVED_SYMLINK_DELETION_SYMLINK_ONLY;
settings.realistic_permissions = 0;
settings.ctime_from_mtime = 0;
+ settings.enable_ioctl = 0;
settings.uid_offset = 0;
settings.gid_offset = 0;
@@ -2155,6 +2178,11 @@ int main(int argc, char *argv[])
bindfs_oper.removexattr = NULL;
}
+ /* Remove the ioctl implementation unless the user has enabled it */
+ if (!settings.enable_ioctl) {
+ bindfs_oper.ioctl = NULL;
+ }
+
/* fuse_main will daemonize by fork()'ing. The signal handler will persist. */
setup_signal_handling();
diff --git a/tests/test_bindfs.rb b/tests/test_bindfs.rb
index b4fd7f5..04c853d 100755
--- a/tests/test_bindfs.rb
+++ b/tests/test_bindfs.rb
@@ -616,6 +616,27 @@ testenv("", :title => "many files in a directory") do
assert { Dir.entries('mnt/dir').sort == expected_entries.sort }
end
+# Issue #37
+root_testenv("--enable-ioctl", :title => "append-only ioctl") do
+ touch('mnt/file')
+ system('chattr +a mnt/file')
+ raise 'chattr +a failed' unless $?.success?
+ begin
+ File.open('mnt/file', 'a') do |f|
+ f.write('stuff')
+ end
+ assert { File.read('mnt/file') == 'stuff' }
+ assert_exception(EPERM) { File.write('mnt/file', 'newstuff') }
+ ensure
+ system('chattr -a mnt/file')
+ end
+end
+
+root_testenv("", :title => "ioctl not enabled by default") do
+ touch('mnt/file')
+ assert { `chattr +a mnt/file 2>&1`; !$?.success? }
+end
+
# FIXME: this stuff around testenv is a hax, and testenv may also exit(), which defeats the 'ensure' below.
# the test setup ought to be refactored. It might well use MiniTest or something.
if Process.uid == 0