1 /* chroot LD_PRELOAD wrapper to safely chroot any application
2  *
3  * (C) 2004 Henrik Nordstrom <hno@marasystems.com>
4  *
5  *  Permission is hereby granted, free of charge, to any person obtaining
6  *  a copy of this software and associated documentation files (the
7  *  "Software"), to deal in the Software without restriction, including
8  *  without limitation the rights to use, copy, modify, merge, publish,
9  *  distribute, sublicense, and/or sell copies of the Software, and to
10  *  permit persons to whom the Software is furnished to do so, subject
11  *  to the following conditions:
12  *
13  *  The above copyright notice and this permission notice shall be
14  *  included in all copies or substantial portions of the Software.
15  *
16  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20  *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21  *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22  *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * Usage:
25  *
26  *  This application is used as a LD_PRELOAD library to make any shared
27  *  executable chroot itself and drop privileges in a safe manner after
28  *  any dynamic linking has taken place.
29  *
30  *  A number of environment variables is used to control how the
31  *  application is chrooted:
32  *
33  *  CHROOT_ROOT   The path to where the application is to be chrooted
34  *                (required)
35  *
36  *  CHROOT_USER   The user to run the application as (defaults to "nobody"
37  *                if not defined)
38  *
39  *  LD_PRELOAD    Must include this application
40  *
41  * Diagnostics:
42  *
43  *  If there is any problem chrooting the application an error message is
44  *  printed on stderr, and execution of the application is terminated.
45  *
46  * Compiling:
47  *
48  *  g++ -fpic -shared -o chroot_safe.so chroot_safe.cpp
49  *
50  * Suggested use:
51  *
52  *  #!/bin/sh
53  *  if [ $# -lt 3 ]; then
54  *    echo "Usage: $0 user root application ..." >&2
55  *    exit 1
56  *  fi
57  *  CHROOT_USER="$1"; export CHROOT_USER
58  *  CHROOT_ROOT="$2"; export CHROOT_ROOT
59  *  shift ; shift
60  *  LD_PRELOAD="/path/to/chroot_safe.so"; export LD_PRELOAD
61  *  exec "$@"
62  */
63 
64 #include <sys/types.h>
65 #include <unistd.h>
66 #include <grp.h>
67 #include <pwd.h>
68 #include <string.h>
69 #include <stdlib.h>
70 #include <errno.h>
71 
72 class automatic_chroot {
73     private:
failure(char * msg)74 	static void failure(char *msg) {
75 	    char *error = strerror(errno);
76 	    write(2, msg, strlen(msg));
77 	    if (errno != 0) {
78 		write(2, ": ", 2);
79 		write(2, error, strlen(error));
80 	    }
81 	    write(2, "\n", 1);
82 	    _exit(1);
83 	}
84     public:
automatic_chroot()85 	automatic_chroot() {
86 	    unsetenv("LD_PRELOAD");
87 	    char *root = getenv("CHROOT_ROOT");
88 	    if (root == NULL)
89 		failure("CHROOT_ROOT not defined");
90 	    char *user = getenv("CHROOT_USER");
91 	    if (user == NULL)
92 		user = "nobody";
93 	    struct passwd *pwd = getpwnam(user);
94 	    if (pwd == NULL)
95 		failure("User not found in /etc/passwd");
96 	    if (setgid(pwd->pw_gid))
97 		failure("setgid failure");
98 	    if (initgroups(user, pwd->pw_gid))
99 		failure("initgroups failure");
100 	    if (chdir(root))
101 		failure("chdir failure");
102 	    if (chroot("."))
103 		failure("chroot failure");
104 	    if (setuid(pwd->pw_uid))
105 		failure("setresuid failure");
106 	    unsetenv("CHROOT_ROOT");
107 	    unsetenv("CHROOT_USER");
108 	}
109 };
110 
111 static class automatic_chroot do_chroot;
112