Deterministic subid calculation#1571
Conversation
d725670 to
b4d445d
Compare
|
I think I've reworked this into a more linear patch set. Hopefully I've gotten the overflow checks clearly documented. |
b4d445d to
3353237
Compare
lib/find_new_sub_uids.c
Outdated
| /* | ||
| * UNSAFE_SUB_UID_DETERMINISTIC_WRAP MODE | ||
| * | ||
| * Promote to uintmax_t before multiplying to avoid truncation on | ||
| * 32-bit platforms where unsigned long is 32 bits. The modulo | ||
| * folds the result back into [0, space) before adding min. | ||
| */ | ||
| uintmax_t logical_offset = (uintmax_t)uid_offset * (uintmax_t)count; | ||
|
|
||
| *range_start = (id_t)(sub_uid_min + (unsigned long)(logical_offset % space)); | ||
| *range_count = count; | ||
| return 0; | ||
| } | ||
|
|
There was a problem hiding this comment.
Why would we want an unsafe mode?
There was a problem hiding this comment.
At my site, once a UNIX UID is assigned, that is your ID forever. It is never reused or reassigned. It is expected to be identical across all systems.
In the next 5 years I expect to have more assigned UIDs than will allow me to give each user 65535 subids.
Eventually I'm going to hit a point where my newest users can't get subids because a bunch of subids are assigned to folks who've left the laboratory.
In my systems with the full user list, I'm going to probably just disable user namespaces since there is no safe way for me to give everyone their own big subid space. I don't really like that plan, but I don't have a better one.
My systems with a limited user list are more interesting... On hosts dedicated to experimental development, I'm willing to take more risks. These hosts typically have less than 100 users.
The great thing about strong determinism in subids is that, so long as all the ids fit between SUBID_MIN and SUBID_MAX, I have perfect consistency across the whole site. Once I run out of space things get rough.
On these hosts as the sysadmin responsible for safety and security of the system, I can see that my UIDs are not contiguous. At times I've got a 1,000+ "unallocated" UIDs on a given host because there are no users in that range who have access to the system. I'm willing to "risk" some overlap when I can see that I've zero interactive UIDs under 2000.
"Unsafe mode" is my best compromise. I get the determinism I want so subids are predicable, and, when I run out of space, I at least have an option I can consider for how to approach the problem.
With a UNIX UID being uint_32, and the traditional subid allocation being "each user gets their own uint_16", I'm going to hit that wall and I don't know what else to do.
If I'm reading the defaults correctly, the defaults from /etc/login.defs only have 9148 65536 ranges. After which some sort of plan is required.
3353237 to
1549cdc
Compare
1526ce3 to
07c9005
Compare
Sorry, I didn't see that - that's good, thanks. |
|
Thanks, I'll take one last look later today. @alejandro-colomar since the logic has changed, probably best that you take another look and make sure we didn't just aim ourselves at another pitfall. |
|
@jcpunk I think something went wrong in your rebase. allow_wrap gets set, but never checked. The wrapping code is missing. |
07c9005 to
b107f30
Compare
|
The wrap code somehow got into the deterministic initial code commit. I've got it in the wrap mode commit now. I'm not sure why the spacing looks all wonky on github. |
c2905f1 to
a2ff4d3
Compare
hallyn
left a comment
There was a problem hiding this comment.
Thanks, looks good to me!
The only thing is, you add new printfs using strerror(), which #1381 replaces. I don't care whether we merge that first and you update to use SYSLOGEC, or this is merged first and @alejandro-colomar updates 1381.
lib/find_new_sub_gids.c
Outdated
| } | ||
| } | ||
|
|
||
| *range_start = (id_t)(sub_gid_min + slot * count); |
There was a problem hiding this comment.
This case is superfluous.
lib/find_new_sub_uids.c
Outdated
| } | ||
| } | ||
|
|
||
| *range_start = (id_t)(sub_uid_min + slot * count); |
There was a problem hiding this comment.
Superfluous cast.
I can update my stuff. Don't worry. :) |
The input to these functions is always an address (&x); that's guaranteed to be non-null. Signed-off-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
GCC has issues with literal -1. Link: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119011> Signed-off-by: Alejandro Colomar <alx@kernel.org>
This helped find a bug, and doesn't seem to have any false positives here, so let's use it. Signed-off-by: Alejandro Colomar <alx@kernel.org>
It's the natural type for this API, and it's also more consistent with its wrappers. Let's also use literal -1 for the error code, which is safer than unsigned constants, as -1 is sign-extended to fit whatever unsigned type we're using. Signed-off-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Cc: Serge Hallyn <serge@hallyn.com> Signed-off-by: Alejandro Colomar <alx@kernel.org>
find_free_range() already checks this, and does it better. Signed-off-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Pat Riehecky <riehecky@fnal.gov>
They are not active at this commit, but they are documented. Signed-off-by: Pat Riehecky <riehecky@fnal.gov>
This adds two new options to /etc/login.defs: * SUB_UID_DETERMINISTIC * SUB_GID_DETERMINISTIC In a lab where users are created ad hoc subids might drift from one host to the other. If there is a shared home area, this drift can create some frustration. Creating subids deterministically provides one type of solution to this problem. Use of nonconsecutive UIDs will result in blocks of unused subids. The manpages provide documentation on how these can be used. Signed-off-by: Pat Riehecky <riehecky@fnal.gov>
They are not active at this commit, but they are documented. Signed-off-by: Pat Riehecky <riehecky@fnal.gov>
This adds two new options to /etc/login.defs:
* UNSAFE_SUB_UID_DETERMINISTIC_WRAP
* UNSAFE_SUB_GID_DETERMINISTIC_WRAP
Deterministic subordinate ID allocation ties each user's subid range
directly to their UID, giving consistent, reproducible ranges across all
hosts without a shared database. This property breaks down when the
subordinate ID space is exhausted.
With a UID space that on Linux extends to 2^32-1 and the traditional
per-user subid allocation of 2^16 ranges, a site with a large UID
population could exhaust the subordinate ID space before all user UIDs
are allocated.
UNSAFE_SUB_UID_DETERMINISTIC_WRAP and UNSAFE_SUB_GID_DETERMINISTIC_WRAP
provide an explicit opt-in to modulo (ring-buffer) wrapping as a
predictable last resort. This preserves the deterministic allocation
at the risk of subid overlap.
The UNSAFE_ prefix and the required explicit opt-in are intentional.
Overlapping ranges break namespace isolation and can allow container
escapes and privilege escalation between users whose ranges collide.
These options are appropriate only when all of the following hold:
- Strict subid determinism is require
- The active UID population on the host is small and well-known
- The administrator regularly audits the UID distribution and confirms
no two active users produce overlapping computed ranges
Do not enable these options on hosts with an uncontrolled user population.
Signed-off-by: Pat Riehecky <riehecky@fnal.gov>
a2ff4d3 to
f3d6f0e
Compare
This patch solves a long standing problem at my site.
We have two main environments: LDAP and "not LDAP".
Our LDAP server doesn't have a schema for subid, so that is local to each system. Users are added to LDAP by a different group and we aren't usually told when a new user appears.
Our "not LDAP" systems are expected to have their UID match whatever is in LDAP, but beyond that we are free to customize. This is typically a lab environment where folks have groups specific to their access within that lab cluster. So here we explicitly want to mangage the subids.
More often then I'd like, users want us to setup an sync job where their home area from the LDAP is synced down to a sub area on the test cluster. So that makes keeping the subids in sync a bit more of an adventure.
Then it gets worse. My site has currently around 63,000 users. Which means if I give every user 65,536 subids to play with, in a few years I'll be out of space since uid_t is u_int_32. Thankfully, my test labs don't the full user list. They generally have about 100 or so users.
Before the merge of 1ed06fe I figured this was a 100% my problem thing since usermod didn't have a "recommend" mode. But now it does.
This patch makes it automatic for me to keep all my "16bit" user subids in perfect sync by just setting up a job to run
usermod -Sas needed.I'm going to need a subid solution for user 75537 (since
UID_MIN==1000) eventually. Since the only place where I'd consider enabling wrap mode is in my heavily curated lab computers, seeding an imperfect solution. I can't shake the feeling that I'm going to need this one day. When LDAP "rolls over" I think we may just drop user namespaces on those hosts...I'll certainly need help with tests.