Putting MySQL into a chroot jail (CentOS 6.4 x86_64)

Hi Everyone,

today I got the interesting project: take a vanilla CentOS 6.4, install a chrooted MySQL onto it. How hard can it be? As it turned out, it is tricky at least. Here’s how I did it:

First, I did a bog standard

yum install mysql-server

and then I started it

service mysqld start

this creates an empty database (actually, the mysql-required grant tables are in it), which I’ve given a new password:

/usr/bin/mysqladmin -u root password 'start123'

then I stopped the db again

service mysql stop

So, now you have a fresh database in /var/lib/mysql to use. Now I set up the chroot jail – I expected to have to install chroot with yum, but it is already included in the minimal CentOS install, yeah.

You’ll need to copy this 3 RPMs to the directory where your chroot is going to be: (I’m using /opt/mysql)


(the versions can differ, I think the most actual is the 5.1.69)

change into /opt/mysql and extract all 3 RPMs:

rpm2cpio mysql-server-5.1.66-2.el6_3.x86_64.rpm | cpio -idmv

You should now have 3 directories, etc, usr and var as subdirectories in /opt/mysql – but for the chroot jail to function, we’ll need some extra stuff, like… libraries?

Make these extra directories (under /opt/mysql)
bin, dev, lib, lib64, proc, sys, tmp
chmod 777 /opt/mysql/tmp
chown mysql:mysql /opt/mysql/var/run/mysqld
chown mysql:mysql /opt/mysql/var/lib/mysql
mkdir /home/chroot/home/chroot/var/log
mkdir -p /opt/mysql/opt/mysql/var/log

Copy these libraries from the system directories into lib64: (some you’ll find in /lib64, some in /usr/lib64) – sorry ūüėČ

ld-linux-x86-64.so.2  libcrypto.so.10  libgmp.so.3
libkrb5support.so.0   libnss_dns-2.12.so  libnss_nis-2.12.so
libpam_misc.so.0   libresolv.so.2   libz.so.1 libacl.so.1
libcrypt.so.1  libgssapi_krb5.so.2  libkrb5support.so.0.1
libnss_dns.so.2  libnss_nisplus-2.12.so  libpam_misc.so.0.82.0
librt.so.1 libattr.so.1  libc.so.6  libk5crypto.so.3
libm.so.6  libnss_files-2.12.so   libnss_nisplus.so.2
libpam.so.0  libselinux.so.1 libaudit.so.1  libdl.so.2
libkeyutils.so.1  libnsl.so.1  libnss_files.so.2
libnss_nis.so.2  libpam.so.0.82.2 libssl.so.10 libcap.so.2
libfreebl3.so    libkrb5.so.3   libnss_compat-2.12.so
libnss_hesiod-2.12.so  libpamc.so.0   libpcre.so.0
libstdc++.so.6 libcom_err.so.2       libgcc_s.so.1
libkrb5.so.3.3       libnss_compat.so.2     libnss_hesiod.so.2
libpamc.so.0.82.1       libpthread.so.0        libtinfo.so.5

Copy everything (may be unnecessary, but I was lazy) from /bin to /opt/mysql/bin, also dirname, expr and nohup from /usr/bin

cp -a /bin/* /opt/mysql/bin/
cp -a /usr/bin/expr /opt/mysql/usr/bin/
cp -a /usr/bin/dirname /opt/mysql/usr/bin/
cp -a /usr/bin/nohup /opt/mysql/usr/bin/

Next, it would be nice to have some system functions, do a few bind mounts in the fstab file:

/sys            /opt/mysql/sys         none    bind      0      0
/proc           /opt/mysql/proc        none    bind      0      0
/dev            /opt/mysql/dev         none    bind      0      0

Activate them with mount -a

Copy the user and group database files from the system’s etc into the jail:

cp /etc/passwd /opt/mysql/etc/
 cp /etc/group /opt/mysql/etc/
 cp /etc/nsswitch.conf /home/chroot/etc/
 cp /etc/localtime /home/chroot/etc/

Copy everything from /var/lib/mysql/ to /opt/mysql/var/lib/mysql/ – now you have a database to start with. Change into the new chroot jail and start the server:

chroot /opt/mysql
/usr/bin/mysqld_safe --chroot=/opt/mysql \
--datadir=/var/lib/mysql --socket=/var/run/mysqld/mysql.sock \
--pid-file=/var/run/mysqld/mysql.pid --basedir=/usr \
 --user=mysql > /dev/null 2>&1 &

[root@localhost log]# ps -ef | grep mysql
root      5328     1  0 09:55 pts/0    00:00:00 /bin/sh /usr/bin/mysqld_safe --datadir=/var/lib/mysql --socket=/var/lib/mysql/mysql.sock --pid-file=/var/run/mysqld/mysqld.pid --basedir=/usr --user=mysql
mysql     5419  5328  0 09:55 pts/0    00:00:00 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql --log-error=/var/log/mysqld.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/lib/mysql/mysql.sock

Now, to get the initscript to function properly, locate the following section in /etc/init.d/mysqld:

# alarms, per bug #547485
 $exec --datadir="$datadir" --socket="$socketfile" \
 --pid-file="$mypidfile" \
 --basedir=/usr --user=mysql >/dev/null 2>&1 &
 # Spin for a maximum of N seconds waiting for the server to come up;

And change it to:

# alarms, per bug #547485
 /usr/sbin/chroot /opt/mysql $exec --datadir="$datadir" --socket="$socketfile" \
 --pid-file="$mypidfile" \
 --basedir=/usr --user=mysql >/dev/null 2>&1 &
 ln -s /opt/mysql/var/lib/mysql/mysql.sock $datadir/mysql.sock 2>/dev/null
 ln -s /opt/mysql/var/run/mysqld/mysqld.pid /var/run/mysqld/mysqld.pid 2>/dev/null
 # Spin for a maximum of N seconds waiting for the server to come up;

From now on, you can start/stop/query the chrooted mysql just as you would normally.

[root@localhost etc]# /etc/init.d/mysqld status
 mysqld (pid  1905) is running...

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s