apt  2.2.4
About: Apt (Advanced Package Tool) is a management system for software packages (Debian/Ubuntu). Release series 2.2.
  Fossies Dox: apt-2.2.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

aptmethod.h
Go to the documentation of this file.
1 #ifndef APT_APTMETHOD_H
2 #define APT_APTMETHOD_H
3 
4 #include "config.h"
5 
7 #include <apt-pkg/configuration.h>
8 #include <apt-pkg/error.h>
9 #include <apt-pkg/fileutl.h>
10 #include <apt-pkg/netrc.h>
11 #include <apt-pkg/strutl.h>
12 
13 #include <algorithm>
14 #include <locale>
15 #include <memory>
16 #include <string>
17 #include <vector>
18 
19 #include <stdlib.h>
20 #include <sys/stat.h>
21 #include <sys/time.h>
22 #include <sys/types.h>
23 #include <sys/wait.h>
24 #include <unistd.h>
25 
26 #include <apti18n.h>
27 
28 #ifdef HAVE_SECCOMP
29 #include <signal.h>
30 
31 #include <seccomp.h>
32 #endif
33 
34 enum class ResultState
35 {
39 };
40 
41 static bool hasDoubleColon(std::string const &n)
42 {
43  return n.find("::") != std::string::npos;
44 }
45 
46 class aptMethod : public pkgAcqMethod
47 {
48 protected:
49  std::string const Binary;
50  unsigned long SeccompFlags;
51  enum Seccomp
52  {
53  BASE = (1 << 1),
54  NETWORK = (1 << 2),
55  DIRECTORY = (1 << 3),
56  };
57 
58  public:
59  virtual bool Configuration(std::string Message) APT_OVERRIDE
60  {
61  if (pkgAcqMethod::Configuration(Message) == false)
62  return false;
63 
64  std::string const conf = std::string("Binary::") + Binary;
65  _config->MoveSubTree(conf.c_str(), NULL);
66 
68  if (LoadSeccomp() == false)
69  return false;
70 
71  return true;
72  }
73 
74  bool RunningInQemu(void)
75  {
76  int status;
77  pid_t pid;
78 
79  pid = fork();
80  if (pid == 0)
81  {
82  close(0);
83  close(1);
84  close(2);
85  setenv("QEMU_VERSION", "meow", 1);
86  char path[] = LIBEXEC_DIR "/apt-helper";
87  char *const argv[] = {path, NULL};
88  execv(argv[0], argv);
89  _exit(255);
90  }
91 
92  // apt-helper is supposed to exit with an error. If it exited with 0,
93  // qemu-user had problems with QEMU_VERSION and returned 0 => running in
94  // qemu-user.
95 
96  if (waitpid(pid, &status, 0) == pid && WIFEXITED(status) && WEXITSTATUS(status) == 0)
97  return true;
98 
99  return false;
100  }
101 
102  bool LoadSeccomp()
103  {
104 #ifdef HAVE_SECCOMP
105  int rc;
106  scmp_filter_ctx ctx = NULL;
107 
108  if (SeccompFlags == 0)
109  return true;
110 
111  if (_config->FindB("APT::Sandbox::Seccomp", false) == false)
112  return true;
113 
114  if (RunningInQemu() == true)
115  {
116  Warning("Running in qemu-user, not using seccomp");
117  return true;
118  }
119 
120  ctx = seccomp_init(SCMP_ACT_TRAP);
121  if (ctx == NULL)
122  return _error->FatalE("HttpMethod::Configuration", "Cannot init seccomp");
123 
124 #define ALLOW(what) \
125  if ((rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(what), 0))) \
126  return _error->FatalE("HttpMethod::Configuration", "Cannot allow %s: %s", #what, strerror(-rc));
127 
128  for (auto &custom : _config->FindVector("APT::Sandbox::Seccomp::Trap"))
129  {
130  if ((rc = seccomp_rule_add(ctx, SCMP_ACT_TRAP, seccomp_syscall_resolve_name(custom.c_str()), 0)))
131  return _error->FatalE("HttpMethod::Configuration", "Cannot trap %s: %s", custom.c_str(), strerror(-rc));
132  }
133 
134  ALLOW(access);
135  ALLOW(arch_prctl);
136  ALLOW(brk);
137  ALLOW(chmod);
138  ALLOW(chown);
139  ALLOW(chown32);
140  ALLOW(clock_getres);
141  ALLOW(clock_getres_time64);
142  ALLOW(clock_gettime);
143  ALLOW(clock_gettime64);
144  ALLOW(clock_nanosleep);
145  ALLOW(clock_nanosleep_time64);
146  ALLOW(close);
147  ALLOW(creat);
148  ALLOW(dup);
149  ALLOW(dup2);
150  ALLOW(dup3);
151  ALLOW(exit);
152  ALLOW(exit_group);
153  ALLOW(faccessat);
154  ALLOW(fchmod);
155  ALLOW(fchmodat);
156  ALLOW(fchown);
157  ALLOW(fchown32);
158  ALLOW(fchownat);
159  ALLOW(fcntl);
160  ALLOW(fcntl64);
161  ALLOW(fdatasync);
162  ALLOW(flock);
163  ALLOW(fstat);
164  ALLOW(fstat64);
165  ALLOW(fstatat64);
166  ALLOW(fstatfs);
167  ALLOW(fstatfs64);
168  ALLOW(fsync);
169  ALLOW(ftime);
170  ALLOW(ftruncate);
171  ALLOW(ftruncate64);
172  ALLOW(futex);
173  ALLOW(futex_time64);
174  ALLOW(futimesat);
175  ALLOW(getegid);
176  ALLOW(getegid32);
177  ALLOW(geteuid);
178  ALLOW(geteuid32);
179  ALLOW(getgid);
180  ALLOW(getgid32);
181  ALLOW(getgroups);
182  ALLOW(getgroups32);
183  ALLOW(getpeername);
184  ALLOW(getpgid);
185  ALLOW(getpgrp);
186  ALLOW(getpid);
187  ALLOW(getppid);
188  ALLOW(getrandom);
189  ALLOW(getresgid);
190  ALLOW(getresgid32);
191  ALLOW(getresuid);
192  ALLOW(getresuid32);
193  ALLOW(getrlimit);
194  ALLOW(get_robust_list);
195  ALLOW(getrusage);
196  ALLOW(gettid);
197  ALLOW(gettimeofday);
198  ALLOW(getuid);
199  ALLOW(getuid32);
200  ALLOW(ioctl);
201  ALLOW(lchown);
202  ALLOW(lchown32);
203  ALLOW(_llseek);
204  ALLOW(lseek);
205  ALLOW(lstat);
206  ALLOW(lstat64);
207  ALLOW(madvise);
208  ALLOW(mmap);
209  ALLOW(mmap2);
210  ALLOW(mprotect);
211  ALLOW(mremap);
212  ALLOW(msync);
213  ALLOW(munmap);
214  ALLOW(nanosleep);
215  ALLOW(newfstatat);
216  ALLOW(_newselect);
217  ALLOW(oldfstat);
218  ALLOW(oldlstat);
219  ALLOW(oldolduname);
220  ALLOW(oldstat);
221  ALLOW(olduname);
222  ALLOW(open);
223  ALLOW(openat);
224  ALLOW(pipe);
225  ALLOW(pipe2);
226  ALLOW(poll);
227  ALLOW(ppoll);
228  ALLOW(ppoll_time64);
229  ALLOW(prctl);
230  ALLOW(prlimit64);
231  ALLOW(pselect6);
232  ALLOW(pselect6_time64);
233  ALLOW(read);
234  ALLOW(readv);
235  ALLOW(rename);
236  ALLOW(renameat);
237  ALLOW(renameat2);
238  ALLOW(restart_syscall);
239  ALLOW(rt_sigaction);
240  ALLOW(rt_sigpending);
241  ALLOW(rt_sigprocmask);
242  ALLOW(rt_sigqueueinfo);
243  ALLOW(rt_sigreturn);
244  ALLOW(rt_sigsuspend);
245  ALLOW(rt_sigtimedwait);
246  ALLOW(sched_yield);
247  ALLOW(select);
248  ALLOW(set_robust_list);
249  ALLOW(sigaction);
250  ALLOW(sigpending);
251  ALLOW(sigprocmask);
252  ALLOW(sigreturn);
253  ALLOW(sigsuspend);
254  ALLOW(stat);
255  ALLOW(stat64);
256  ALLOW(statfs);
257  ALLOW(statfs64);
258 #ifdef __NR_statx
259  ALLOW(statx);
260 #endif
261  ALLOW(sync);
262  ALLOW(syscall);
263  ALLOW(sysinfo);
264  ALLOW(time);
265  ALLOW(truncate);
266  ALLOW(truncate64);
267  ALLOW(ugetrlimit);
268  ALLOW(umask);
269  ALLOW(uname);
270  ALLOW(unlink);
271  ALLOW(unlinkat);
272  ALLOW(utime);
273  ALLOW(utimensat);
274  ALLOW(utimensat_time64);
275  ALLOW(utimes);
276  ALLOW(write);
277  ALLOW(writev);
278 
279  if ((SeccompFlags & Seccomp::NETWORK) != 0)
280  {
281  ALLOW(bind);
282  ALLOW(connect);
283  ALLOW(getsockname);
284  ALLOW(getsockopt);
285  ALLOW(recv);
286  ALLOW(recvfrom);
287  ALLOW(recvmmsg);
288  ALLOW(recvmmsg_time64);
289  ALLOW(recvmsg);
290  ALLOW(send);
291  ALLOW(sendmmsg);
292  ALLOW(sendmsg);
293  ALLOW(sendto);
294  ALLOW(setsockopt);
295  ALLOW(shutdown);
296  ALLOW(socket);
297  ALLOW(socketcall);
298  }
299 
300  if ((SeccompFlags & Seccomp::DIRECTORY) != 0)
301  {
302  ALLOW(readdir);
303  ALLOW(getdents);
304  ALLOW(getdents64);
305  }
306 
307  if (getenv("FAKED_MODE"))
308  {
309  ALLOW(semop);
310  ALLOW(semget);
311  ALLOW(msgsnd);
312  ALLOW(msgrcv);
313  ALLOW(msgget);
314  ALLOW(msgctl);
315  ALLOW(ipc);
316  }
317 
318  for (auto &custom : _config->FindVector("APT::Sandbox::Seccomp::Allow"))
319  {
320  if ((rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, seccomp_syscall_resolve_name(custom.c_str()), 0)))
321  return _error->FatalE("aptMethod::Configuration", "Cannot allow %s: %s", custom.c_str(), strerror(-rc));
322  }
323 
324 #undef ALLOW
325 
326  rc = seccomp_load(ctx);
327  if (rc == -EINVAL)
328  {
329  std::string msg;
330  strprintf(msg, "aptMethod::Configuration: could not load seccomp policy: %s", strerror(-rc));
331  Warning(std::move(msg));
332  }
333  else if (rc != 0)
334  return _error->FatalE("aptMethod::Configuration", "could not load seccomp policy: %s", strerror(-rc));
335 
336  if (_config->FindB("APT::Sandbox::Seccomp::Print", true))
337  {
338  struct sigaction action;
339  memset(&action, 0, sizeof(action));
340  sigemptyset(&action.sa_mask);
341  action.sa_sigaction = [](int, siginfo_t *info, void *) {
342  // Formats a number into a 10 digit ASCII string
343  char buffer[10];
344  int number = info->si_syscall;
345 
346  for (int i = sizeof(buffer) - 1; i >= 0; i--)
347  {
348  buffer[i] = (number % 10) + '0';
349  number /= 10;
350  }
351 
352  constexpr const char *str1 = "\n **** Seccomp prevented execution of syscall ";
353  constexpr const char *str2 = " on architecture ";
354  constexpr const char *str3 = " ****\n";
355 #ifdef __GNUC__
356 #pragma GCC diagnostic push
357 #pragma GCC diagnostic ignored "-Wunused-result"
358 #endif
359  write(2, str1, strlen(str1));
360  write(2, buffer, sizeof(buffer));
361  write(2, str2, strlen(str2));
362  write(2, COMMON_ARCH, strlen(COMMON_ARCH));
363  write(2, str3, strlen(str3));
364 #ifdef __GNUC__
365 #pragma GCC diagnostic pop
366 #endif
367  _exit(31);
368  };
369  action.sa_flags = SA_SIGINFO;
370 
371  sigaction(SIGSYS, &action, nullptr);
372  }
373 #endif
374  return true;
375  }
376 
377  bool CalculateHashes(FetchItem const * const Itm, FetchResult &Res) const APT_NONNULL(2)
378  {
379  Hashes Hash(Itm->ExpectedHashes);
380  FileFd Fd;
381  if (Fd.Open(Res.Filename, FileFd::ReadOnly) == false || Hash.AddFD(Fd) == false)
382  return false;
383  Res.TakeHashes(Hash);
384  return true;
385  }
386 
387  void Warning(std::string &&msg)
388  {
389  std::unordered_map<std::string, std::string> fields;
390  if (Queue != 0)
391  fields.emplace("URI", Queue->Uri);
392  else
393  fields.emplace("URI", "<UNKNOWN>");
394  if (not UsedMirror.empty())
395  fields.emplace("UsedMirror", UsedMirror);
396  fields.emplace("Message", std::move(msg));
397  SendMessage("104 Warning", std::move(fields));
398  }
399 
400  std::vector<std::string> methodNames;
401  void setPostfixForMethodNames(char const * const postfix) APT_NONNULL(2)
402  {
403  methodNames.erase(std::remove_if(methodNames.begin(), methodNames.end(), hasDoubleColon), methodNames.end());
404  decltype(methodNames) toAdd;
405  for (auto && name: methodNames)
406  toAdd.emplace_back(name + "::" + postfix);
407  std::move(toAdd.begin(), toAdd.end(), std::back_inserter(methodNames));
408  }
409  bool DebugEnabled() const
410  {
411  if (methodNames.empty())
412  return false;
413  auto const sni = std::find_if_not(methodNames.crbegin(), methodNames.crend(), hasDoubleColon);
414  if (unlikely(sni == methodNames.crend()))
415  return false;
416  auto const ln = methodNames[methodNames.size() - 1];
417  // worst case: all three are the same
418  std::string confln, confsn, confpn;
419  strprintf(confln, "Debug::Acquire::%s", ln.c_str());
420  strprintf(confsn, "Debug::Acquire::%s", sni->c_str());
421  auto const pni = sni->substr(0, sni->find('+'));
422  strprintf(confpn, "Debug::Acquire::%s", pni.c_str());
423  return _config->FindB(confln,_config->FindB(confsn, _config->FindB(confpn, false)));
424  }
425  std::string ConfigFind(char const * const postfix, std::string const &defValue) const APT_NONNULL(2)
426  {
427  for (auto name = methodNames.rbegin(); name != methodNames.rend(); ++name)
428  {
429  std::string conf;
430  strprintf(conf, "Acquire::%s::%s", name->c_str(), postfix);
431  auto const value = _config->Find(conf);
432  if (value.empty() == false)
433  return value;
434  }
435  return defValue;
436  }
437  std::string ConfigFind(std::string const &postfix, std::string const &defValue) const
438  {
439  return ConfigFind(postfix.c_str(), defValue);
440  }
441  bool ConfigFindB(char const * const postfix, bool const defValue) const APT_NONNULL(2)
442  {
443  return StringToBool(ConfigFind(postfix, defValue ? "yes" : "no"), defValue);
444  }
445  int ConfigFindI(char const * const postfix, int const defValue) const APT_NONNULL(2)
446  {
447  char *End;
448  std::string const value = ConfigFind(postfix, "");
449  auto const Res = strtol(value.c_str(), &End, 0);
450  if (value.c_str() == End)
451  return defValue;
452  return Res;
453  }
454 
455  bool TransferModificationTimes(char const * const From, char const * const To, time_t &LastModified) APT_NONNULL(2, 3)
456  {
457  if (strcmp(To, "/dev/null") == 0)
458  return true;
459 
460  struct stat Buf2;
461  if (lstat(To, &Buf2) != 0 || S_ISLNK(Buf2.st_mode))
462  return true;
463 
464  struct stat Buf;
465  if (stat(From, &Buf) != 0)
466  return _error->Errno("stat",_("Failed to stat"));
467 
468  // we don't use utimensat here for compatibility reasons: #738567
469  struct timeval times[2];
470  times[0].tv_sec = Buf.st_atime;
471  LastModified = times[1].tv_sec = Buf.st_mtime;
472  times[0].tv_usec = times[1].tv_usec = 0;
473  if (utimes(To, times) != 0)
474  return _error->Errno("utimes",_("Failed to set modification time"));
475  return true;
476  }
477 
478  // This is a copy of #pkgAcqMethod::Dequeue which is private & hidden
479  void Dequeue()
480  {
481  FetchItem const *const Tmp = Queue;
482  Queue = Queue->Next;
483  if (Tmp == QueueBack)
484  QueueBack = Queue;
485  delete Tmp;
486  }
487  static std::string URIEncode(std::string const &part)
488  {
489  // The "+" is encoded as a workaround for an S3 bug (LP#1003633 and LP#1086997)
490  return QuoteString(part, _config->Find("Acquire::URIEncode", "+~ ").c_str());
491  }
492 
493  static std::string DecodeSendURI(std::string const &part)
494  {
495  if (_config->FindB("Acquire::Send-URI-Encoded", false))
496  return DeQuoteString(part);
497  return part;
498  }
499 
500  aptMethod(std::string &&Binary, char const *const Ver, unsigned long const Flags) APT_NONNULL(3)
502  {
503  try {
504  std::locale::global(std::locale(""));
505  } catch (...) {
506  setlocale(LC_ALL, "");
507  }
508  }
509 };
511 {
512  std::vector<std::unique_ptr<FileFd>> authconfs;
513 
514  public:
515  virtual bool Configuration(std::string Message) APT_OVERRIDE
516  {
517  if (pkgAcqMethod::Configuration(Message) == false)
518  return false;
519 
520  std::string const conf = std::string("Binary::") + Binary;
521  _config->MoveSubTree(conf.c_str(), NULL);
522 
523  // ignore errors with opening the auth file as it doesn't need to exist
524  _error->PushToStack();
525  auto const netrc = _config->FindFile("Dir::Etc::netrc");
526  if (netrc.empty() == false)
527  {
528  authconfs.emplace_back(new FileFd());
529  authconfs.back()->Open(netrc, FileFd::ReadOnly);
530  }
531 
532  auto const netrcparts = _config->FindDir("Dir::Etc::netrcparts");
533  if (netrcparts.empty() == false)
534  {
535  for (auto &&netrcpart : GetListOfFilesInDir(netrcparts, "conf", true, true))
536  {
537  authconfs.emplace_back(new FileFd());
538  authconfs.back()->Open(netrcpart, FileFd::ReadOnly);
539  }
540  }
541  _error->RevertToStack();
542 
543  DropPrivsOrDie();
544 
545  if (LoadSeccomp() == false)
546  return false;
547 
548  return true;
549  }
550 
551  bool MaybeAddAuthTo(URI &uri)
552  {
553  bool result = true;
554 
555  if (uri.User.empty() == false || uri.Password.empty() == false)
556  return true;
557 
558  _error->PushToStack();
559  for (auto &authconf : authconfs)
560  {
561  if (authconf->IsOpen() == false)
562  continue;
563  if (authconf->Seek(0) == false)
564  {
565  result = false;
566  continue;
567  }
568 
569  result &= MaybeAddAuth(*authconf, uri);
570  }
571 
572  while (not _error->empty())
573  {
574  std::string message;
575  _error->PopMessage(message);
576  Warning(std::move(message));
577  }
578  _error->RevertToStack();
579 
580  return result;
581  }
582 
583  aptAuthConfMethod(std::string &&Binary, char const *const Ver, unsigned long const Flags) APT_NONNULL(3)
584  : aptMethod(std::move(Binary), Ver, Flags) {}
585 };
586 #endif
strprintf(m, msg, repo.c_str())
static char const *const msg
ResultState
Definition: aptmethod.h:35
static bool hasDoubleColon(std::string const &n)
Definition: aptmethod.h:41
void MoveSubTree(char const *const OldRoot, char const *const NewRoot)
std::vector< std::string > FindVector(const char *Name, std::string const &Default="", bool const Keys=false) const
std::string Find(const char *Name, const char *Default=0) const
bool FindB(const char *Name, bool const &Default=false) const
std::string FindDir(const char *Name, const char *Default=0) const
std::string FindFile(const char *Name, const char *Default=0) const
Definition: fileutl.h:39
@ ReadOnly
Definition: fileutl.h:59
bool Open(std::string FileName, unsigned int const Mode, CompressMode Compress, unsigned long const AccessMode=0666)
Definition: fileutl.cc:2415
Definition: hashes.h:170
bool AddFD(int const Fd, unsigned long long Size=0)
Definition: hashes.cc:362
Definition: strutl.h:193
std::string User
Definition: strutl.h:199
std::string Password
Definition: strutl.h:200
aptAuthConfMethod(std::string &&Binary, char const *const Ver, unsigned long const Flags) APT_NONNULL(3)
Definition: aptmethod.h:583
std::vector< std::unique_ptr< FileFd > > authconfs
Definition: aptmethod.h:512
virtual bool Configuration(std::string Message) APT_OVERRIDE
Definition: aptmethod.h:515
bool MaybeAddAuthTo(URI &uri)
Definition: aptmethod.h:551
void Warning(std::string &&msg)
Definition: aptmethod.h:387
std::string ConfigFind(std::string const &postfix, std::string const &defValue) const
Definition: aptmethod.h:437
std::string ConfigFind(char const *const postfix, std::string const &defValue) const APT_NONNULL(2)
Definition: aptmethod.h:425
bool DebugEnabled() const
Definition: aptmethod.h:409
unsigned long SeccompFlags
Definition: aptmethod.h:50
bool struct stat Buf2
Definition: aptmethod.h:460
std::vector< std::string > methodNames
Definition: aptmethod.h:400
bool CalculateHashes(FetchItem const *const Itm, FetchResult &Res) const APT_NONNULL(2)
Definition: aptmethod.h:377
bool ConfigFindB(char const *const postfix, bool const defValue) const APT_NONNULL(2)
Definition: aptmethod.h:441
virtual bool Configuration(std::string Message) APT_OVERRIDE
Definition: aptmethod.h:59
void Dequeue()
Definition: aptmethod.h:479
static std::string URIEncode(std::string const &part)
Definition: aptmethod.h:487
bool RunningInQemu(void)
Definition: aptmethod.h:74
bool LoadSeccomp()
Definition: aptmethod.h:102
void setPostfixForMethodNames(char const *const postfix) APT_NONNULL(2)
Definition: aptmethod.h:401
std::string const Binary
Definition: aptmethod.h:49
struct timeval times[2]
Definition: aptmethod.h:469
bool TransferModificationTimes(char const *const From, char const *const To, time_t &LastModified) APT_NONNULL(2
int ConfigFindI(char const *const postfix, int const defValue) const APT_NONNULL(2)
Definition: aptmethod.h:445
@ DIRECTORY
Definition: aptmethod.h:55
aptMethod(std::string &&Binary, char const *const Ver, unsigned long const Flags) APT_NONNULL(3)
Definition: aptmethod.h:500
static std::string DecodeSendURI(std::string const &part)
Definition: aptmethod.h:493
struct stat Buf
Definition: aptmethod.h:464
std::string UsedMirror
virtual bool Configuration(std::string Message)
FetchItem * QueueBack
void DropPrivsOrDie()
FetchItem * Queue
void SendMessage(std::string const &header, std::unordered_map< std::string, std::string > &&fields)
Configuration * _config
std::vector< string > GetListOfFilesInDir(string const &Dir, string const &Ext, bool const &SortList, bool const &AllowNoExt)
Definition: fileutl.cc:421
#define APT_OVERRIDE
Definition: macros.h:111
#define APT_NONNULL(...)
Definition: macros.h:67
bool MaybeAddAuth(FileFd &NetRCFile, URI &Uri)
Definition: netrc.cc:26
int StringToBool(const string &Text, int Default)
Definition: strutl.cc:820
string DeQuoteString(const string &Str)
Definition: strutl.cc:404
string QuoteString(const string &Str, const char *Bad)
Definition: strutl.cc:384