As part of an assessment I'm using mysql to poke around at a compromised hosts' filesystem. As I seemed to remember from the last time I played with it, some files can be read (eg. /etc/passwd) and others cannot (/etc/shells.)

The mysql documentation specifically says: For security reasons, when reading text files located on the server, the files must either reside in the database directory or be readable by all... https://dev.mysql.com/doc/refman/5.6/en/load-data.html

But that doesn't seem to be the case, since both files have the same effective permissions, and ownership and only the former can be read by load_data() or LOAD DATA INFILE.

-rw-r--r--   1 root    root      73 Feb 13  2013 shells
-rw-r--r--   1 root    root    1.7K Oct  9 04:49 passwd

mysql> select load_file("/etc/passwd");
| load_file("/etc/passwd")
| root:x:0:0:root:/root:/bin/bash


mysql> select load_file("/etc/shells");
| load_file("/etc/shells") |
| NULL                     |
1 row in set (0.00 sec)

How is this discrimination performed and is it something that can be even further restricted? (I know you can disable load data infile, but lets say you couldn't due to an ETL or something, how would you selectively enforce this on /etc/passwd for instance.)

  • 1
    Are SELinux or AppArmor active? Chroots?
    – Lekensteyn
    Oct 9, 2013 at 15:49
  • Yes AppArmor is active. No Chroots. I don't have a profile for mysqld explicitly. But it seems like it doesn't matter. (more below)
    – Ori
    Oct 10, 2013 at 3:05

1 Answer 1


It looks like this is the apparmor conundrum. I had "stopped" apparmor, and retested, but it didn't seem to matter.

Enabling APPARMOR_ENABLE_AAEVENTD so I could get logs on apparmor related denys:

vi /etc/apparmor/subdomain.conf

and updated the line:


and restarted apparmor

ori@myamdbox:/etc/apparmor$ sudo service apparmor restart

I then reran the load_file("/etc/shells") above and the log spewed out:

Oct 10 04:03:13 myamdbox kernel: [85739.145281] type=1400 audit(1381374193.268:132): apparmor="DENIED" operation="open" parent=1 profile="/usr/sbin/mysqld" name="/etc/shells" pid=22485 comm="mysqld" requested_mask="r" denied_mask="r" fsuid=115 ouid=0

Tearing down the profile for a test worked, so it's certainly the culprit.

To fix it simply I opened /etc/apparmor.d/usr.sbin.mysqld

and added the line:


/etc/shells r, 

And yep, it works.

mysql> select load_file("/etc/shells");
| load_file("/etc/shells")                                                  |
| # /etc/shells: valid login shells
1 row in set (0.00 sec)

To do the opposite I need only find the reference in the apparmor config and remove it.

Thanks Lekensteyn!

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .