Bug 229278 - LSPP: ssh-mls allows a level through that it should not
Summary: LSPP: ssh-mls allows a level through that it should not
Keywords:
Status: CLOSED ERRATA
Alias: None
Product: Red Hat Enterprise Linux 5
Classification: Red Hat
Component: openssh
Version: 5.0
Hardware: All
OS: Linux
medium
urgent
Target Milestone: ---
: ---
Assignee: Tomas Mraz
QA Contact: Brian Brock
URL:
Whiteboard:
Depends On:
Blocks: RHEL5LSPPCertTracker 234654
TreeView+ depends on / blocked
 
Reported: 2007-02-19 21:39 UTC by Joy Latten
Modified: 2018-10-19 22:56 UTC (History)
9 users (show)

Fixed In Version: RHSA-2007-0540
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2007-11-07 15:32:33 UTC
Target Upstream Version:
Embargoed:


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
Red Hat Product Errata RHSA-2007:0540 0 normal SHIPPED_LIVE Moderate: openssh security and bug fix update 2007-11-07 16:19:19 UTC

Description Joy Latten 2007-02-19 21:39:36 UTC
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.

Comment 1 Loulwa Salem 2007-02-20 23:51:33 UTC
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.


Comment 2 Tomas Mraz 2007-02-22 14:56:46 UTC
What is in the /var/log/secure after the ssh over labeled IPSec login?


Comment 3 Joy Latten 2007-02-22 20:16:21 UTC
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



Comment 4 Tomas Mraz 2007-02-22 20:23:35 UTC
And /var/log/messages?


Comment 5 Joy Latten 2007-02-22 20:39:34 UTC
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



Comment 6 Tomas Mraz 2007-02-22 20:48:18 UTC
And 'ausearch -m USER_ROLE_CHANGE' - from the time of the ssh login attempt?


Comment 7 Joy Latten 2007-02-22 20:57:48 UTC
/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)


Comment 8 Joy Latten 2007-02-22 21:01:35 UTC
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)'

Comment 9 Joy Latten 2007-02-22 21:21:04 UTC
This is being considered very important and a security risk for LSPP, so bumping
up the severity. 

Comment 10 Tomas Mraz 2007-02-22 21:41:06 UTC
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.


Comment 11 Daniel Walsh 2007-02-23 14:51:20 UTC
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.

Comment 12 Stephen Smalley 2007-02-23 15:41:47 UTC
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.





Comment 13 Tomas Mraz 2007-02-23 16:19:41 UTC
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?


Comment 14 Stephen Smalley 2007-02-23 17:44:10 UTC
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.

Comment 15 Stephen Smalley 2007-02-23 18:07:19 UTC
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...

Comment 16 Tomas Mraz 2007-02-27 08:06:12 UTC
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? 


Comment 17 Daniel Walsh 2007-02-27 17:00:15 UTC
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.

Comment 18 Stephen Smalley 2007-02-27 17:47:32 UTC
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.

Comment 19 Stephen Smalley 2007-02-27 18:18:42 UTC
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.


Comment 20 Tomas Mraz 2007-02-27 18:24:49 UTC
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.


Comment 21 Tomas Mraz 2007-02-27 18:26:36 UTC
(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.


Comment 22 Eric Paris 2007-02-27 18:30:30 UTC
(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.

Comment 23 Stephen Smalley 2007-02-27 18:35:19 UTC
(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).




Comment 24 Stephen Smalley 2007-02-27 18:40:44 UTC
(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.


Comment 25 Tomas Mraz 2007-02-27 18:55:05 UTC
(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?


Comment 26 Stephen Smalley 2007-02-27 19:18:25 UTC
(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.



Comment 27 Tomas Mraz 2007-02-27 19:33:53 UTC
Ah OK, that makes sense, thanks for the explanation.

Comment 28 Tomas Mraz 2007-02-27 21:18:52 UTC
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.


Comment 29 Joy Latten 2007-03-19 00:42:09 UTC
Tested several ranges, valid and invalid and all worked correctly.
This appears to be fixed and working ok with labeled ipsec.

Comment 35 errata-xmlrpc 2007-11-07 15:32:33 UTC
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



Note You need to log in before you can comment on or make changes to this bug.