You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

396 lines
9.5 KiB

4 years ago
  1. /*
  2. Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
  3. Permission to use, copy, modify, and/or distribute this software for any
  4. purpose with or without fee is hereby granted, provided that the above
  5. copyright notice and this permission notice appear in all copies.
  6. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  7. WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  8. MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  9. ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  10. WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  11. ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  12. OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  13. */
  14. #include "config.hpp"
  15. #include "dirinfo.hpp"
  16. #include "endian.hpp"
  17. #include "errno.hpp"
  18. #include "fileinfo.hpp"
  19. #include "fs_close.hpp"
  20. #include "fs_findallfiles.hpp"
  21. #include "fs_ioctl.hpp"
  22. #include "fs_open.hpp"
  23. #include "fs_path.hpp"
  24. #include "str.hpp"
  25. #include "ugid.hpp"
  26. #include <fuse.h>
  27. #include <string>
  28. #include <vector>
  29. #include <fcntl.h>
  30. #include <string.h>
  31. using std::string;
  32. using std::vector;
  33. typedef char IOCTL_BUF[4096];
  34. #define IOCTL_APP_TYPE 0xDF
  35. //#define IOCTL_READ_KEYS 0xD000DF00
  36. //#define IOCTL_READ_VAL 0xD000DF01
  37. //#define IOCTL_WRITE_VAL 0x5000DF02
  38. //#define IOCTL_FILE_INFO 0xD000DF03
  39. #define IOCTL_READ_KEYS _IOWR(IOCTL_APP_TYPE,0,IOCTL_BUF)
  40. #define IOCTL_READ_VAL _IOWR(IOCTL_APP_TYPE,1,IOCTL_BUF)
  41. #define IOCTL_WRITE_VAL _IOW(IOCTL_APP_TYPE,2,IOCTL_BUF)
  42. #define IOCTL_FILE_INFO _IOWR(IOCTL_APP_TYPE,3,IOCTL_BUF)
  43. #ifndef FS_IOC_GETFLAGS
  44. # define FS_IOC_GETFLAGS _IOR('f',1,long)
  45. #endif
  46. #ifndef FS_IOC_SETFLAGS
  47. # define FS_IOC_SETFLAGS _IOW('f',2,long)
  48. #endif
  49. #ifndef FS_IOC_GETVERSION
  50. # define FS_IOC_GETVERSION _IOR('v',1,long)
  51. #endif
  52. #ifndef FS_IOC_SETVERSION
  53. # define FS_IOC_SETVERSION _IOW('v',2,long)
  54. #endif
  55. /*
  56. There is a bug with FUSE and these ioctl commands. The regular
  57. libfuse high level API assumes the output buffer size based on the
  58. command and gives no control over this. FS_IOC_GETFLAGS and
  59. FS_IOC_SETFLAGS however are defined as `long` when in fact it is an
  60. `int`. On 64bit systems where long is 8 bytes this can lead to
  61. libfuse telling the kernel to write 8 bytes and if the user only
  62. allocated an integer then it will overwrite the 4 bytes after the
  63. variable which could result in data corruption and/or crashes.
  64. I've modified the API to allow changing of the output buffer
  65. size. This fixes the issue on little endian systems because the
  66. lower 4 bytes are the same regardless of what the user
  67. allocated. However, on big endian systems that's not the case and it
  68. is not possible to safely handle the situation.
  69. https://lwn.net/Articles/575846/
  70. */
  71. namespace l
  72. {
  73. static
  74. int
  75. ioctl(const int fd_,
  76. const uint32_t cmd_,
  77. void *data_,
  78. uint32_t *out_bufsz_)
  79. {
  80. int rv;
  81. switch(cmd_)
  82. {
  83. case FS_IOC_GETFLAGS:
  84. case FS_IOC_SETFLAGS:
  85. case FS_IOC_GETVERSION:
  86. case FS_IOC_SETVERSION:
  87. if(endian::is_big() && (sizeof(long) != sizeof(int)))
  88. return -ENOTTY;
  89. if((data_ != NULL) && (*out_bufsz_ > 4))
  90. *out_bufsz_ = 4;
  91. break;
  92. }
  93. rv = fs::ioctl(fd_,cmd_,data_);
  94. return ((rv == -1) ? -errno : rv);
  95. }
  96. static
  97. int
  98. ioctl_file(fuse_file_info *ffi_,
  99. const uint32_t cmd_,
  100. void *data_,
  101. uint32_t *out_bufsz_)
  102. {
  103. FileInfo *fi = reinterpret_cast<FileInfo*>(ffi_->fh);
  104. const fuse_context *fc = fuse_get_context();
  105. const ugid::Set ugid(fc->uid,fc->gid);
  106. return l::ioctl(fi->fd,cmd_,data_,out_bufsz_);
  107. }
  108. #ifndef O_NOATIME
  109. #define O_NOATIME 0
  110. #endif
  111. static
  112. int
  113. ioctl_dir_base(Policy::Func::Search searchFunc_,
  114. const Branches &branches_,
  115. const char *fusepath_,
  116. const uint32_t cmd_,
  117. void *data_,
  118. uint32_t *out_bufsz_)
  119. {
  120. int fd;
  121. int rv;
  122. string fullpath;
  123. vector<string> basepaths;
  124. rv = searchFunc_(branches_,fusepath_,&basepaths);
  125. if(rv == -1)
  126. return -errno;
  127. fullpath = fs::path::make(basepaths[0],fusepath_);
  128. fd = fs::open(fullpath,O_RDONLY|O_NOATIME|O_NONBLOCK);
  129. if(fd == -1)
  130. return -errno;
  131. rv = l::ioctl(fd,cmd_,data_,out_bufsz_);
  132. fs::close(fd);
  133. return rv;
  134. }
  135. static
  136. int
  137. ioctl_dir(fuse_file_info *ffi_,
  138. const uint32_t cmd_,
  139. void *data_,
  140. uint32_t *out_bufsz_)
  141. {
  142. DirInfo *di = reinterpret_cast<DirInfo*>(ffi_->fh);
  143. const fuse_context *fc = fuse_get_context();
  144. const Config &config = Config::ro();
  145. const ugid::Set ugid(fc->uid,fc->gid);
  146. return l::ioctl_dir_base(config.func.open.policy,
  147. config.branches,
  148. di->fusepath.c_str(),
  149. cmd_,
  150. data_,
  151. out_bufsz_);
  152. }
  153. static
  154. int
  155. strcpy(const std::string &s_,
  156. void *data_)
  157. {
  158. char *data = (char*)data_;
  159. if(s_.size() >= (sizeof(IOCTL_BUF) - 1))
  160. return -ERANGE;
  161. memcpy(data,s_.c_str(),s_.size());
  162. data[s_.size()] = '\0';
  163. return s_.size();
  164. }
  165. static
  166. int
  167. read_keys(void *data_)
  168. {
  169. std::string keys;
  170. const Config &config = Config::ro();
  171. config.keys(keys);
  172. return l::strcpy(keys,data_);
  173. }
  174. static
  175. int
  176. read_val(void *data_)
  177. {
  178. int rv;
  179. char *data;
  180. std::string key;
  181. std::string val;
  182. const Config &config = Config::ro();
  183. data = (char*)data_;
  184. data[sizeof(IOCTL_BUF) - 1] = '\0';
  185. key = data;
  186. rv = config.get(key,&val);
  187. if(rv < 0)
  188. return rv;
  189. return l::strcpy(val,data_);
  190. }
  191. static
  192. int
  193. write_val(void *data_)
  194. {
  195. char *data;
  196. std::string kv;
  197. std::string key;
  198. std::string val;
  199. Config &config = Config::rw();
  200. data = (char*)data_;
  201. data[sizeof(IOCTL_BUF) - 1] = '\0';
  202. kv = data;
  203. str::splitkv(kv,'=',&key,&val);
  204. return config.set(key,val);
  205. }
  206. static
  207. int
  208. file_basepath(Policy::Func::Search searchFunc_,
  209. const Branches &branches_,
  210. const char *fusepath_,
  211. void *data_)
  212. {
  213. int rv;
  214. vector<string> basepaths;
  215. rv = searchFunc_(branches_,fusepath_,&basepaths);
  216. if(rv == -1)
  217. return -errno;
  218. return l::strcpy(basepaths[0],data_);
  219. }
  220. static
  221. int
  222. file_basepath(fuse_file_info *ffi_,
  223. void *data_)
  224. {
  225. const Config &config = Config::ro();
  226. std::string &fusepath = reinterpret_cast<FH*>(ffi_->fh)->fusepath;
  227. return l::file_basepath(config.func.open.policy,
  228. config.branches,
  229. fusepath.c_str(),
  230. data_);
  231. }
  232. static
  233. int
  234. file_relpath(fuse_file_info *ffi_,
  235. void *data_)
  236. {
  237. std::string &fusepath = reinterpret_cast<FH*>(ffi_->fh)->fusepath;
  238. return l::strcpy(fusepath,data_);
  239. }
  240. static
  241. int
  242. file_fullpath(Policy::Func::Search searchFunc_,
  243. const Branches &branches_,
  244. const string &fusepath_,
  245. void *data_)
  246. {
  247. int rv;
  248. string fullpath;
  249. vector<string> basepaths;
  250. rv = searchFunc_(branches_,fusepath_,&basepaths);
  251. if(rv == -1)
  252. return -errno;
  253. fullpath = fs::path::make(basepaths[0],fusepath_);
  254. return l::strcpy(fullpath,data_);
  255. }
  256. static
  257. int
  258. file_fullpath(fuse_file_info *ffi_,
  259. void *data_)
  260. {
  261. const Config &config = Config::ro();
  262. std::string &fusepath = reinterpret_cast<FH*>(ffi_->fh)->fusepath;
  263. return l::file_fullpath(config.func.open.policy,
  264. config.branches,
  265. fusepath,
  266. data_);
  267. }
  268. static
  269. int
  270. file_allpaths(fuse_file_info *ffi_,
  271. void *data_)
  272. {
  273. string concated;
  274. vector<string> paths;
  275. vector<string> branches;
  276. string &fusepath = reinterpret_cast<FH*>(ffi_->fh)->fusepath;
  277. const Config &config = Config::ro();
  278. config.branches.to_paths(branches);
  279. fs::findallfiles(branches,fusepath.c_str(),&paths);
  280. concated = str::join(paths,'\0');
  281. return l::strcpy(concated,data_);
  282. }
  283. static
  284. int
  285. file_info(fuse_file_info *ffi_,
  286. void *data_)
  287. {
  288. char *key = (char*)data_;
  289. if(!strcmp("basepath",key))
  290. return l::file_basepath(ffi_,data_);
  291. if(!strcmp("relpath",key))
  292. return l::file_relpath(ffi_,data_);
  293. if(!strcmp("fullpath",key))
  294. return l::file_fullpath(ffi_,data_);
  295. if(!strcmp("allpaths",key))
  296. return l::file_allpaths(ffi_,data_);
  297. return -ENOATTR;
  298. }
  299. }
  300. namespace FUSE
  301. {
  302. int
  303. ioctl(unsigned long cmd_,
  304. void *arg_,
  305. fuse_file_info *ffi_,
  306. unsigned int flags_,
  307. void *data_,
  308. uint32_t *out_bufsz_)
  309. {
  310. switch(cmd_)
  311. {
  312. case IOCTL_READ_KEYS:
  313. return l::read_keys(data_);
  314. case IOCTL_READ_VAL:
  315. return l::read_val(data_);
  316. case IOCTL_WRITE_VAL:
  317. return l::write_val(data_);
  318. case IOCTL_FILE_INFO:
  319. return l::file_info(ffi_,data_);
  320. }
  321. if(flags_ & FUSE_IOCTL_DIR)
  322. return l::ioctl_dir(ffi_,cmd_,data_,out_bufsz_);
  323. return l::ioctl_file(ffi_,cmd_,data_,out_bufsz_);
  324. }
  325. }