{"id":24,"date":"2009-09-29T13:30:44","date_gmt":"2009-09-29T12:30:44","guid":{"rendered":"http:\/\/paguilar.org\/?p=24"},"modified":"2009-09-29T13:30:44","modified_gmt":"2009-09-29T12:30:44","slug":"creating-a-sandbox-or-jail-for-cross-compiling","status":"publish","type":"post","link":"https:\/\/paguilar.org\/?p=24","title":{"rendered":"Creating a sandbox or jail for cross-compiling"},"content":{"rendered":"<p>When cross-compiling dynamic libraries like GTK+ we normally have a couple of issues that complicate the compilation and later the execution of apps that depend on those libraries.<br \/>\nFirst, we have to be very careful with the includes <em>-I<\/em> and libraries <em>-L<\/em> paths since they must point to the target, otherwise we risk to overwrite the host files.<br \/>\nSecond, after compiling we normally end up with libraries and\/or apps that require the whole path that we used during the process.<br \/>\nFor example, if we installed GTK+ in our target&#8217;s filesystem, let&#8217;s say <em>\/opt\/STM\/STLinux-2.3\/devkit\/sh4\/target\/usr\/local<\/em>, then when we execute an app in the target that is dynamically linked to GTK+, it will search the libraries in that path, instead of <em>\/usr\/local<\/em>.<br \/>\nThis issue can be solved creating ugly symbolic links or modifying the .la files, but neither of them are a clean\/good solution.<\/p>\n<p>One method for completely eliminating these problems is to cross-compile in a protected environment in which we can install, modify and remove files without causing any damage.<br \/>\nSuch an environment is called a jail or sandbox.<\/p>\n<p>There are several ways for implementing a sandbox (like the jail package for Debian),<br \/>\nbut the procedure shown below is quite simple and illustrates how a sandbox works.<\/p>\n<p>There are two main concepts behind a sandbox: <strong>chroot<\/strong> and <strong>unionfs<\/strong>.<br \/>\nchroot changes the root directory of the calling process to another specified in the given path. This directory will be used for pathnames beginning with <em>\/<\/em>. The new root directory is inherited by all children of the calling process.<br \/>\nUnionfs gives the possibility of creating a filesystem that is the union of at least two others. For example, consider that the new unionfs is the union of our host&#8217;s root filesytem mounted in read-only mode, and of a temporary filesystem mounted in read-write mode.<br \/>\nThe result is a filesystem which looks exactly like the host&#8217;s root filesystem,<br \/>\nbut in which you can install, modify and\/or delete files without touching anything in the root filesystem.<\/p>\n<p>The following procedure and script show step by step how to create the sandbox:<\/p>\n<p>First we create a dedicated user that will have read\/write access to the sandbox.<br \/>\nYou can do it with any graphical interface or using the shell:<\/p>\n<pre lang=\"bash\">\n$ adduser sandbox\n<\/pre>\n<p>Give sudo permissions to this user.<br \/>\nWARNING: Under some circumstances this is not safe, but in our case in which we just<br \/>\nwant to cross-compile it&#8217;s sufficient.<\/p>\n<pre lang=\"bash\">\n$ sudoedit \/etc\/sudoers\n\nAdd the following line at the end of the sudoers file:\n    sandbox ALL=(ALL) ALL \n<\/pre>\n<p>Set the default shell, that is the last token in a line of the <em>\/etc\/passwd<\/em> file, of the sandbox user to the script <em>\/bin\/sandbox.sh<\/em> that is explained later:<\/p>\n<pre lang=\"bash\">\nsandbox:x:1001:1001:sandbox user,,,:\/home\/sandbox:\/bin\/sandbox.sh\n<\/pre>\n<p>Now we create the temporary filesystem.<\/p>\n<p>Create a 1GB file called sandbox.img filled with zeroes:<\/p>\n<pre lang=\"bash\">\n$ dd if=\/dev\/zero of=\/opt\/sandbox.img bs=1M count=1000\n<\/pre>\n<p>Create an ext3 filesystem in that file:<\/p>\n<pre lang=\"bash\">\n$ mkfs.ext3 \/opt\/sandbox.img\n<\/pre>\n<p>Create the empty temporary directory:<\/p>\n<pre lang=\"bash\">\n$ mkdir \/opt\/sandbox\n<\/pre>\n<p>Mount the ext3 formatted file filled with zeroes in the empty directory:<\/p>\n<pre lang=\"bash\">\n$ mount -o loop \/opt\/sandbox.img \/opt\/sandbox\n<\/pre>\n<p>Change it&#8217;s permissions so everybody can read\/write to\/from it.<\/p>\n<pre lang=\"bash\">\n$ chmod 777 \/opt\/sandbox\n<\/pre>\n<p>Create the directory \/opt\/unionfs<\/p>\n<pre lang=\"bash\">\n$ mkdir \/opt\/unionfs\n<\/pre>\n<p>In the <em>\/opt\/unionfs<\/em> directory we will mount the zeroed ext3 filesystem altogether with the host&#8217;s root filesystem taking advantage of the unionfs.<br \/>\nThis operation takes place in the \/bin\/sandbox.sh script that will be executed each time<br \/>\nwe log in as the sandbox user:<\/p>\n<p>In the function <em>mount_unionfs()<\/em> in which we take one element of the mdirs list at a time, we mount the unionfs filesystem that is the union of the zeroed ext3 filesystem and the host&#8217;s root filesystem mounted in read only mode. This is the most important part of the mounting procedure.<br \/>\nThen we mount in the unionfs the necessary filesystem for having a working system such as <em>\/dev<\/em>, <em>\/sys<\/em>, <em>\/proc<\/em> and <em>\/tmp<\/em><br \/>\nThe last element is the path of the cross-toolchain that can vary.<br \/>\nEg. The openmoko toolchain is located in <em>\/usr\/local\/openmoko\/arm\/bin<\/em><br \/>\nwhilst the STM toolchain for the sh4 arch is located in <em>\/opt\/STM\/STLinux-2.3\/devkit\/sh4\/bin<\/em><\/p>\n<p>The chroot command is the other important part: it changes the root from <em>\/<\/em> to <em>\/opt\/unionfs<\/em> executing the <em>su<\/em> command that contains the <em>&#8211;shell<\/em> and <em>&#8211;login<\/em> parameters.<\/p>\n<p>At this point we&#8217;re logged in as the user sandbox in a safe filesystem that is the union of<br \/>\nthe host&#8217;s filesystem and the empty ext3 filesystem. What we see in the unionfs is the host&#8217;s filesystem that was mounted in read-only mode:<\/p>\n<pre lang=\"bash\">\n$ ls \/\nboot dev    initrd.img  lib     media       opt  root  selinux  sys  usr  vmlinuz\nbin  cdrom  etc         home    lost+found  mnt  proc  sbin     srv  tmp  var\n<\/pre>\n<p>and we can happily start compiling libraries like GTK+ in default paths such as <em>\/usr\/local<\/em> without risking our host filesystem integrity.<\/p>\n<p>After compilation, we can log out and check out the compilation results in <em>\/opt\/sandbox<\/em><br \/>\nWe&#8217;ll see something like this:<\/p>\n<pre lang=\"bash\">\n$ ls \/opt\/sandbox\/\ngtkdfb  lost+found  usr  var\n<\/pre>\n<p>Before we logged in as the sandbox user this directory was empty (lost+found is not considered), but now it contains three new directories: the gtkdfb contains all the GTK+ sources that we compiled.<br \/>\nThe var directory contains the cache and run with temporal information that was different than the one in the host filesystem.<br \/>\nThe usr directory contains the local directory with all the libraries, includes, shares and everything that was generated as a result of the GTK+ compilation:<\/p>\n<pre lang=\"bash\">\n$ ls \/opt\/sandbox\/usr\/local\/\nbin  etc  include  lib  share  var\n<\/pre>\n<p>Now we can safely copy this directoy to our <em>\/usr\/local\/<\/em> of the target filesystem!<br \/>\nThis avoids ugly logical links or other dirty solutions.<\/p>\n<p>Finally, the function <em>umount_unionfs()<\/em> does the same steps as the <em>mount_unionfs()<\/em> function<br \/>\nbut in reverse order. This is executed when the user sandbox logs out.<\/p>\n<p>Here&#8217;s the script:<\/p>\n<pre lang=\"bash\">\n#!\/bin\/bash\n\n# Mount a source directory or fs type $i in destination mount point $j \n# using options $k\n#\n#     i               j                  k\nmdirs=( \n  \"unionfs\"   \"\/opt\/unionfs\"         \"-t unionfs -o dirs=\/opt\/sandbox:\/=ro\"\n  \"\/dev\"      \"\/opt\/unionfs\/dev\"     \"--bind\"\n  \"devpts\"    \"\/opt\/unionfs\/dev\/pts\" \"-t devpts\"\n  \"shm\"       \"\/opt\/unionfs\/dev\/shm\" \"-t tmpfs\"\n  \"sysfs\"     \"\/opt\/unionfs\/sys\"     \"-t sysfs\"\n  \"proc\"      \"\/opt\/unionfs\/proc\"    \"-t proc\"\n  \"\/tmp\"      \"\/opt\/unionfs\/tmp\"     \"--bind\"\n  \"\/dev\/sda6\" \"\/opt\/unionfs\/opt\"     \"-t ext3\"\n      )\n\nmount_unionfs()\n{\n    mdir_size=${#mdirs[*]}\n\n    i=0; j=1; k=2\n    while [ \"$i\" -lt \"$mdir_size\" ]; do\n        if [ -z \"$(mount | grep -w ${mdirs[$j]})\" ]; then\n            echo \"Mounting ${mdirs[$j]}\"\n            sudo \/bin\/mount ${mdirs[$k]} ${mdirs[$i]} ${mdirs[$j]}\n        fi\n        i=$((i + 3)); j=$((j + 3)); k=$((k + 3))\n    done\n}\n\numount_unionfs()\n{\n    mdir_size=${#mdirs[*]}\n\n    j=$((mdir_size - 2))\n    while [ \"$j\" -gt \"0\" ]; do\n        if [ -n \"$(mount | grep -w ${mdirs[$j]})\" ]; then\n            echo \"Umounting ${mdirs[$j]}\"\n            sudo \/bin\/umount ${mdirs[$j]} 2> \/dev\/null\n        fi\n        j=$((j - 3))\n    done\n}\n\nmount_unionfs\n\nsudo \/usr\/sbin\/chroot \/opt\/unionfs \/bin\/su --shell \/bin\/bash --login $USER\n\numount_unionfs\n<\/pre>\n<p>References:<br \/>\nchroot info page<br \/>\n<a href=\"http:\/\/www.filesystems.org\/project-unionfs.html\">http:\/\/www.filesystems.org\/project-unionfs.html<\/a><br \/>\n<a href=\"http:\/\/www.howtoforge.com\/safe_mirror_unionfs_chroot\">http:\/\/www.howtoforge.com\/safe_mirror_unionfs_chroot<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>When cross-compiling dynamic libraries like GTK+ we normally have a couple of issues that complicate the compilation and later the execution of apps that depend on those libraries. First, we have to be very careful with the includes -I and libraries -L paths since they must point to the target, otherwise we risk to overwrite\u2026 <span class=\"read-more\"><a href=\"https:\/\/paguilar.org\/?p=24\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,6,10],"tags":[18,22,32,42],"class_list":["post-24","post","type-post","status-publish","format-standard","hentry","category-command-line-interface","category-compiling","category-gtk","tag-chroot","tag-cross-compiling","tag-sandbox","tag-unionfs"],"_links":{"self":[{"href":"https:\/\/paguilar.org\/index.php?rest_route=\/wp\/v2\/posts\/24","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/paguilar.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/paguilar.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/paguilar.org\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/paguilar.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=24"}],"version-history":[{"count":0,"href":"https:\/\/paguilar.org\/index.php?rest_route=\/wp\/v2\/posts\/24\/revisions"}],"wp:attachment":[{"href":"https:\/\/paguilar.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=24"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/paguilar.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=24"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/paguilar.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=24"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}