Logrotate throws access denied error

Over the past few months, my CentOS 7 server has starting throwing errors when logrotate tries to rotate UrBackup’s logs. This is the error I see:

/etc/cron.daily/logrotate:

Failed to kill unit urbackup-server.service: Access denied
error: error running non-shared postrotate script for /var/log/urbackup.log of '"/var/log/urbackup.log" '

At first I thought there was a problem with creating the new log file, but I found that this is not the case: the current log file is renamed, and a new, empty one is created in /var/log.

The problem is with the postrotate command that sends the urbackup service the -HUP signal. Apparently that isn’t working, so UrBackup never starts writing to the new log file (it continues writing indefinitely to the old one).

Here is the relevant error I found in /var/log/messages after my daily log rotation:

Nov 14 03:33:33 backup4 kernel: type=1107 audit(1510648413.518:4407695): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='avc:  denied  { stop } for auid=0 uid=0 gid=0 path="/usr/lib/systemd/system/urbackup-server.service" cmdline="/bin/systemctl kill -s HUP urbackup-server.service" scontext=system_u:system_r:logrotate_t:s0-s0:c0.c1023 tcontext=system_u:object_r:systemd_unit_file_t:s0 tclass=service#012 exe="/usr/lib/systemd/systemd" sauid=0 hostname=? addr=? terminal=?'

Nov 14 03:33:33 backup4 logrotate: ALERT exited abnormally with [1]

So the issue is with the postrotate command:

systemctl kill -s HUP urbackup-server.service

If I try to run this command interactively as root, it always completes correctly. However, it never works when run through cron/logrotate.

Does anyone have an idea what should be used instead as the postrotate command? My Web searches haven’t turned up anything relevant.

Thanks for any help.

Just an update: I’ve since confirmed that SELinux doesn’t allow logrotate to control systemd units, so this is expected behavior. In that case, I don’t know why UrBackup has the “systemctl kill” command in the postrotate script at all.

However, it brings up another question: why isn’t the first part of the postrotate script running?:

test -e /var/run/urbackupsrv.pid && kill -HUP 'cat /var/run/urbackupsrv.pid' || /bin/systemctl kill -s HUP urbackup-server.service

The reason is because the pid file /var/run/urbackupsrv.pid doesn’t exist.

Does this pid file get created for anyone else?

The first part (with the pid file) is used if it still uses the old sysv-init (init.d script), i.e. the server is started using urbackupsrv run -d.

The other programs (like e.g. apache) have to receive SIGHUP too, maybe you can have a look how it is solved there?
Non-elegant solution would be to use kill -HUP $(pidof urbackupsrv) since command line stuff may cause a second instance to become active.

Thanks a lot for your reply. I also had the idea that the pid file was probably related to the older init method.

I checked out all the other logrotate conf files on the system in /etc/logrotate.d, and they handle the log rotation differently. Apache uses systemctl reload, while others use command arguments such as chronyd cyclelogs or mysqladmin flush-logs. Nobody seems to be sending the HUP signal.

As a workaround, I did have luck putting the following into root’s crontab:

/bin/systemctl kill -s HUP urbackup-server.service

That gets around the SELinux restriction.

I could also try modifying the logrotate to include the kill command you listed. Maybe SELinux will allow that. I’ll reply with what I find out.

Reload is a good idea I think. The systemd docu has an example how to change the systemd config such that it sends SIGHUP on reload (though I still think the kill thing is better…).

Well, it looks like your suggested postrotate command works:

/usr/bin/kill -HUP $(pidof urbackupsrv)

I can see that the logs were properly rotated last night, and UrBackup is now writing into /var/log/urbackup.log, as it should.

So we could probably generalize this and suggest the following logrotate configuration be used in UrBackup to cover both SysV and systemd init systems:

"/var/log/urbackup.log" {
        daily
        rotate 30
        missingok
        create 640 urbackup urbackup
        compress
        postrotate
                test -e /var/run/urbackupsrv.pid && kill -HUP 'cat /var/run/urbackupsrv.pid' || /usr/bin/kill -HUP $(pidof urbackupsrv)
        endscript
}

I agree that a systemctl reload would probably be most consistent with the systemd way of doing things. However, SELinux is still pretty opaque to me: I assume that it allows systemctl reload, but specifically doesn’t allow systemctl kill. That would be worth checking out if you wanted to implement this.

Thanks a lot for your help!