Technology Blog

Putting MySQL into a chroot jail (CentOS 6.4 x86_64)

0

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)

 mysql-server-5.1.66-2.el6_3.x86_64
  mysql-libs-5.1.66-2.el6_3.x86_64
  mysql-5.1.66-2.el6_3.x86_64

(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 &
 logout
 
 [[email protected] 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 &
  safe_pid=$  !
  # 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
 safe_pid=$  !
  # 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.

[[email protected] etc]# /etc/init.d/mysqld status
  mysqld (pid  1905) is running...