Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>If the files you need to access are within a few directories you could open those directories <em>before</em> you chroot and save the file descriptors. You can then use the so-called *at functions (e.g. <a href="http://www.linux.com/learn/docs/man/3710-openat2" rel="nofollow noreferrer">openat()</a>, <a href="http://www.linux.com/learn/docs/man/3909-renameat2" rel="nofollow noreferrer">renameat()</a>, etc.) to get at the individual files. Basically you are opening the files <em>relative</em> to the already open directory file descriptors rather than the chrooted directory. </p> <p>Whether this is a safe thing to do is open to question but it should work in Linux.</p> <p><strong>EDIT:</strong> This is on the ugly side but it seems to work. You should poke around a lot more for vulnerabilities than I have. I haven't tested how dropping privileges and so forth will effect things. </p> <pre><code>#include &lt;iostream&gt; #include &lt;string&gt; using namespace std; #include &lt;cstdio&gt; #include &lt;cstdlib&gt; #include &lt;cerrno&gt; #include &lt;cstring&gt; #include &lt;unistd.h&gt; #include &lt;fcntl.h&gt; #include &lt;dirent.h&gt; #include &lt;sys/types.h&gt; #include &lt;sys/stat.h&gt; int main(int argc, char *argv[]) { if (argc &lt; 4) { cerr &lt;&lt; "USAGE: " &lt;&lt; argv[0] &lt;&lt; " &lt;jail directory&gt; &lt;freeworld directory&gt; &lt;filename&gt;\n"; exit(EXIT_FAILURE); } const string JAILDIR(argv[1]); const string FREEDIR(argv[2]); string freefilename(argv[3]); while (freefilename[0] == '/') freefilename.erase(0, 1); DIR *pDir; if ((pDir = opendir(FREEDIR.c_str())) == NULL) { perror("Could not open outside dir"); exit(EXIT_FAILURE); } int freeFD = dirfd(pDir); //cd to jail dir if (chdir(JAILDIR.c_str()) == -1) { perror("cd before chroot"); exit(EXIT_FAILURE); } //lock in jail if (chroot(JAILDIR.c_str()) &lt; 0) { cerr &lt;&lt; "Failed to chroot to " &lt;&lt; JAILDIR &lt;&lt; " - " &lt;&lt; strerror(errno) &lt;&lt; endl; exit(EXIT_FAILURE); } // //in jail, won't work // string JailFile(FREEDIR); JailFile += "/"; JailFile += freefilename; int jailFD; if ((jailFD = open(JailFile.c_str(), O_RDONLY)) == -1) { cout &lt;&lt; "as expected, could not open " &lt;&lt; JailFile &lt;&lt; endl; perror("exected open fail"); } else { cout &lt;&lt; "defying all logic, opened " &lt;&lt; JailFile &lt;&lt; endl; exit(EXIT_FAILURE); } // //using this works // if ((jailFD = openat(freeFD, freefilename.c_str(), O_RDONLY)) == -1) { cout &lt;&lt; "example did not work. Could not open " &lt;&lt; freefilename &lt;&lt; " Sorry!" &lt;&lt; endl; exit(EXIT_FAILURE); } else cout &lt;&lt; "opened " &lt;&lt; freefilename &lt;&lt; " from inside jail" &lt;&lt; endl; char buff[255]; ssize_t numread; while (1) { if ((numread = read(jailFD, buff, sizeof(buff) - 1)) == -1) { perror("read"); exit(EXIT_FAILURE); } if (numread == 0) break; buff[numread] = '\0'; cout &lt;&lt; buff &lt;&lt; endl; } return 0; } </code></pre> <p>To test:</p> <p>echo "Hello World" >/tmp/mystuff.dat</p> <p>mkdir /tmp/jail</p> <p>sudo ./myprog /tmp/jail /tmp mystuff.dat</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload