I have what (should) be a fairly straightforward task: Migrate a set of custom log files to a database at night.

I use logrotate (cron.daily) with a simple prerotate task

    rotate 366
    dateformat .%Y-%m-%d
    compresscmd /usr/bin/xz
    compressoptions -ze9
    compressext .xz
        /usr/local/myapp/bin/DBWriter $1

Unfortunately SELinux doesn't see it that way. If I setenforce 0 then the script runs perfectly. Rotates logs, sends them to the DB, etc. setenforce 1, however, returns :

logrotate_script: line 1: /usr/local/myapp/bin/DBWriter: Permission denied

I've tried changing contexts on DBWriter, most recently I set it to unconfined_u:unconfined_r:unconfined_t which did not work either...

Ideally, I need to keep SELinux enabled. If it matters, DBWriter is also available as a java .jar file. But running java -jar DBWriter.jar has the same result.

Thanks in advance!

Edit: Win.T's answer below solved the problem for me.

semanage permissive -a logrotate_t

Part of the problem is that I was trying to do exactly what SELinux is designed to prevent: cause process A to execute unknown file B and wreak havoc on system C

Project design considerations and restrictions put us on this path.

Clients don't always want to hear about those fancy buzz words like security and future-proofing.

  • I'm pretty sure there is an SELinux helper daemon that you can run that dumps a logfile with the exact command you need to do to allow the things that just failed. The name escapes me at the moment, sorry! Commented Feb 27, 2015 at 0:28

2 Answers 2


Look in /var/log/messages and /var/log/audit/audit.log (if you have auditd running). You can also use audit2allow to view SELinux error messages and possible solutions.

Additionally, try semanage permissive -a logrotate_t to allow logrotate to run and not be denied by SELinux.

  • audit.log doesn't help much. It just says it failed. messages doesn't give me much to go on either.
    – Sean
    Commented Feb 27, 2015 at 5:29
  • 1
    @SeanEichhorn try adding this semanage fcontext : #semanage permissive -a logrotate_t. This should allow logrotate to run and not denied by Selinux even it is set as enforcing. Remember to perform a restorecon -R -v
    – Win.T
    Commented Feb 27, 2015 at 9:21
  • See access.redhat.com/solutions/39006 for a complete explanation of the problem and the solution. Commented Jan 18, 2022 at 8:20
  • Is the semanage permissive -a logrotate_t persistent? Does it persist reboots?
    Commented Feb 29 at 9:53

If you are unsure it's SELinux, first try temporarily disabling SELinux enforcing sudo setenforce 0 SELinux Ref and run the code that was failing. If it is SELinux read on..

I ran into this issue recently and was pretty unfamiliar with SELinux so it was a bit of a learning curve for me. Unlike (DAC) standard posix mode permissions using chmod & chown, SELinux is a lot more granular with it's permissions. It will in certain cases deny specific operations such as connecting to the internet over TCP/443, or allow writing to /foo & /bar, but nowhere else etc. depending on the caller (application).

To view a files (MAC) mandatory access control permissions ls -Z or users id -Z with output in the user:role:type:level format.

In my case on Centos7 I had a script called in a logrotate.d conf file with a prerotate script that would upload a logfile before it was rotated. I was having several denials (logged to /var/log/audit/audit.log). I learned you can use a few tools to generate specific policy package to install. I am creating .rpm packages for our code, so I added all the steps below to the .spec file to generate & install a policy package during time of install.

What you'll need: policycoreutils-python, checkpolicy (might already be installed)

From what I understand if you plan on distributing this security policy the idea is you want to only ship the *.te file and generate the policy onsite so if the definitions that policy relies on get updated, they will be inherited at time of install.

#finding the denial messages

watch "tail /var/log/audit/audit.log | grep 'denied'"

# creating the te (type enforcement) file (human readable security policy)

grep 1561055176.928:11371 /var/log/audit/audit.log|audit2allow -m myapp > myapp.te

# you can also grep a few failures and pipe them all to audit2allow

cat /var/log/audit/audit.log | grep logrotate | audit2allow -m myapp > myapp.te

# you can also use audit2why to give you a little explanation of why it failed sometimes with remediation steps

cat /var/log/audit/audit.log | grep logrotate | audit2why

WARNING During this step I found audit2why reporting my script would work if I ran setsebool -P nis_enabled 1. While that sounds fine and dandy you should always lookup what the security implications are of running those commands. Setting this may broaden your attack surface, so user beware.

# build a policy module from type enforcement file

checkmodule -M -m -o myapp.mod myapp.te

# build a policy package from policy module

semodule_package -o myapp.pp -m myapp.mod

# load policy package with root privs

semodule -i myapp.pp

I had to do these steps several times until I had accumulated all the tiny permissions my code needed to operate.

-- update --

I ended up running my script inline just before the logrotate cron task so that I didn't have to expand logrotate_t's permissions. I had it in prerotate because I wanted not to rotate the file on failures, which this syntax still satisfies. Using the '&&' syntax if the 1st command fails it won't execute the 2nd.

10 * * * * root /usr/bin/sudo -i -u otheruser /opt/send_logs.sh && /usr/sbin/logrotate -f /path/to/myapp_logrotate.conf > /tmp/myapp_rotate.log 2&1

You must log in to answer this question.

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