Bug 2833 - The code in opennsd-compat/port-solaris.c should not change PRIV_LIMIT when PRIV_XPOLICY is set.
Summary: The code in opennsd-compat/port-solaris.c should not change PRIV_LIMIT when P...
Status: NEW
Alias: None
Product: Portable OpenSSH
Classification: Unclassified
Component: sftp-server (show other bugs)
Version: 7.5p1
Hardware: Other Solaris
: P5 normal
Assignee: Assigned to nobody
URL:
Keywords: patch
Depends on:
Blocks:
 
Reported: 2018-02-24 10:44 AEDT by ron.jordan
Modified: 2019-03-13 02:15 AEDT (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description ron.jordan 2018-02-24 10:44:07 AEDT
The code in opennsd-compat/port-solaris.c should not change PRIV_LIMIT
when PRIV_XPOLICY is set. 

In Solaris, it is possible for a user to have an extended policy in place; the LIMIT set restricts the extended policy and so should not be restricted.
Comment 1 ron.jordan 2018-02-24 10:47:56 AEDT
This issue will immediately be addressed in Solaris 11 by Oracle via a patch.  This patch is being offered for inclusion upstream: 

diff -ur orig/openbsd-compat/port-solaris.c new/openbsd-compat/port-solaris.c
--- orig/openbsd-compat/port-solaris.c  Tue Feb  6 08:22:44 2018
+++ new/openbsd-compat/port-solaris.c   Tue Feb  6 08:45:21 2018
@@ -306,6 +306,31 @@
            priv_delset(npset, PRIV_PROC_SESSION) != 0)
                fatal("priv_delset: %s", strerror(errno));

+#ifdef PRIV_XPOLICY
+       /*
+        * It is possible that the user has an extended policy
+        * in place; the LIMIT set restricts the extended policy
+        * and so should not be restricted.
+        * PRIV_XPOLICY is newly defined in Solaris 11 though the extended
+        * policy was not implemented until Solaris 11.1.
+        */
+       if (getpflags(PRIV_XPOLICY) == 1) {
+               if (getppriv(PRIV_LIMIT, pset) != 0)
+                       fatal("getppriv: %s", strerror(errno));
+
+               priv_intersect(pset, npset);
+
+               if (setppriv(PRIV_SET, PRIV_LIMIT, npset) != 0)
+                       fatal("setppriv: %s", strerror(errno));
+       } else
+#endif
+       {
+               /* Cannot exec, so we can kill the limit set. */
+               priv_emptyset(pset);
+               if (setppriv(PRIV_SET, PRIV_LIMIT, pset) != 0)
+                       fatal("setppriv: %s", strerror(errno));
+       }
+
        if (getppriv(PRIV_PERMITTED, pset) != 0)
                fatal("getppriv: %s", strerror(errno));

@@ -312,7 +337,6 @@
        priv_intersect(pset, npset);

        if (setppriv(PRIV_SET, PRIV_PERMITTED, npset) != 0 ||
-           setppriv(PRIV_SET, PRIV_LIMIT, npset) != 0 ||
            setppriv(PRIV_SET, PRIV_INHERITABLE, npset) != 0)
                fatal("setppriv: %s", strerror(errno));
Comment 2 Damien Miller 2018-06-01 14:37:30 AEST
Could you point us to some documentation on PRIV_XPOLICY? I can't see anything in any of the available online manual pages and I'd like to understand what is wrong rather than blindly commit this.
Comment 3 Damien Miller 2018-06-08 13:37:00 AEST
Remove release target until we understand this properly.
Comment 4 ron.jordan 2018-06-13 09:51:11 AEST
(In reply to Damien Miller from comment #2)
> Could you point us to some documentation on PRIV_XPOLICY? I can't
> see anything in any of the available online manual pages and I'd
> like to understand what is wrong rather than blindly commit this.


Sorry for the delay!

Please see:

Securing Users and Processes in Oracle, Solaris 11.3's Locking Down Resources by Using Extended Privileges:
https://docs.oracle.com/cd/E53394_01/html/E54830/rbactask-lockdown-1.html

Solaris 11.3 ppriv man page, especially examples 6 & 7:
https://docs.oracle.com/cd/E86824_01/html/E54763/ppriv-1.html

Please let me know if you need further info.  Thx!
Comment 5 Damien Miller 2018-07-27 14:52:58 AEST
I'm still a little unclear, sorry:

It looks like the !PRIV_XPOLICY case gets a more restricted (empty) PRIV_LIMIT set than the case where an PRIV_XPOLICY exists. Why can't an empty set be used in both cases?
Comment 6 Peter Whittaker 2019-03-13 02:15:49 AEDT
The end-goal is to set effective privileges for the current process (and, to be safe, for any children) but changes to PRIV_LIMIT are not put into effect until an exec(); refer to "man setppriv" referenced above: Changing PRIV_LIMIT does nothing to the current process, only to its children.

The other thing to note from that man page is that when privileges are removed from PRIV_PERMITTED, they are ALSO immediately and silently removed from PRIV_EFFECTIVE: if npset is more restrictive than PRIV_PERMITTED, the first call to setppriv() removes privileges from both PRIV_PERMITTED and PRIV_EFFECTIVE, which has the desired effect of removing privileges from the current process.

If npset is more restrictive that PRIV_INHERITABLE, the second call to setppriv() removes permissions from that set, covering any subsequent processes created with exec().

Since the privileges of the current process were limited to PRIV_INHERITABLE when it was exec()'d, if npset is more restrictive than PRIV_INHERITABLE it is likely more restrictive than PRIV_PERMITTED - but the reverse might not be true in general, since PRIV_PERMITTED might have already been reduced to less than PRIV_INHERITABLE.

The end result of these two calls is that PRIV_INHERITABLE and PRIV_PERMITTED match npset, controlling both the privileges available to the current process and the privileges available to any children.

Modifying PRIV_LIMIT is redundant and unnecessary. I don't know that it is harmful (would we ever want to query it?) but it is unneeded.

Refer also to https://docs.oracle.com/cd/E86824_01/html/E54776/privileges-5.html