mdo(1): Added extensive group setting options and --print-rule#3
mdo(1): Added extensive group setting options and --print-rule#3thesynthax wants to merge 23 commits intoOlCe2:oc-thesynthaxfrom
Conversation
Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
…oups Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
Multiple issues existed within the powerpc FP/VSX save/restore functionality, leading to register corruption and loss of register contents in specific scenarios involving high signal load and use of both floating point and VSX instructions. Issue #1 On little endian systems the PCB used the wrong location for the shadowed FP register within the larger VSX register. This appears to have been an attempt to correct issue #2 without understanding how the vector load/store instructions actually operate. Issue #2 On little endian systems, the VSX state save/restore routines swapped 32-bit words within the 64-bit aliased double word for the associated floating point register. This was due to the use of a word-oriented load/store vs. doubleword oriented load/store. Issue #3 The FPU was turned off in the PCB but not in hardware, leading to a potential race condition if the same thread was scheduled immediately after sigreturn. The triggering codebase for this is Go, which makes heavy use of signals and and generates an unusual mix of floating point and VSX assembler. As a result, when combined with th powerpc lazy FPU restore, a condition was repeatedly hit whereby the thread was interrupted in FP+VSX mode, then restored in FP only mode, thus reliably triggering the issues above. Also clean up the associated asm() style issue flagged by GitHub Actions. Signed-off-by: Timothy Pearson <tpearson@raptorengineering.com> MFC after: 1 week Pull Request: freebsd#1756
OlCe2
left a comment
There was a problem hiding this comment.
This generally looks good. Please see inline comments.
usr.bin/mdo/mdo.c
Outdated
| err(EXIT_FAILURE, "strdup failed"); | ||
| char *tok = strtok(s, ","); | ||
| while (tok) { | ||
| if (strcmp(tok, "@") == 0) { |
There was a problem hiding this comment.
I think it would be better if @ is accepted only as the first token. Else, there is confusion between whether @ should reset everything first even when not in first position, or should reset groups after the first directives, which anyway would be silly (and I don't see a use case for this feature with automatically produced command lines).
Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
OlCe2
left a comment
There was a problem hiding this comment.
Oh sorry, had not validated this GitHub's review, so perhaps some my comments from yesterday were not visible.
OlCe2
left a comment
There was a problem hiding this comment.
Having a set of tests would be great.
As a separate, subsequent commit, it would be nice to add some way to say that the user should not be changed, but only groups should. E.g., some new -k option? Ideally, I would have preferred that this behavior is triggered simply by not specifying -u, but since all credentials-changing program actually interpret not specifying a user as a request to change to root, diverging from that would be too surprising to users.
usr.bin/mdo/mdo.c
Outdated
| if (pw != NULL) { | ||
| const long max = sysconf(_SC_NGROUPS_MAX) + 2; | ||
| base = malloc(sizeof(*base) * max); | ||
| if (!base) | ||
| err(EXIT_FAILURE, "malloc failed"); | ||
| base_count = max; | ||
| getgrouplist(pw->pw_name, pw->pw_gid, base, &base_count); | ||
| } |
There was a problem hiding this comment.
As expressed in the comment just above, this code should be moved up in another block. At this point, you should only be processing supp_add and supp_rem.
There was a problem hiding this comment.
-s option is having problems when I do that. I'm not able to add a new group for some reason.
Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
OlCe2
left a comment
There was a problem hiding this comment.
General style problems:
- Always enclose return values following a
returnin parenthesis. - Use
_to separate words in a variable name.
Generally, in everything you do, be consistent.
The changes I'm requesting here are for readability but also to fix some remaining bugs, notably that -k with -u doesn't trigger an error, that groups to remove are not obeyed when -G is passed, and switching to root without -u is not handled correctly.
usr.bin/mdo/mdo.c
Outdated
| if (keepuser && (ruid_str != NULL || svuid_str != NULL || euid_str != NULL)) | ||
| errx(EXIT_FAILURE, "-k and --ruid/--svuid/--euid cannot be used together"); |
There was a problem hiding this comment.
These lines do not need any ID processing. Move them up before if (!keepuser), and add username_provided to the disjunction (else, -k will simply be ignored with -u, without printing an error message).
usr.bin/mdo/mdo.c
Outdated
| int ngroups = getgroups(0, NULL); | ||
| gid_t *groups = NULL; |
There was a problem hiding this comment.
All code with groups and ngroups here can be removed, as the current supplementary groups are irrelevant for a rule's "target" part. And, indeed, groups is not really used anywhere.
usr.bin/mdo/mdo.c
Outdated
| } else if (pw != NULL && !uidonly) { | ||
| gid = pw->pw_gid; | ||
| override_gid = true; | ||
| } else if (ruid_str != NULL || svuid_str != NULL || euid_str != NULL) { |
There was a problem hiding this comment.
Note: Setting GIDs with the effective GID is in fact not necessary if all 3 strings are present. That would save a call to getegid() in this case, but that's not really important.
usr.bin/mdo/mdo.c
Outdated
| struct setcred wcred = SETCRED_INITIALIZER; | ||
| u_int setcred_flags = 0; | ||
| bool uidonly = false; | ||
| bool keepuser = false; |
There was a problem hiding this comment.
| bool keepuser = false; | |
| bool keep_user = false; |
usr.bin/mdo/mdo.c
Outdated
| const char *group_mod_str = NULL; | ||
| struct setcred wcred = SETCRED_INITIALIZER; | ||
| u_int setcred_flags = 0; | ||
| bool uidonly = false; |
There was a problem hiding this comment.
| bool uidonly = false; | |
| bool uid_only = false; |
usr.bin/mdo/mdo.c
Outdated
| username); | ||
| pw = getpwuid(uid); | ||
| if (!keepuser) { | ||
| if (username_provided) { |
There was a problem hiding this comment.
Remove this if (username_provided). The code inside it must be executed unconditionally.
There was a problem hiding this comment.
Removing this creates problems for explicit UID changes. I changed the check though to work allow the default use of mdo i.e. mdo without any options.
Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
|
Thank you for taking the time to contribute to FreeBSD!
Please review CONTRIBUTING.md, then update and push your branch again. |
OlCe2
left a comment
There was a problem hiding this comment.
Globally fine, there are a few bugs still.
I think we should slightly change the semantics of -i and -k, see inline comments.
| } else { | ||
| pw = getpwuid(geteuid()); | ||
| if (pw == NULL) | ||
| err(EXIT_FAILURE, "invalid username '%s'", username); | ||
| err(EXIT_FAILURE, "cannot determine current user"); | ||
| } |
There was a problem hiding this comment.
If keeping the current user, we do not want to infer the groups from the DB, even if an entry exists. That feels too much surprising.
If some admin really wants to reload the groups from the DB, we'll let him enter the user name explicitly.
So, replace the content of the else block with (please indent as appropriate):
start_from_current_groups = true;
Also, please add in this same else block a comment explaining that, on keep_user the baseline for groups are the current ones.
usr.bin/mdo/mdo.c
Outdated
| "\n" | ||
| "Options:\n" | ||
| " -u <user> Target user (name or UID)\n" | ||
| " -i Only change UID, skip groups\n" |
There was a problem hiding this comment.
I think we should change slightly semantics here:
| " -i Only change UID, skip groups\n" | |
| " -i Keep current groups, unless explicitly overridden\n" |
This is still compatible with the initial mdo behavior, but a different extension than the one we have been doing so far. This new proposal has an important advantage: It allows more freedom to "admins" in that they can specify that mdo should leave groups alone unless explicitly told too (the previous behavior is to just leave groups alone entirely, and you would have to explicitly specify them all to their current values as the same starting point).
Basically, if the target user is in the password database, we just don't set the corresponding groups, and if it is not, we do not request -g (or the more fine-grained group options). But we let the admin still override groups manually if he wishes.
usr.bin/mdo/mdo.c
Outdated
| struct setcred wcred = SETCRED_INITIALIZER; | ||
| u_int setcred_flags = 0; | ||
| bool uidonly = false; | ||
| bool uid_only = false; |
There was a problem hiding this comment.
| bool uid_only = false; | |
| bool start_from_current_groups = false; |
In accordance with the change of semantics for -i.
usr.bin/mdo/mdo.c
Outdated
| (euid_str == NULL && ruid_str == NULL && svuid_str == NULL)) { | ||
| uid_t uid = parse_user_pwd(username, &pw); | ||
|
|
||
| if (pw == NULL && primary_group == NULL && !uid_only) |
There was a problem hiding this comment.
This should rather be:
| if (pw == NULL && primary_group == NULL && !uid_only) | |
| if (!start_from_current_groups && pw == NULL && | |
| primary_group == NULL && (rgid_str == NULL || svgid_str == NULL || egid_str == NULL)) |
(please wrap the line to 80 columns and indent appropriately)
Please also move this if block out and just after the containing if (makes the general logic clearer, and changes the semantics in a way that makes some other check below unnecessary).
We don't need to treat the absence of explicitly specified supplementary groups as an error, if we effectively remove all supplementary groups in this case. If pw is not NULL, we readily have the group to use as a primary one, and we know we can call getgrouplist() to obtain the supplementary ones.
Please add a comment explaining the reason for this if (some elaboration of your own and perhaps a summary of the previous paragraph).
usr.bin/mdo/mdo.c
Outdated
| uid_t uid = parse_user_pwd(username, &pw); | ||
|
|
||
| if (pw == NULL && primary_group == NULL && !uid_only) | ||
| errx(EXIT_FAILURE, "must specify -g when using a numeric UID"); |
There was a problem hiding this comment.
| errx(EXIT_FAILURE, "must specify -g when using a numeric UID"); | |
| errx(EXIT_FAILURE, "must specify primary groups or a user with an entry in the password database"); |
(please wrap the line as necessary; to be moved with its enclosing if as explained in my previous comment)
| } | ||
| free(groups); | ||
| } | ||
| } |
usr.bin/mdo/mdo.c
Outdated
| for (int i = 0; i < base_count; ++i) { | ||
| supp_groups_add = realloc_groups(supp_groups_add, add_count + 1); | ||
| supp_groups_add[add_count++] = groups[i]; | ||
| } | ||
| free(groups); |
There was a problem hiding this comment.
Sorry, should have spotted this earlier, but this loop is in fact not necessary. Just set supp_groups_add to groups here.
usr.bin/mdo/mdo.c
Outdated
| wcred.sc_supp_groups = NULL; | ||
| wcred.sc_supp_groups_nb = 0; | ||
| setcred_flags |= SETCREDF_SUPP_GROUPS; | ||
| } else { |
There was a problem hiding this comment.
| } else { |
The if in the else should be at the same level as the previous if.
usr.bin/mdo/mdo.c
Outdated
| wcred.sc_supp_groups_nb = 0; | ||
| setcred_flags |= SETCREDF_SUPP_GROUPS; | ||
| } else { | ||
| if (pw != NULL && !uid_only) { |
There was a problem hiding this comment.
| if (pw != NULL && !uid_only) { | |
| if (!start_from_current_groups && pw != NULL) { |
usr.bin/mdo/mdo.c
Outdated
| } | ||
|
|
||
| static size_t | ||
| remove_groups_from_array(gid_t *array, size_t count, const gid_t *remove_list, size_t remove_count) |
There was a problem hiding this comment.
Not a priority, but if you have some time: Replace by qsort() + duplicate removal on remove_list followed by a merge-like algorithm, since array is sorted and without duplicates.
Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
Signed-off-by: Kushagra Srivastava <kushagra1403@gmail.com>
Multiple issues existed within the powerpc FP/VSX save/restore functionality, leading to register corruption and loss of register contents in specific scenarios involving high signal load and use of both floating point and VSX instructions. Issue #1 On little endian systems the PCB used the wrong location for the shadowed FP register within the larger VSX register. This appears to have been an attempt to correct issue #2 without understanding how the vector load/store instructions actually operate. Issue #2 On little endian systems, the VSX state save/restore routines swapped 32-bit words within the 64-bit aliased double word for the associated floating point register. This was due to the use of a word-oriented load/store vs. doubleword oriented load/store. Issue #3 The FPU was turned off in the PCB but not in hardware, leading to a potential race condition if the same thread was scheduled immediately after sigreturn. The triggering codebase for this is Go, which makes heavy use of signals and and generates an unusual mix of floating point and VSX assembler. As a result, when combined with th powerpc lazy FPU restore, a condition was repeatedly hit whereby the thread was interrupted in FP+VSX mode, then restored in FP only mode, thus reliably triggering the issues above. Also clean up the associated asm() style issue flagged by GitHub Actions. Signed-off-by: Timothy Pearson <tpearson@raptorengineering.com> MFC after: 1 week Pull Request: freebsd#1756 (cherry picked from commit 077e30e)
|
Code here was largely rewritten, for lots of reason (have The final result was committed as 3ca1e69, and will be present in 15.0. |
|
Actually, the |
Added options to: