mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-26 19:01:56 -04:00
fix FS_IOC_{GET,SET}{FLAGS,VERSION} ioctl calls
This commit is contained in:
parent
a80f9a0b29
commit
7bf607bb6b
6 changed files with 132 additions and 27 deletions
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "config.hpp"
|
||||
#include "dirinfo.hpp"
|
||||
#include "endian.hpp"
|
||||
#include "errno.hpp"
|
||||
#include "fileinfo.hpp"
|
||||
#include "fs_base_close.hpp"
|
||||
|
|
@ -35,30 +36,81 @@
|
|||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
#ifndef FS_IOC_GETFLAGS
|
||||
# define FS_IOC_GETFLAGS _IOR('f',1,long)
|
||||
#endif
|
||||
|
||||
#ifndef FS_IOC_SETFLAGS
|
||||
# define FS_IOC_SETFLAGS _IOW('f',2,long)
|
||||
#endif
|
||||
|
||||
#ifndef FS_IOC_GETVERSION
|
||||
# define FS_IOC_GETVERSION _IOR('v',1,long)
|
||||
#endif
|
||||
|
||||
#ifndef FS_IOC_SETVERSION
|
||||
# define FS_IOC_SETVERSION _IOW('v',2,long)
|
||||
#endif
|
||||
|
||||
/*
|
||||
There is a bug with FUSE and these ioctl commands. The regular
|
||||
libfuse high level API assumes the output buffer size based on the
|
||||
command and gives no control over this. FS_IOC_GETFLAGS and
|
||||
FS_IOC_SETFLAGS however are defined as `long` when in fact it is an
|
||||
`int`. On 64bit systems where long is 8 bytes this can lead to
|
||||
libfuse telling the kernel to write 8 bytes and if the user only
|
||||
allocated an integer then it will overwrite the 4 bytes after the
|
||||
variable which could result in data corruption and/or crashes.
|
||||
|
||||
I've modified the API to allow changing of the output buffer
|
||||
size. This fixes the issue on little endian systems because the
|
||||
lower 4 bytes are the same regardless of what the user
|
||||
allocated. However, on big endian systems thats not the case and it
|
||||
is not possible to safely handle the situation.
|
||||
|
||||
https://lwn.net/Articles/575846/
|
||||
*/
|
||||
|
||||
namespace l
|
||||
{
|
||||
static
|
||||
int
|
||||
ioctl(const int fd_,
|
||||
const unsigned long cmd_,
|
||||
void *data_)
|
||||
ioctl(const int fd_,
|
||||
const int cmd_,
|
||||
void *data_,
|
||||
uint32_t *out_bufsz_)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = fs::ioctl(fd_,cmd_,data_);
|
||||
switch(cmd_)
|
||||
{
|
||||
case FS_IOC_GETFLAGS:
|
||||
case FS_IOC_SETFLAGS:
|
||||
case FS_IOC_GETVERSION:
|
||||
case FS_IOC_SETVERSION:
|
||||
if(endian::is_big() && (sizeof(long) != sizeof(int)))
|
||||
return -ENOTTY;
|
||||
*out_bufsz_ = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
rv = ((_IOC_DIR(cmd_) == _IOC_NONE) ?
|
||||
fs::ioctl(fd_,cmd_) :
|
||||
fs::ioctl(fd_,cmd_,data_));
|
||||
|
||||
return ((rv == -1) ? -errno : rv);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
ioctl_file(fuse_file_info *ffi_,
|
||||
const unsigned long cmd_,
|
||||
void *data_)
|
||||
ioctl_file(fuse_file_info *ffi_,
|
||||
const int cmd_,
|
||||
void *data_,
|
||||
uint32_t *out_bufsz_)
|
||||
{
|
||||
FileInfo *fi = reinterpret_cast<FileInfo*>(ffi_->fh);
|
||||
|
||||
return l::ioctl(fi->fd,cmd_,data_);
|
||||
return l::ioctl(fi->fd,cmd_,data_,out_bufsz_);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -72,8 +124,9 @@ namespace l
|
|||
const Branches &branches_,
|
||||
const uint64_t minfreespace_,
|
||||
const char *fusepath_,
|
||||
const unsigned long cmd_,
|
||||
void *data_)
|
||||
const int cmd_,
|
||||
void *data_,
|
||||
uint32_t *out_bufsz_)
|
||||
{
|
||||
int fd;
|
||||
int rv;
|
||||
|
|
@ -91,7 +144,7 @@ namespace l
|
|||
if(fd == -1)
|
||||
return -errno;
|
||||
|
||||
rv = l::ioctl(fd,cmd_,data_);
|
||||
rv = l::ioctl(fd,cmd_,data_,out_bufsz_);
|
||||
|
||||
fs::close(fd);
|
||||
|
||||
|
|
@ -100,9 +153,10 @@ namespace l
|
|||
|
||||
static
|
||||
int
|
||||
ioctl_dir(fuse_file_info *ffi_,
|
||||
const unsigned long cmd_,
|
||||
void *data_)
|
||||
ioctl_dir(fuse_file_info *ffi_,
|
||||
const int cmd_,
|
||||
void *data_,
|
||||
uint32_t *out_bufsz_)
|
||||
{
|
||||
DirInfo *di = reinterpret_cast<DirInfo*>(ffi_->fh);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
|
|
@ -115,7 +169,8 @@ namespace l
|
|||
config.minfreespace,
|
||||
di->fusepath.c_str(),
|
||||
cmd_,
|
||||
data_);
|
||||
data_,
|
||||
out_bufsz_);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -127,12 +182,12 @@ namespace FUSE
|
|||
void *arg_,
|
||||
fuse_file_info *ffi_,
|
||||
unsigned int flags_,
|
||||
void *data_)
|
||||
void *data_,
|
||||
uint32_t *out_bufsz_)
|
||||
{
|
||||
if(flags_ & FUSE_IOCTL_DIR)
|
||||
return l::ioctl_dir(ffi_,cmd_,data_);
|
||||
return l::ioctl_dir(ffi_,cmd_,data_,out_bufsz_);
|
||||
|
||||
|
||||
return l::ioctl_file(ffi_,cmd_,data_);
|
||||
return l::ioctl_file(ffi_,cmd_,data_,out_bufsz_);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue