-
Notifications
You must be signed in to change notification settings - Fork 3
libnss_tcb: Match interfaces with NSS documentation. #31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Last one for v1.3, promissed! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've made some comments based on skimming of the code, but also I need to review the spec and we need to review and cleanup our previous errno logic. This may be overly complicated with us separately maintaining errno and *__errnop.
Was the spec always this way or are we breaking compatibility with some legacy glibc?
|
|
||
| if (asprintf(&file, TCB_FMT, name) < 0) | ||
| if (asprintf(&file, TCB_FMT, name) < 0) { | ||
| *__errnop = EAGAIN; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should maybe be *__errnop = errno, because asprintf may set perhaps ENOMEM and it'd be right.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the specs EAGAIN looks correct to me, as NSS_STATUS_TRYAGAIN with errnop EAGAIN means: "One of the functions used ran temporarily out of resources or a service is currently not available."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation says that in case of NSS_STATUS_TRYAGAIN only ERANGE has a special meaning, and everything else is as good as EAGAIN. The implementation agrees with the documentation, there is some special handling for ERANGE, but besides that all errno values are equal. In fact, __nss_getent_r returns EAGAIN in case of NSS_STATUS_TRYAGAIN regardless of errno value.
libs/nss.c
Outdated
| switch (saved_errno) { | ||
| case 0: | ||
| if (!*result_buf_ptr) { | ||
| *__errnop = ENOENT; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe EINVAL here? But is it a good idea to check for improper usage like that? It's typical for libc function to just crash when called with a NULL pointer where that is not allowed.
libs/nss.c
Outdated
| tcbdir = opendir(TCB_DIR); | ||
| if (!tcbdir) | ||
| if (!tcbdir) { | ||
| *__errnop = ENOENT; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe *__errnop = errno;.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NSS_STATUS_UNAVAIL with ENOENT means "A necessary input file cannot be found.", which is the case here; tcbdir cannot be opened.
| closedir(tcbdir); | ||
| errno = saved_errno; | ||
| tcbdir = NULL; | ||
| *__errnop = ENOENT; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure that our previous errno logic here was right, so maybe ENOENT is right here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, as we cannot iterate over tcbdir for unknown reasons, so we should indicate "A necessary input file cannot be found."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that in practice __errnop == &errno, assigning different values to errno and *__errnop doesn't make sense.
The spec for the function prototype is unchanged since glibc-2.0.98 (~Oct 1998); the See: https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=c66dbe00b9c98bb9d1fc10c9007fdcfb98a59b73 |
89c5d74 to
ea61369
Compare
ea61369 to
20c1bb2
Compare
|
@solardiz I would be nice, if you could another look here; this rebase should address most of your previous comments. |
Thanks. I will, but not right now. I want to take a look at the specs and hear from @ldv-alt his thoughts on whether we should continue setting |
20c1bb2 to
b2ca446
Compare
According to [1] the interfaces provided are of return-type 'enum nss_status', of which the _nss_database_getXXX_r() interfaces are mandated to take four parameters: a pointer to the result, a pointer to an additional buffer, the size of the buffer supplied, and a pointer to an integer to report error values (errnop). The returned status values are meant to be accompanied by a corresponding error value [2] passed through the errnop pointer. [1] https://www.gnu.org/software/libc/manual/html_node/NSS-Module-Function-Internals.html [2] https://www.gnu.org/software/libc/manual/html_node/NSS-Modules-Interface.html Signed-off-by: Björn Esser <[email protected]>
b2ca446 to
a26fe47
Compare
I've checked the current glibc implementation of nss_files, and for me it looks like it's not quite consistent wrt setting That is, we could make nss_tcb behavior wrt setting |
OK, and what's your preference? Off the top of my head, our options may be:
|
| if (!f) | ||
| return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL; | ||
| if (!f) { | ||
| /* $user/shadow not existing nor readable */ | ||
| *__errnop = ENOENT; | ||
| return NSS_STATUS_UNAVAIL; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The original logic seems to be correct: ENOENT means that the shadow file doesn't exist, in that case NSS_STATUS_NOTFOUND (The requested entry is not available) should be returned. If the shadow file is not available for other reasons, than NSS_STATUS_UNAVAIL should be returned.
| retval = fgetspent_r(f, __result_buf, __buffer, __buflen, __result); | ||
| retval = fgetspent_r(f, __result_buf, __buffer, | ||
| __buflen, &__result_buf); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to make sure, this is a bug fix: when fgetspent_r returns a nonzero value, it writes NULL at the address specified by its last argument. Before this change, that address used to be &errno.
| switch (saved_errno) { | ||
| /* real error number is retval from fgetspent_r(), | ||
| by NSS spec errnop *MUST NOT* be set to 0 */ | ||
| if (retval) | ||
| *__errnop = retval; | ||
|
|
||
| switch (retval) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is correct, the error code returned by fgetspent_r is currently either ENOENT or EAGAIN, it doesn't necessarily have to match the value of errno.
| errno = ENOENT; | ||
| errno = saved_errno; | ||
| tcbdir = NULL; | ||
| /* we have no more entries in tcbdir */ | ||
| *__errnop = ENOENT; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likewise.
I think first of all we should update the function prototypes and fix the bug of passing After that we could fix other inconsistencies, keeping in the mind that in practice |
So maybe 3 separate commits (fix bug, fix prototypes, start to use the passed BTW, why the two underscores? I think that's inappropriate. |
I concur, identifiers with two leading underscores belong to the reserved namespace, it's not correct to introduce them here. |
LGTM. |
According to [1] the interfaces provided are of return-type 'enum nss_status', of which the _nss_database_getXXX_r() interfaces are mandated to take four parameters: a pointer to the result, a pointer to an additional buffer, the size of the buffer supplied, and a pointer to an integer to report error values (errnop). The returned status values are meant to be accompanied by a corresponding error value [2] passed through the errnop pointer.
[1] https://www.gnu.org/software/libc/manual/html_node/NSS-Module-Function-Internals.html
[2] https://www.gnu.org/software/libc/manual/html_node/NSS-Modules-Interface.html