{"id":8611,"date":"2020-09-30T14:56:27","date_gmt":"2020-09-30T14:56:27","guid":{"rendered":"http:\/\/www.max-sperling.bplaced.net\/?p=8611"},"modified":"2024-02-16T10:34:53","modified_gmt":"2024-02-16T10:34:53","slug":"chroot-part-2-mount-ns-linux","status":"publish","type":"post","link":"http:\/\/www.max-sperling.bplaced.net\/?p=8611","title":{"rendered":"Sandboxing (Linux)"},"content":{"rendered":"<p>There are multiple possibilities with Linux to sandbox applications.<\/p>\n<ul>\n<li>chroot &#8230; Changed file system root<\/li>\n<li>namespaces &#8230; Separated namespaces (e.g. Mount table)<\/li>\n<li>cgroups &#8230; Restricted resources (e.g. Memory)<\/li>\n<\/ul>\n<hr>\n<p><strong>Example<\/strong> (with changed system root)<\/p>\n<pre class=\"brush: cpp; gutter: false; title: main.cpp; notranslate\" title=\"main.cpp\">\r\n#include &lt;filesystem&gt;\r\n#include &lt;iostream&gt;\r\n#include &lt;vector&gt;\r\n\r\n#include &lt;errno.h&gt;\r\n#include &lt;fcntl.h&gt;\r\n#include &lt;string.h&gt;\r\n#include &lt;unistd.h&gt;\r\n\r\n#include &lt;sys\/mount.h&gt;\r\n#include &lt;sys\/types.h&gt;\r\n#include &lt;sys\/wait.h&gt;\r\n\r\nnamespace sfs = std::filesystem;\r\n\r\nvoid mountDeps(std::string&amp; chrootPath, std::vector&lt;std::string&gt;&amp; deps);\r\nvoid unmountDeps(std::string&amp; chrootPath, std::vector&lt;std::string&gt;&amp; deps);\r\nvoid startApp(std::string&amp; chrootPath, std::vector&lt;std::string&gt;&amp; deps);\r\nvoid changeRoot(std::string&amp; chrootPath);\r\n\r\nint main()\r\n{\r\n  std::vector&lt;std::string&gt; deps = { &quot;child.out&quot;, &quot;\/lib&quot;, &quot;\/lib64&quot; };\r\n  std::string chrootPath = &quot;\/tmp\/chroot\/&quot;;\r\n\r\n  sfs::create_directory(chrootPath);\r\n  mountDeps(chrootPath, deps);\r\n\r\n  startApp(chrootPath, deps);\r\n\r\n  unmountDeps(chrootPath, deps);\r\n  sfs::remove_all(chrootPath);\r\n\r\n  return 0;\r\n}\r\n\r\nvoid mountDeps(std::string&amp; chrootPath, std::vector&lt;std::string&gt;&amp; deps)\r\n{\r\n  for (std::string&amp; dep : deps)\r\n  {\r\n    std::string dest = chrootPath + dep;\r\n\r\n    if (sfs::is_directory(dep)) { sfs::create_directory(dest); }\r\n    else { close(open(dest.c_str(), O_WRONLY | O_CREAT, 0755)); }\r\n\r\n    if (mount(dep.c_str(), dest.c_str(), &quot;&quot;, MS_BIND, &quot;&quot;))\r\n    {\r\n      std::cerr &lt;&lt; &quot;Bind mounting from &quot; &lt;&lt; dep &lt;&lt; &quot; to &quot; &lt;&lt; dest &lt;&lt;\r\n                   &quot; failed: &quot; &lt;&lt; strerror(errno) &lt;&lt; std::endl;\r\n    }\r\n  }\r\n}\r\n\r\nvoid unmountDeps(std::string&amp; chrootPath, std::vector&lt;std::string&gt;&amp; deps)\r\n{\r\n  for (std::string&amp; dep : deps)\r\n  {\r\n    std::string dest = chrootPath + dep;\r\n\r\n    if (umount2(dest.c_str(), MNT_DETACH))\r\n    {\r\n      std::cerr &lt;&lt; &quot;Unmounting of &quot; &lt;&lt; dest &lt;&lt;\r\n                   &quot; failed: &quot; &lt;&lt; strerror(errno) &lt;&lt; std::endl;\r\n    }\r\n\r\n    sfs::remove_all(dest);\r\n  }\r\n}\r\n\r\nvoid startApp(std::string&amp; chrootPath, std::vector&lt;std::string&gt;&amp; deps)\r\n{\r\n  pid_t pid = fork();\r\n\r\n  switch (pid)\r\n  {\r\n    case -1:\r\n      \/* Couldn&#039;t fork *\/\r\n      {\r\n        std::cerr &lt;&lt; &quot;Couldn&#039;t fork&quot; &lt;&lt; std::endl;\r\n      }\r\n      break;\r\n    case 0:\r\n      \/* Child process *\/\r\n      {\r\n          changeRoot(chrootPath);\r\n\r\n          std::string execFile = &quot;.\/&quot; + deps[0];\r\n          if (execlp(execFile.c_str(), execFile.c_str(), NULL) == -1)\r\n          {\r\n            std::cerr &lt;&lt; &quot;Execution of &quot; &lt;&lt; deps[0] &lt;&lt; &quot; failed: &quot;\r\n                      &lt;&lt; strerror(errno) &lt;&lt; std::endl;\r\n          }\r\n          \/\/ The child is gone now\r\n      }\r\n      break;\r\n    default:\r\n      \/* Parent process *\/\r\n      {\r\n        std::cout &lt;&lt; &quot;Parent: I put my child in a sandbox&quot; &lt;&lt; std::endl;\r\n        waitpid(pid, NULL, 0);\r\n      }\r\n      break;\r\n  }\r\n}\r\n\r\nvoid changeRoot(std::string&amp; chrootPath)\r\n{\r\n  if (chroot(chrootPath.c_str()) == -1)\r\n  {\r\n    std::cerr &lt;&lt; &quot;Chroot to &quot; &lt;&lt; chrootPath &lt;&lt; &quot; failed: &quot;\r\n              &lt;&lt; strerror(errno) &lt;&lt; std::endl;\r\n  }\r\n\r\n  if (chdir(&quot;\/&quot;) == -1)\r\n  {\r\n    std::cerr &lt;&lt; &quot;Chdir to root failed: &quot;\r\n              &lt;&lt; strerror(errno) &lt;&lt; std::endl;\r\n  }\r\n}\r\n<\/pre>\n<pre class=\"brush: cpp; gutter: false; title: child.cpp; notranslate\" title=\"child.cpp\">\r\n#include &lt;filesystem&gt;\r\n#include &lt;fstream&gt;\r\n#include &lt;iostream&gt;\r\n\r\nnamespace sfs = std::filesystem;\r\n\r\nint main()\r\n{\r\n  std::cout &lt;&lt; &quot;Child: Let&#039;s check the root:&quot;;\r\n  for (auto&amp; entry : sfs::directory_iterator(&quot;\/&quot;))\r\n  {\r\n    std::cout &lt;&lt; &quot; &quot; &lt;&lt; entry.path();\r\n  }\r\n  std::cout &lt;&lt; std::endl;\r\n\r\n  std::cout &lt;&lt; &quot;Child: Oh shit, I have to play in a sandbox&quot; &lt;&lt; std::endl;\r\n\r\n  return 0;\r\n}\r\n<\/pre>\n<pre>\r\n$ g++ child.cpp -o child.out\r\n\r\n$ ldd child.out\r\nlinux-vdso.so.1 (0x00007ffcc8375000)\r\nlibstdc++.so.6 => \/lib\/x86_64-linux-gnu\/libstdc++.so.6 (0x00007f50bb800000)\r\nlibc.so.6 => \/lib\/x86_64-linux-gnu\/libc.so.6 (0x00007f50bb400000)\r\nlibm.so.6 => \/lib\/x86_64-linux-gnu\/libm.so.6 (0x00007f50bb715000)\r\n\/lib64\/ld-linux-x86-64.so.2 (0x00007f50bbb1e000)\r\nlibgcc_s.so.1 => \/lib\/x86_64-linux-gnu\/libgcc_s.so.1 (0x00007f50bbae3000)\r\n\r\n$ g++ main.cpp -o main.out\r\n\r\n$ sudo .\/main.out\r\nParent: I put my child in a sandbox\r\nChild: Let's check the root: \"\/child.out\" \"\/lib\" \"\/lib64\"\r\nChild: Oh shit, I have to play in a sandbox\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>There are multiple possibilities with Linux to sandbox applications. chroot &#8230; Changed file system root namespaces &#8230; Separated namespaces (e.g.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false},"categories":[65],"tags":[],"_links":{"self":[{"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/posts\/8611"}],"collection":[{"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=8611"}],"version-history":[{"count":10,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/posts\/8611\/revisions"}],"predecessor-version":[{"id":16424,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=\/wp\/v2\/posts\/8611\/revisions\/16424"}],"wp:attachment":[{"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=8611"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=8611"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.max-sperling.bplaced.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=8611"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}