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.
 
 
 
 
 
 

400 lines
10 KiB

  1. #ifndef APT_APTMETHOD_H
  2. #define APT_APTMETHOD_H
  3. #include "config.h"
  4. #include <apt-pkg/acquire-method.h>
  5. #include <apt-pkg/configuration.h>
  6. #include <apt-pkg/error.h>
  7. #include <apt-pkg/fileutl.h>
  8. #include <apt-pkg/netrc.h>
  9. #include <algorithm>
  10. #include <locale>
  11. #include <string>
  12. #include <vector>
  13. #include <sys/stat.h>
  14. #include <sys/time.h>
  15. #include <sys/types.h>
  16. #include <unistd.h>
  17. #include <apti18n.h>
  18. #ifdef HAVE_SECCOMP
  19. #include <seccomp.h>
  20. #endif
  21. static bool hasDoubleColon(std::string const &n)
  22. {
  23. return n.find("::") != std::string::npos;
  24. }
  25. class aptMethod : public pkgAcqMethod
  26. {
  27. protected:
  28. std::string const Binary;
  29. unsigned long SeccompFlags;
  30. enum Seccomp
  31. {
  32. BASE = (1 << 1),
  33. NETWORK = (1 << 2),
  34. DIRECTORY = (1 << 3),
  35. };
  36. public:
  37. virtual bool Configuration(std::string Message) APT_OVERRIDE
  38. {
  39. if (pkgAcqMethod::Configuration(Message) == false)
  40. return false;
  41. std::string const conf = std::string("Binary::") + Binary;
  42. _config->MoveSubTree(conf.c_str(), NULL);
  43. DropPrivsOrDie();
  44. if (LoadSeccomp() == false)
  45. return false;
  46. return true;
  47. }
  48. bool LoadSeccomp()
  49. {
  50. #ifdef HAVE_SECCOMP
  51. int rc;
  52. scmp_filter_ctx ctx = NULL;
  53. if (SeccompFlags == 0)
  54. return true;
  55. if (_config->FindB("APT::Sandbox::Seccomp", true) == false)
  56. return true;
  57. ctx = seccomp_init(SCMP_ACT_TRAP);
  58. if (ctx == NULL)
  59. return _error->FatalE("HttpMethod::Configuration", "Cannot init seccomp");
  60. #define ALLOW(what) \
  61. if ((rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(what), 0))) \
  62. return _error->FatalE("HttpMethod::Configuration", "Cannot allow %s: %s", #what, strerror(-rc));
  63. for (auto &custom : _config->FindVector("APT::Sandbox::Seccomp::Trap"))
  64. {
  65. if ((rc = seccomp_rule_add(ctx, SCMP_ACT_TRAP, seccomp_syscall_resolve_name(custom.c_str()), 0)))
  66. return _error->FatalE("HttpMethod::Configuration", "Cannot trap %s: %s", custom.c_str(), strerror(-rc));
  67. }
  68. ALLOW(access);
  69. ALLOW(arch_prctl);
  70. ALLOW(brk);
  71. ALLOW(chmod);
  72. ALLOW(chown);
  73. ALLOW(chown32);
  74. ALLOW(clock_getres);
  75. ALLOW(clock_gettime);
  76. ALLOW(close);
  77. ALLOW(creat);
  78. ALLOW(dup);
  79. ALLOW(dup2);
  80. ALLOW(dup3);
  81. ALLOW(exit);
  82. ALLOW(exit_group);
  83. ALLOW(faccessat);
  84. ALLOW(fchmod);
  85. ALLOW(fchmodat);
  86. ALLOW(fchown);
  87. ALLOW(fchown32);
  88. ALLOW(fchownat);
  89. ALLOW(fcntl);
  90. ALLOW(fcntl64);
  91. ALLOW(fdatasync);
  92. ALLOW(flock);
  93. ALLOW(fstat);
  94. ALLOW(fstat64);
  95. ALLOW(fstatat64);
  96. ALLOW(fstatfs);
  97. ALLOW(fstatfs64);
  98. ALLOW(fsync);
  99. ALLOW(ftime);
  100. ALLOW(ftruncate);
  101. ALLOW(ftruncate64);
  102. ALLOW(futex);
  103. ALLOW(futimesat);
  104. ALLOW(getegid);
  105. ALLOW(getegid32);
  106. ALLOW(geteuid);
  107. ALLOW(geteuid32);
  108. ALLOW(getgid);
  109. ALLOW(getgid32);
  110. ALLOW(getgroups);
  111. ALLOW(getgroups32);
  112. ALLOW(getpeername);
  113. ALLOW(getpgid);
  114. ALLOW(getpgrp);
  115. ALLOW(getpid);
  116. ALLOW(getppid);
  117. ALLOW(getrandom);
  118. ALLOW(getresgid);
  119. ALLOW(getresgid32);
  120. ALLOW(getresuid);
  121. ALLOW(getresuid32);
  122. ALLOW(getrlimit);
  123. ALLOW(get_robust_list);
  124. ALLOW(getrusage);
  125. ALLOW(gettid);
  126. ALLOW(gettimeofday);
  127. ALLOW(getuid);
  128. ALLOW(getuid32);
  129. ALLOW(ioctl);
  130. ALLOW(lchown);
  131. ALLOW(lchown32);
  132. ALLOW(_llseek);
  133. ALLOW(lseek);
  134. ALLOW(lstat);
  135. ALLOW(lstat64);
  136. ALLOW(madvise);
  137. ALLOW(mmap);
  138. ALLOW(mmap2);
  139. ALLOW(mprotect);
  140. ALLOW(mremap);
  141. ALLOW(msync);
  142. ALLOW(munmap);
  143. ALLOW(newfstatat);
  144. ALLOW(oldfstat);
  145. ALLOW(oldlstat);
  146. ALLOW(oldolduname);
  147. ALLOW(oldstat);
  148. ALLOW(olduname);
  149. ALLOW(open);
  150. ALLOW(openat);
  151. ALLOW(pipe);
  152. ALLOW(pipe2);
  153. ALLOW(poll);
  154. ALLOW(ppoll);
  155. ALLOW(prctl);
  156. ALLOW(prlimit64);
  157. ALLOW(pselect6);
  158. ALLOW(read);
  159. ALLOW(rename);
  160. ALLOW(renameat);
  161. ALLOW(rt_sigaction);
  162. ALLOW(rt_sigpending);
  163. ALLOW(rt_sigprocmask);
  164. ALLOW(rt_sigqueueinfo);
  165. ALLOW(rt_sigreturn);
  166. ALLOW(rt_sigsuspend);
  167. ALLOW(rt_sigtimedwait);
  168. ALLOW(sched_yield);
  169. ALLOW(select);
  170. ALLOW(set_robust_list);
  171. ALLOW(sigaction);
  172. ALLOW(sigpending);
  173. ALLOW(sigprocmask);
  174. ALLOW(sigreturn);
  175. ALLOW(sigsuspend);
  176. ALLOW(stat);
  177. ALLOW(statfs);
  178. ALLOW(sync);
  179. ALLOW(syscall);
  180. ALLOW(time);
  181. ALLOW(truncate);
  182. ALLOW(truncate64);
  183. ALLOW(ugetrlimit);
  184. ALLOW(umask);
  185. ALLOW(uname);
  186. ALLOW(unlink);
  187. ALLOW(unlinkat);
  188. ALLOW(utime);
  189. ALLOW(utimensat);
  190. ALLOW(utimes);
  191. ALLOW(write);
  192. if ((SeccompFlags & Seccomp::NETWORK) != 0)
  193. {
  194. ALLOW(bind);
  195. ALLOW(connect);
  196. ALLOW(getsockname);
  197. ALLOW(getsockopt);
  198. ALLOW(recv);
  199. ALLOW(recvfrom);
  200. ALLOW(recvmsg);
  201. ALLOW(send);
  202. ALLOW(sendmsg);
  203. ALLOW(sendto);
  204. ALLOW(setsockopt);
  205. ALLOW(socket);
  206. }
  207. if ((SeccompFlags & Seccomp::DIRECTORY) != 0)
  208. {
  209. ALLOW(readdir);
  210. ALLOW(getdents);
  211. ALLOW(getdents64);
  212. }
  213. for (auto &custom : _config->FindVector("APT::Sandbox::Seccomp::Allow"))
  214. {
  215. if ((rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, seccomp_syscall_resolve_name(custom.c_str()), 0)))
  216. return _error->FatalE("HttpMethod::Configuration", "Cannot allow %s: %s", custom.c_str(), strerror(-rc));
  217. }
  218. #undef ALLOW
  219. rc = seccomp_load(ctx);
  220. if (rc != 0)
  221. return _error->FatalE("HttpMethod::Configuration", "could not load seccomp policy: %s", strerror(-rc));
  222. #endif
  223. return true;
  224. }
  225. bool CalculateHashes(FetchItem const * const Itm, FetchResult &Res) const APT_NONNULL(2)
  226. {
  227. Hashes Hash(Itm->ExpectedHashes);
  228. FileFd Fd;
  229. if (Fd.Open(Res.Filename, FileFd::ReadOnly) == false || Hash.AddFD(Fd) == false)
  230. return false;
  231. Res.TakeHashes(Hash);
  232. return true;
  233. }
  234. void Warning(const char *Format,...)
  235. {
  236. va_list args;
  237. va_start(args,Format);
  238. PrintStatus("104 Warning", Format, args);
  239. va_end(args);
  240. }
  241. std::vector<std::string> methodNames;
  242. void setPostfixForMethodNames(char const * const postfix) APT_NONNULL(2)
  243. {
  244. methodNames.erase(std::remove_if(methodNames.begin(), methodNames.end(), hasDoubleColon), methodNames.end());
  245. decltype(methodNames) toAdd;
  246. for (auto && name: methodNames)
  247. toAdd.emplace_back(name + "::" + postfix);
  248. std::move(toAdd.begin(), toAdd.end(), std::back_inserter(methodNames));
  249. }
  250. bool DebugEnabled() const
  251. {
  252. if (methodNames.empty())
  253. return false;
  254. auto const sni = std::find_if_not(methodNames.crbegin(), methodNames.crend(), hasDoubleColon);
  255. if (unlikely(sni == methodNames.crend()))
  256. return false;
  257. auto const ln = methodNames[methodNames.size() - 1];
  258. // worst case: all three are the same
  259. std::string confln, confsn, confpn;
  260. strprintf(confln, "Debug::Acquire::%s", ln.c_str());
  261. strprintf(confsn, "Debug::Acquire::%s", sni->c_str());
  262. auto const pni = sni->substr(0, sni->find('+'));
  263. strprintf(confpn, "Debug::Acquire::%s", pni.c_str());
  264. return _config->FindB(confln,_config->FindB(confsn, _config->FindB(confpn, false)));
  265. }
  266. std::string ConfigFind(char const * const postfix, std::string const &defValue) const APT_NONNULL(2)
  267. {
  268. for (auto name = methodNames.rbegin(); name != methodNames.rend(); ++name)
  269. {
  270. std::string conf;
  271. strprintf(conf, "Acquire::%s::%s", name->c_str(), postfix);
  272. auto const value = _config->Find(conf);
  273. if (value.empty() == false)
  274. return value;
  275. }
  276. return defValue;
  277. }
  278. std::string ConfigFind(std::string const &postfix, std::string const &defValue) const
  279. {
  280. return ConfigFind(postfix.c_str(), defValue);
  281. }
  282. bool ConfigFindB(char const * const postfix, bool const defValue) const APT_NONNULL(2)
  283. {
  284. return StringToBool(ConfigFind(postfix, defValue ? "yes" : "no"), defValue);
  285. }
  286. int ConfigFindI(char const * const postfix, int const defValue) const APT_NONNULL(2)
  287. {
  288. char *End;
  289. std::string const value = ConfigFind(postfix, "");
  290. auto const Res = strtol(value.c_str(), &End, 0);
  291. if (value.c_str() == End)
  292. return defValue;
  293. return Res;
  294. }
  295. bool TransferModificationTimes(char const * const From, char const * const To, time_t &LastModified) APT_NONNULL(2, 3)
  296. {
  297. if (strcmp(To, "/dev/null") == 0)
  298. return true;
  299. struct stat Buf2;
  300. if (lstat(To, &Buf2) != 0 || S_ISLNK(Buf2.st_mode))
  301. return true;
  302. struct stat Buf;
  303. if (stat(From, &Buf) != 0)
  304. return _error->Errno("stat",_("Failed to stat"));
  305. // we don't use utimensat here for compatibility reasons: #738567
  306. struct timeval times[2];
  307. times[0].tv_sec = Buf.st_atime;
  308. LastModified = times[1].tv_sec = Buf.st_mtime;
  309. times[0].tv_usec = times[1].tv_usec = 0;
  310. if (utimes(To, times) != 0)
  311. return _error->Errno("utimes",_("Failed to set modification time"));
  312. return true;
  313. }
  314. aptMethod(std::string &&Binary, char const *const Ver, unsigned long const Flags) APT_NONNULL(3)
  315. : pkgAcqMethod(Ver, Flags), Binary(Binary), SeccompFlags(0), methodNames({Binary})
  316. {
  317. try {
  318. std::locale::global(std::locale(""));
  319. } catch (...) {
  320. setlocale(LC_ALL, "");
  321. }
  322. }
  323. };
  324. class aptAuthConfMethod : public aptMethod
  325. {
  326. FileFd authconf;
  327. public:
  328. virtual bool Configuration(std::string Message) APT_OVERRIDE
  329. {
  330. if (pkgAcqMethod::Configuration(Message) == false)
  331. return false;
  332. std::string const conf = std::string("Binary::") + Binary;
  333. _config->MoveSubTree(conf.c_str(), NULL);
  334. auto const netrc = _config->FindFile("Dir::Etc::netrc");
  335. if (netrc.empty() == false)
  336. {
  337. // ignore errors with opening the auth file as it doesn't need to exist
  338. _error->PushToStack();
  339. authconf.Open(netrc, FileFd::ReadOnly);
  340. _error->RevertToStack();
  341. }
  342. DropPrivsOrDie();
  343. if (LoadSeccomp() == false)
  344. return false;
  345. return true;
  346. }
  347. bool MaybeAddAuthTo(URI &uri)
  348. {
  349. if (uri.User.empty() == false || uri.Password.empty() == false)
  350. return true;
  351. if (authconf.IsOpen() == false)
  352. return true;
  353. if (authconf.Seek(0) == false)
  354. return false;
  355. return MaybeAddAuth(authconf, uri);
  356. }
  357. aptAuthConfMethod(std::string &&Binary, char const *const Ver, unsigned long const Flags) APT_NONNULL(3)
  358. : aptMethod(std::move(Binary), Ver, Flags) {}
  359. };
  360. #endif