Description of problem: As testuser at level s2-s5, I am able to ssh-mls in to sshuser at s3-s5, although sshuser is defined at s3-s9. Additional Info: Labeled ipsec is configured. My "id" is uid=502(testuser) gid=502(testuser) groups=502(testuser) context=testuser_u:user_r:user_t:Secret-s5 I use ssh-mls to log into remote system... ssh -p 222 -l sshuser <remote ipaddress> On remote, sshuser is defined as, # semanage user -l Labeling MLS/ MLS/ SELinux User Prefix MCS Level MCS Range SELinux Roles sshuser_u user s3 s3-s9 user_r ... # semanage login -l Login Name SELinux User MLS/MCS Range sshuser sshuser_u s3-s9 ... ssh-mls successfully logs me in as, uid=502(sshuser) gid=502(sshuser) groups=502(sshuser) context=sshuser_u:user_r:user_t:s3-s5 I talked to Klaus and this is incorrect behaviour. Since my effective level is s2, I should not be allowed to login as s3-s5. Version-Release number of selected component (if applicable): Running lspp 65 kernel. How reproducible: happens all the time... Steps to Reproduce: ssh -l testuser/user_r/s2-s5 localhost Password: Last login: Mon Feb 19 15:19:45 2007 from localhost.localdomain [testuser/user_r/Secret]$ id uid=502(testuser) gid=502(testuser) groups=502(testuser) context=testuser_u:user_r:user_t:Secret-s5 [testuser/user_r/Secret]$ ssh -p 222 -l sshuser X.X.X.X Password: Last login: Mon Feb 19 14:09:40 2007 from X.X.X.X [sshuser/user_r/s3@hvracer1 ~]$ id uid=502(sshuser) gid=502(sshuser) groups=502(sshuser) context=sshuser_u:user_r:user_t:s3-s5 Actual results: Should have been denied access. Expected results: Was allowed to login as s3-s5. Additional info: Need to try this with cipso and see what happens. Cipso should just send over s2... so perhaps access will be denied... Will try and document behaviour in bug.
As per the Monday LSPP call, I tried this with Cipso .. It worked as expected for me, ie it denied my connection. (I am on lspp.64 kernel, will update soon and post here if the below behavior changed on new kernel, although I doubt it will). What I did .. - Enabled cipso - As testuser (context=testuser_u:user_r:user_t:Secret-s5), I tried : ssh -p 222 -l sshuser localhost - I get denied with the following message : Read from remote host localhost: Connection reset by peer Connection to localhost closed.
What is in the /var/log/secure after the ssh over labeled IPSec login?
After I login, here is contents of /var/log/secure: Feb 22 14:11:43 hvracer1 sshd[7717]: pam_unix(sshd:session): session opened for user sshuser by (uid=0) Feb 22 14:11:43 hvracer1 sshd[7717]: pam_namespace(sshd:session): open_session - start Feb 22 14:11:43 hvracer1 sshd[7717]: pam_namespace(sshd:session): Parsing config file /etc/security/namespace.conf Feb 22 14:11:43 hvracer1 sshd[7717]: pam_namespace(sshd:session): Configured poly dirs: Feb 22 14:11:43 hvracer1 sshd[7717]: pam_namespace(sshd:session): dir='/tmp' iprefix='/tmp-inst/' meth=3 Feb 22 14:11:43 hvracer1 sshd[7717]: pam_namespace(sshd:session): override user 0 Feb 22 14:11:43 hvracer1 sshd[7717]: pam_namespace(sshd:session): override user 3 Feb 22 14:11:43 hvracer1 sshd[7717]: pam_namespace(sshd:session): dir='/var/tmp' iprefix='/var/tmp-inst/' meth=3 Feb 22 14:11:43 hvracer1 sshd[7717]: pam_namespace(sshd:session): override user 0 Feb 22 14:11:43 hvracer1 sshd[7717]: pam_namespace(sshd:session): override user 3 Feb 22 14:11:43 hvracer1 sshd[7717]: pam_namespace(sshd:session): dir='/home/sshuser' iprefix='/home/home.inst/' meth=3Feb 22 14:11:43 hvracer1 sshd[7717]: pam_namespace(sshd:session): override user 0 Feb 22 14:11:43 hvracer1 sshd[7717]: pam_namespace(sshd:session): override user 3 Feb 22 14:11:43 hvracer1 sshd[7717]: pam_namespace(sshd:session): Set up namespace for pid 7717 Feb 22 14:11:43 hvracer1 sshd[7717]: pam_namespace(sshd:session): Checking for ns override in dir /tmp for uid 505 Feb 22 14:11:43 hvracer1 sshd[7717]: pam_namespace(sshd:session): Need poly ns for user 505 for dir /tmp Feb 22 14:11:43 hvracer1 sshd[7717]: pam_namespace(sshd:session): Checking for ns override in dir /tmp for uid 505 Feb 22 14:11:43 hvracer1 sshd[7717]: pam_namespace(sshd:session): Setting poly ns for user 505 for dir /tmp Feb 22 14:11:43 hvracer1 sshd[7717]: pam_namespace(sshd:session): Set namespace for directory /tmp Feb 22 14:11:43 hvracer1 sshd[7717]: pam_namespace(sshd:session): poly_name system_u:object_r:tmp_t:s3-s5_sshuser Feb 22 14:11:43 hvracer1 sshd[7717]: pam_namespace(sshd:session): Inst ctxt system_u:object_r:tmp_t:s3-s5 Orig ctxt system_u:object_r:tmp_t:SystemLow-SystemHighFeb 22 14:11:43 hvracer1 sshd[7717]: pam_namespace(sshd:session): instance_dir /tmp-inst/system_u:object_r:tmp_t:s3-s5_sshuser Feb 22 14:11:44 hvracer1 sshd[7717]: pam_namespace(sshd:session): Checking for ns override in dir /var/tmp for uid 505 Feb 22 14:11:44 hvracer1 sshd[7717]: pam_namespace(sshd:session): Setting poly ns for user 505 for dir /var/tmp Feb 22 14:11:44 hvracer1 sshd[7717]: pam_namespace(sshd:session): Set namespace for directory /var/tmp Feb 22 14:11:44 hvracer1 sshd[7717]: pam_namespace(sshd:session): poly_name system_u:object_r:tmp_t:s3-s5_sshuser Feb 22 14:11:44 hvracer1 sshd[7717]: pam_namespace(sshd:session): Inst ctxt system_u:object_r:tmp_t:s3-s5 Orig ctxt system_u:object_r:tmp_t:SystemLow-SystemHighFeb 22 14:11:44 hvracer1 sshd[7717]: pam_namespace(sshd:session): instance_dir /var/tmp-inst/system_u:object_r:tmp_t:s3-s5_sshuser Feb 22 14:11:44 hvracer1 sshd[7717]: pam_namespace(sshd:session): Checking for ns override in dir /home/sshuser for uid 505 Feb 22 14:11:44 hvracer1 sshd[7717]: pam_namespace(sshd:session): Setting poly ns for user 505 for dir /home/sshuser Feb 22 14:11:44 hvracer1 sshd[7717]: pam_namespace(sshd:session): Set namespace for directory /home/sshuser Feb 22 14:11:44 hvracer1 sshd[7717]: pam_namespace(sshd:session): poly_name user_u:object_r:user_home_dir_t:s3-s5_sshuser Feb 22 14:11:44 hvracer1 sshd[7717]: pam_namespace(sshd:session): Inst ctxt user_u:object_r:user_home_dir_t:s3-s5 Orig ctxt user_u:object_r:user_home_dir_t:SystemLow-SystemHigh Feb 22 14:11:44 hvracer1 sshd[7717]: pam_namespace(sshd:session): instance_dir /home/home.inst/user_u:object_r:user_home_dir_t:s3-s5_sshuser Feb 22 14:11:44 hvracer1 sshd[7717]: pam_namespace(sshd:session): namespace setup ok for pid 7717
And /var/log/messages?
I was curious about xinetd, so added some debug messages and ran it with "-d"... 07/2/22@14:33:10: NOTICE: 4658 {main} xinetd Version 2.3.14 started with libwrap loadavg labeled-networking options compiled in. 07/2/22@14:33:10: NOTICE: 4658 {main} Started working: 1 available service 07/2/22@14:33:10: DEBUG: 4658 {main_loop} active_services = 1 07/2/22@14:33:25: DEBUG: 4658 {main_loop} select returned 1 07/2/22@14:33:25: DEBUG: 4658 {server_start} Starting service ssh-mls 07/2/22@14:33:25: DEBUG: 4659 {exec_server} duping 7 07/2/22@14:33:25: DEBUG: 4658 {main_loop} active_services = 1 07/2/22@14:33:25: DEBUG: 4659 {set_context} getcon returned: system_u:system_r:inetd_t:SystemLow-SystemHigh 07/2/22@14:33:25: DEBUG: 4659 {set_context} getpeercon returned: testuser_u:user_r:user_ssh_t:Secret-s5 07/2/22@14:33:25: DEBUG: 4659 {set_context} getfilecon returned: system_u:object_r:sshd_exec_t:SystemLow 07/2/22@14:33:25: DEBUG: 4659 {set_context} current security exec context now: system_u:system_r:sshd_t:Secret-s5 07/2/22@14:34:11: DEBUG: 4658 {main_loop} active_services = 1 07/2/22@14:34:11: DEBUG: 4658 {main_loop} select returned 1 07/2/22@14:34:11: DEBUG: 4658 {check_pipe} Got signal 17 (Child exited) 07/2/22@14:34:11: DEBUG: 4658 {child_exit} waitpid returned = 4659 07/2/22@14:34:11: DEBUG: 4658 {server_end} ssh-mls server 4659 exited
And 'ausearch -m USER_ROLE_CHANGE' - from the time of the ssh login attempt?
/var/log/messages has: Feb 22 14:46:54 hvracer1 xinetd[7938]: START: ssh-mls pid=8061 from=9.3.192.210 Feb 22 14:46:59 hvracer1 sshd[8061]: Accepted keyboard-interactive/pam for sshuser from 9.3.192.210 port 33670 ssh2 Feb 22 14:46:59 hvracer1 sshd[8061]: permit MLS level Secret-s5 (user range s3-s9) Feb 22 14:47:29 hvracer1 xinetd[7938]: EXIT: ssh-mls status=0 pid=8061 duration=35(sec)
ausearch -m USER_ROLE_CHANGE: time->Thu Feb 22 14:59:20 2007 type=USER_ROLE_CHANGE msg=audit(1172177960.648:1454): user pid=8166 uid=0 auid=0 subj=system_u:system_r:sshd_t:s2-s5 msg='sshd: default-context=sshuser_u:user_r:user_t:s3-s9 selected-context=sshuser_u:user_r:user_t:s3-s5: exe="/usr/sbin/sshd" (hostname=?, addr=?, terminal=? res=success)'
This is being considered very important and a security risk for LSPP, so bumping up the severity.
Dan, it seems that the get_default_context_with_level causes this - it should return a failure if the requested range isn't a subrange of the user's allowed range. It instead happily returns a context with the range shortened to be a subrange. I don't know how it behaves in case of categories but just for a note it should fail if the requested categories aren't a subset of the user's allowed categories.
I don't agree. It is up to the calling app to figure out if what libselinux returned is appropriate or not. get_default_context_with_level returns the system default level based on the Role/Type handed to it. It reads the seusers file and figures out what the user can log in with. If this is different IE < then what is requested, the calling app can either fail or continue depending on its design.
Actually, IIUC, the caller has already called getseuserbyname(), adjusted appropriately for the peer context, etc and is now calling get_default_context_with_level() with the level/range it has already determined. And get_default_context_with_level() is not returning a range contained by the level/range provided. Reproduced as follows: # semanage user -a -P user -R user_r -L s3 -r s3-s9 sshuser_u # semanage login -a -s sshuser_u -r s3-s9 sshuser # getdefaultcon -l s2-s5 sshuser system_u:system_r:sshd_t:SystemLow-SystemHigh getdefaultcon: sshuser from system_u:system_r:sshd_t:SystemLow-SystemHigh sshuser_u (null) s2-s5 -> sshuser_u:user_r:user_t:s3-s5 Internally, get_default_context_with_level() is just setting the level/range of the fromcon to the specified one and computing reachable contexts as usual. Which boils down to: # compute_user system_u:system_r:sshd_t:s2-s5 sshuser_u sshuser_u:user_r:user_t:s3-s5 Because this is allowed by policy. Is your ssh-mls running in sshd_t or some other domain? Does it have MLS overrides that it shouldn't? Now, we could make get_default_context_with_level(), or rather get_ordered_context_list_with_level(), instead do a strict substitution of the specified level/range into the context it returns. But from a policy POV, this transition _is_ allowed.
I'm also still not convinced this is really a bug. Suppose that this "bug" is fixed but. 1.login on the local machine (allowed s2-s5) with range s3-s5. 2.ssh to the remote machine (allowed s3-s9) as s3-s5 then take some files from there on levels s3 to s5 to the local machine. 3.login locally with range s2-s5 4.downgrade the files to s2 Or is the scenario above not possible?
Step 4 (downgrade the files) would require MLS privilege to perform; while logged in locally at s2, he couldn't read the s3 files, and if he logged in at s3, he wouldn't be able to write to any lower level file without MLS privilege / going through a trusted downgrader. They don't want a process to be able to automatically downgrade data without MLS privilege, not only thinking of the user (who naturally could export the document to external media or printer while at s3 and then re-import it while at s2) but of untrusted/malicious code he may run. But I think this should be fixable in the policy rather than the code; what domain does the ssh-mls process run in, and what MLS overrides does it have? You may need to remove a typeattribute from the ssh-mls process' domain or alternatively customize the MLS constraints to prevent this from happening without breaking other aspects.
I had thought that the sshd-via-xinetd for mls was going to be run in a distinct domain than sshd_t with no MLS overrides per past comments by Klaus. But I don't see anything like that in the current policy. So if you are running it as sshd_t, and sshd_t is MLS privileged, then no surprise that it can do bad things here...
So the idea is in pseudocode: ctx1=get_default_context_with_rolelevel(rlevel); ctx2=selinux_trans_to_raw_context(context_range_set(ctx1,rlevel)); if(strcmp(ctx1, ctx2)) failure; else success; But then I think that the additional check (security_compute_av(src, dst, SECCLASS_CONTEXT, CONTEXT__CONTAINS, &avd)) which is done in the current code doesn't make much sense as the get_default_context_with_rolelevel cannot return anything which is not reachable by the user?? But why was the check there and why it could fail before and not now? Did the get_default_context_with_rolelevel implementation change recently?
No there are two different situations here. 1. ssh is being run by xinetd at a particular level. If the final level does not match the network level, then drop the connection. 2. sshd is running normal, a user tries to login ssh dwalsh/sysadm_r/SystemHigh: In this case the context check is done and if it returns ok, the user gets logged in. So only when you are running on a confined network to you drop the connection on mismatch.
I haven't seen any response to my assertion that this is a policy problem - the sshd run by xinetd for labeled networking should run in a different domain than the normal sshd, and its domain should not be given MLS overrides. Then policy would not allow the transition.
Note that you might need xinetd to explicitly run sshd in a distinct domain (via setexeccon) when using labeled networking, as an automatic domain transition there can't distinguish whether it is a labeled networking session or not.
Dwalsh, the codepath is the same for both situations except the difference in how the desired context is obtained. I think that if the user requests manually a level (or more specifically range) part of which he is not allowed to he can be rejected access as well. Still I'd like to know why the additional check (security_compute_av(src, dst, SECCLASS_CONTEXT, CONTEXT__CONTAINS, &avd)) is necessary when get_default_context_with_rolelevel cannot return a range which the user is not allowed to.
(In reply to comment #19) > Note that you might need xinetd to explicitly run sshd in a distinct domain (via > setexeccon) when using labeled networking, as an automatic domain transition > there can't distinguish whether it is a labeled networking session or not. > The idea is to run sshd from xinetd only for labeled networking and run it standalone for the unlabeled networks.
(In reply to comment #18) This came up on the call and it was said that a second domain wasn't possible because MLS override was needed for polyinstantiation. There also was a comment about not wanting to have to explain how sometimes ssh is a trusted process and sometimes it isn't. I don't know the truth of any of this, just relaying what was said on the last conference call.
(In reply to comment #20) > Still I'd like to know why the additional check (security_compute_av(src, dst, > SECCLASS_CONTEXT, CONTEXT__CONTAINS, &avd)) is necessary when > get_default_context_with_rolelevel cannot return a range which the user is not > allowed to. Don't confuse the Linux user with the SELinux user, or what the Linux user is authorized for (as defined by seusers) and what the SELinux user is authorized for (as defined by kernel policy).
(In reply to comment #22) > (In reply to comment #18) > This came up on the call and it was said that a second domain wasn't possible > because MLS override was needed for polyinstantiation. There also was a comment > about not wanting to have to explain how sometimes ssh is a trusted process and > sometimes it isn't. > > I don't know the truth of any of this, just relaying what was said on the last > conference call. That's broken. But in that case, then sshd needs to special case it and enforce the restriction itself when it is invoked by xinetd for labeled networking. Because as far as the kernel policy is concerned, it can transition to the new context, regardless of what LSPP may say, and in fact, you want it able to make such transitions in the non-labeled networking case.
(In reply to comment #23) > (In reply to comment #20) > > Still I'd like to know why the additional check (security_compute_av(src, dst, > > SECCLASS_CONTEXT, CONTEXT__CONTAINS, &avd)) is necessary when > > get_default_context_with_rolelevel cannot return a range which the user is not > > allowed to. > > Don't confuse the Linux user with the SELinux user, or what the Linux user is > authorized for (as defined by seusers) and what the SELinux user is authorized > for (as defined by kernel policy). So get_default_context_with_rolelevel operates on the range it gets from seusers? (but it gets SELinux user and not Linux user as param) And the check mentioned above queries policy? (In reply to comment #24) > That's broken. But in that case, then sshd needs to special case it and enforce > the restriction itself when it is invoked by xinetd for labeled networking. > Because as far as the kernel policy is concerned, it can transition to the new > context, regardless of what LSPP may say, and in fact, you want it able to make > such transitions in the non-labeled networking case. > But there is already the security_compute_av check in the current sshd code which should do this or not?
(In reply to comment #25) > So get_default_context_with_rolelevel operates on the range it gets from > seusers? (but it gets SELinux user and not Linux user as param) It uses the range you passed it as input into the computation of reachable contexts. IOW, if I take my current context (e.g. sshd_t) and tack on that range as its initial state, what contexts am I allowed to transition to for the specified SELinux user by the kernel's policy. > And the check mentioned above queries policy? Well, sort of. The point here is that we have a seusers-defined range for the Linux user that is potentially a subset of the authorized range for the SELinux user. So if we let the user specify a level, we need to check it against the seusers-defined range in some way. But range interpretation is policy-specific, so we have to bring the policy engine into play for checking that. Which is why we perform a security_compute_av call. But all we are really doing is asking "Is this context's range contained by this other context's range?". > But there is already the security_compute_av check in the current sshd code > which should do this or not? It will only check whether the one context's range is within the other context's range, whatever those contexts may be. It was added to check whether a user-supplied level was within the seusers-defined authorized range. Not for labeled networking per se.
Ah OK, that makes sense, thanks for the explanation.
Hopefully fixed in openssh-4.3p2-18.el5 in dist-5E-lspp. Please test all the possible combinations of valid/invalid ranges again for potential regressions.
Tested several ranges, valid and invalid and all worked correctly. This appears to be fixed and working ok with labeled ipsec.
An advisory has been issued which should help the problem described in this bug report. This report is therefore being closed with a resolution of ERRATA. For more information on the solution and/or where to find the updated files, please follow the link below. You may reopen this bug report if the solution does not work for you. http://rhn.redhat.com/errata/RHSA-2007-0540.html