Skip to content
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

Attempt to fix the identified thread safety bugs #155

Merged
merged 3 commits into from
Oct 15, 2020

Conversation

vathpela
Copy link
Contributor

In #154 , @marler8997 noticed we have some thread safety bugs (though I think one of them was actually a getenv() usage bug). This PR attempts to resolve those that were identified.

I don't have a particularly good way to test this, nor to actually detect thread safety bugs, so any help would be handy.

@@ -28,18 +29,36 @@
#endif

static char const default_efivarfs_path[] = "/sys/firmware/efi/efivars/";
static char *efivarfs_path;

static char const *
get_efivarfs_path(void)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this purpose of this function was to support lazy initialization, but if you're going to use a CONSTRUCTOR to initialize efivarfs_path, then this function seems unnecessary. Its contents could be put into the CONSTRUCTOR function instead. This removes need to check whether efivarfs_path is NULL both in the constructor and any time it is being used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure it does actually obviate that—though admittedly the situation where it doesn't is fraught with bad ideas. Consider a program which links against libefivar.so and another library, libmistakes.so. libmistakes.so does not link against libefivar.so or have any DT_NEEDED object references to it, but has a DT_INIT constructor that does something like:

static void CONSTRUCTOR init_mistakes(void)
{
  int (*gnvn)(efi_guid_t **guid, char **name);
  char *name;
  efi_guid_t *guid;
  int rc;

  gnvn = dlsym(RTLD_DEFAULT, "efi_get_next_variable_name");
  if (!gnvn)
    return;
  rc = gnvn(&guid, &name);
  if (rc >= 0)
    printf("first EFI variable is %s\n", name);
}

Since libmistakes.so has no DT_NEEDED pointing at libefivar.so, the DT_INIT sorting is not required to ensure that init_mistakes() is called after init_efivarfs_path(); they could be called in any order. Though that does mean the error check on the allocation also needs to be in get_efivarfs_path(), rather than init_efivarfs_path(). I've fixed that in 3d19e7d.

I realize this sounds completely contrived but the basic outline here is more or less how kdeinit works...

Anyway, that aside, are you okay with what I've done in 77f77a4c6d6 ?

@vathpela vathpela force-pushed the thread-safety branch 3 times, most recently from 1e7e321 to 77f77a4 Compare October 1, 2020 20:43
vathpela and others added 3 commits October 15, 2020 19:43
Because the error log array can be changed in any call, it could be
modified by more than one thread at once.  This means that the results
won't make any sense - even absent actual execution errors as a result,
the best case is intermixed error logs from different threads.

This makes the error log pointer thread local, so that each thread will
effectively get its own error log.

Fixes github issue rhboot#154

Signed-off-by: Peter Jones <pjones@redhat.com>
To avoid having problems when the environment changes (due to setenv()
or whatever), ensure that there's an initial call to
get_efivarfs_path(), and that it duplicates the result into a freshly
allocated string.

Fixes github issue rhboot#154

Signed-off-by: Peter Jones <pjones@redhat.com>
This adds a test case that just spawns a bunch of threads quickly and
calls efi_get_variable() on an empty directory.  It fails pretty
reliably without either of the following commits:

65a3ad0 error.c: make our 'global' state be thread local
3d19e7d efivarfs.c: Call get_efivarfs_path() from a constructor

Signed-off-by: Peter Jones <pjones@redhat.com>
@vathpela
Copy link
Contributor Author

(I'm going to assume that's a yes, if you're not okay with that I can always revert it later and do something else.)

@vathpela vathpela merged commit cff88dd into rhboot:master Oct 15, 2020
@marler8997
Copy link
Contributor

What you had was fine, it may or may not be able to be improved with my suggestion. Thanks for taking the time to bring in the new test as well.

@vathpela vathpela deleted the thread-safety branch December 9, 2021 15:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants