I just installed Fedora 22 on my VPS and tried to make trivial thing -- run my informer script on every ssh login via pam_exec. But I was confronted with unexpected difficulties: pam_exec failed with exit code 13.

I added habitual line to the end of /etc/pam.d/sshd:

session optional pam_exec.so seteuid /usr/local/bin/loginformer.py

Of course loginformer.py has execution flags:

$ ls -l /usr/local/bin/loginformer.py
-rwxr-xr-x. 1 root root 4254 Jun  8 09:35 /usr/local/bin/loginformer.py

But here is painful extract from journalctl -lb SYSLOG_FACILITY=10:

Jun 08 11:58:49 fedora22 sshd[671]: pam_exec(sshd:session): execve(/usr/local/bin/loginformer.py,...) failed: Permission denied
Jun 08 11:58:49 fedora22 sshd[663]: pam_exec(sshd:session): /usr/local/bin/loginformer.py failed: exit code 13

I'm not sure what's happening, because it always work on my ArchLinux. I think it may be some SELinux resctriction, but I'm not sure.

What I'm doing wrong?


Well, I tried to go deeply to SELinux and understood I should change SELinux context of my script.

Now SELinux context of it looks so:

$ ls -Z /usr/local/bin/loginformer.py
unconfined_u:object_r:user_home_t:s0 /usr/local/bin/loginformer.py

But which context should I set to the script?


Also, I think SELinux AVC logs may be very useful for detection of problem. I'm sorry I didn't give it earlier. cat /var/log/audit/audit.log | grep loginformer.py return a lot of same strings:

type=AVC msg=audit(1433784991.570:265): avc:  denied  { execute } for  pid=7866 comm="sshd" name="loginfomer.py" dev="vda1" ino=11924 scontext=system_u:system_r:sshd_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file permissive=0
  • @Christopher "same context as the files that loginformer.py reads". But it doesn't read any files. It just get values of PAM enviroment variables (like PAM_USER), compose an email and send it via smtplib. Or python's import ... is "file read" from the point of view of SELinux?.. – shau-kote Jun 8 '15 at 17:29
  • @Christopher also I attach extract from SELinux AVC log. As I can see, SELinux prohibited execute of script, not some file reading. – shau-kote Jun 8 '15 at 18:00
  • 1
    @Christopher yes, setenforce 0 "fix" the problem and loginformer.py start and run normally. But I think it isn't a good idea. – shau-kote Jun 8 '15 at 18:12
  • I mean to say that setenforce 0 is insecure and I think it isn't a good solution. – shau-kote Jun 8 '15 at 18:22
  • Yes, I understood. It worked. But I till now have no idea how explain SELinux that I want run this script from pam_exec. :( – shau-kote Jun 8 '15 at 18:31

The order in which pam_exec and pam_selinux are invoked is important. Man page for pam_selinux notes:

Adding pam_selinux into the PAM stack might disrupt behavior of other PAM modules which execute applications. To avoid that, pam_selinux.so open should be placed after such modules in the PAM stack, and pam_selinux.so close should be placed before them. When such a placement is not feasible, pam_selinux.so restore could be used to temporary restore original security contexts.

Similarly, Dan Walsh writes about the topic:

If you are going to add a pam_module that would exec commands that the user would not be allowed to execute, for example pam_mount, it should be added before the pam_selinux.so open command. If you are adding a pam_module that execs command a user could execute, then you probably want these after the pam_selinux.so open line.

Also note that your script currently has security context of user_home_t, which is not likely compatible with the default policy (file contexts are preserved when file is moved; if you created the file in your home directory moving the file will preserve the original context). You probably should use the default bin_t context. To restore the default context:

restorecon  /usr/local/bin/loginformer.py

If your script does not do anything too special, placing pam_exec before pam_selinux and restring the context should be enough to fix your issue.

| improve this answer | |
  • Sorry, I do not already have the VPS so cannot check your answer. I assume it will not be proper if I accept the answer without it. Thank you for the verbose answer, I hope it will help someone else. – shau-kote Oct 9 '18 at 14:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.