Skip to content

read lock store on ossl_method_store_do_all - #24782

Closed
nhorman wants to merge 5 commits into
openssl:masterfrom
nhorman:24672
Closed

nhorman wants to merge 5 commits into
openssl:masterfrom
nhorman:24672

Conversation

@nhorman

@nhorman nhorman commented Jul 2, 2024

Copy link
Copy Markdown
Contributor

Theres a data race between ossl_method_store_insert and ossl_method_store_do_all, as the latter doesn't take the property lock before iterating.

However, we can't lock in do_all, as the call stack in several cases later attempts to take the write lock.

The choices to fix it are I think:

  1. add an argument to indicate to ossl_method_store_do_all weather to
    take the read or write lock when doing iterations, and add an
    is_locked api to the ossl_property_[read|write] lock family so that
    subsequent callers can determine if they need to take a lock or not

  2. Clone the algs sparse array in ossl_method_store_do_all and use the
    clone to iterate with no lock held, ensuring that updates to the
    parent copy of the sparse array are left untoucheTheres a data race
    between ossl_method_store_insert and ossl_method_store_do_all, as the
    latter doesn't take the property lock before iterating.

I think method (2), while being a bit more expensive, is probably the far less invasive way to go here

Fixes #24672

Theres a data race between ossl_method_store_insert and
ossl_method_store_do_all, as the latter doesn't take the property lock
before iterating.

However, we can't lock in do_all, as the call stack in several cases
later attempts to take the write lock.

The choices to fix it are I think:
1) add an argument to indicate to ossl_method_store_do_all weather to
   take the read or write lock when doing iterations, and add an
   is_locked api to the ossl_property_[read|write] lock family so that
   subsequent callers can determine if they need to take a lock or not

2) Clone the algs sparse array in ossl_method_store_do_all and use the
   clone to iterate with no lock held, ensuring that updates to the
   parent copy of the sparse array are left untoucheTheres a data race
   between ossl_method_store_insert and ossl_method_store_do_all, as the
   latter doesn't take the property lock before iterating.

   However, we can't lock in do_all, as the call stack in several cases
   later attempts to take the write lock.

   The choices to fix it are I think:
   1) add an argument to indicate to ossl_method_store_do_all weather to
      take the read or write lock when doing iterations, and add an
      is_locked api to the ossl_property_[read|write] lock family so
      that subsequent callers can determine if they need to take a lock
      or not

   2) Clone the algs sparse array in ossl_method_store_do_all and use
      the clone to iterate with no lock held, ensuring that updates to
      the parent copy of the sparse array are left untouched during the
      iteration

I think method (2), while being a bit more expensive, is probably the
far less invasive way to go here

Fixes openssl#24672
@nhorman nhorman self-assigned this Jul 2, 2024
@nhorman
nhorman marked this pull request as draft July 2, 2024 19:15
@github-actions github-actions Bot added the severity: fips change The pull request changes FIPS provider sources label Jul 2, 2024
@nhorman
nhorman marked this pull request as ready for review July 2, 2024 19:36

@paulidale paulidale left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just one nit.

This is the method we use elsewhere to avoid similar problems.

Comment thread crypto/property/property.c Outdated
@paulidale

Copy link
Copy Markdown
Contributor

A thought: would using a stack for the temporary copy make sense? It would avoid some of the inefficiencies of the sparse array.

@t8m t8m added branch: master Applies to master branch triaged: bug The issue/pr is/fixes a bug branch: 3.0 Applies to openssl-3.0 branch (EOL) branch: 3.1 Applies to openssl-3.1 (EOL) tests: exempted The PR is exempt from requirements for testing branch: 3.2 Applies to openssl-3.2 (EOL) branch: 3.3 Applies to openssl-3.3 (EOL) labels Jul 3, 2024
@t8m

t8m commented Jul 3, 2024

Copy link
Copy Markdown
Member

A thought: would using a stack for the temporary copy make sense? It would avoid some of the inefficiencies of the sparse array.

Yeah, we should use that.

@t8m

t8m commented Jul 3, 2024

Copy link
Copy Markdown
Member

Please also note there is a duplicated text in the commit message.

read lock store on ossl_method_store_do_all

Theres a data race between ossl_method_store_insert and
ossl_method_store_do_all, as the latter doesn't take the property lock
before iterating.

However, we can't lock in do_all, as the call stack in several cases
later attempts to take the write lock.

The choices to fix it are I think:
1) add an argument to indicate to ossl_method_store_do_all weather to
   take the read or write lock when doing iterations, and add an
   is_locked api to the ossl_property_[read|write] lock family so that
   subsequent callers can determine if they need to take a lock or not

2) Clone the algs sparse array in ossl_method_store_do_all and use the
   clone to iterate with no lock held, ensuring that updates to the
   parent copy of the sparse array are left untoucheTheres a data race
   between ossl_method_store_insert and ossl_method_store_do_all, as the
   latter doesn't take the property lock before iterating.

I think method (2), while being a bit more expensive, is probably the
far less invasive way to go here

Fixes openssl#24672
@nhorman

nhorman commented Jul 3, 2024

Copy link
Copy Markdown
Contributor Author

fixups made to use a stack rather than a sparse array, fix nits, and correct commit message

@t8m t8m added approval: review pending This pull request needs review by a committer approval: otc review pending labels Jul 3, 2024

@t8m t8m left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

One minor nit.

Comment thread crypto/property/property.c Outdated
@nhorman
nhorman requested a review from t8m July 3, 2024 15:15
rschu1ze pushed a commit to ClickHouse/openssl that referenced this pull request Jul 3, 2024
This is a combination of 3 commits.

This is the 1st commit message:

read lock store on ossl_method_store_do_all

Theres a data race between ossl_method_store_insert and
ossl_method_store_do_all, as the latter doesn't take the property lock
before iterating.

However, we can't lock in do_all, as the call stack in several cases
later attempts to take the write lock.

The choices to fix it are I think:
1) add an argument to indicate to ossl_method_store_do_all weather to
   take the read or write lock when doing iterations, and add an
   is_locked api to the ossl_property_[read|write] lock family so that
   subsequent callers can determine if they need to take a lock or not

2) Clone the algs sparse array in ossl_method_store_do_all and use the
   clone to iterate with no lock held, ensuring that updates to the
   parent copy of the sparse array are left untoucheTheres a data race
   between ossl_method_store_insert and ossl_method_store_do_all, as the
   latter doesn't take the property lock before iterating.

   However, we can't lock in do_all, as the call stack in several cases
   later attempts to take the write lock.

   The choices to fix it are I think:
   1) add an argument to indicate to ossl_method_store_do_all weather to
      take the read or write lock when doing iterations, and add an
      is_locked api to the ossl_property_[read|write] lock family so
      that subsequent callers can determine if they need to take a lock
      or not

   2) Clone the algs sparse array in ossl_method_store_do_all and use
      the clone to iterate with no lock held, ensuring that updates to
      the parent copy of the sparse array are left untouched during the
      iteration

I think method (2), while being a bit more expensive, is probably the
far less invasive way to go here

Fixes openssl#24672

This is the commit message #2:

amend! read lock store on ossl_method_store_do_all

read lock store on ossl_method_store_do_all

Theres a data race between ossl_method_store_insert and
ossl_method_store_do_all, as the latter doesn't take the property lock
before iterating.

However, we can't lock in do_all, as the call stack in several cases
later attempts to take the write lock.

The choices to fix it are I think:
1) add an argument to indicate to ossl_method_store_do_all weather to
   take the read or write lock when doing iterations, and add an
   is_locked api to the ossl_property_[read|write] lock family so that
   subsequent callers can determine if they need to take a lock or not

2) Clone the algs sparse array in ossl_method_store_do_all and use the
   clone to iterate with no lock held, ensuring that updates to the
   parent copy of the sparse array are left untoucheTheres a data race
   between ossl_method_store_insert and ossl_method_store_do_all, as the
   latter doesn't take the property lock before iterating.

I think method (2), while being a bit more expensive, is probably the
far less invasive way to go here

Fixes openssl#24672

This is the commit message #3:

fixup! amend! read lock store on ossl_method_store_do_all
Comment thread crypto/property/property.c Outdated
@paulidale
paulidale self-requested a review July 4, 2024 03:26
@openssl-machine openssl-machine removed the approval: done This pull request has the required number of approvals label Jul 9, 2024
@openssl-machine

Copy link
Copy Markdown
Collaborator

This pull request is ready to merge

@openssl-machine openssl-machine added the approval: ready to merge The 24 hour grace period has passed, ready to merge label Jul 9, 2024
@t8m

t8m commented Jul 9, 2024

Copy link
Copy Markdown
Member

Merged to all the active branches. Thank you.

@t8m t8m closed this Jul 9, 2024
openssl-machine pushed a commit that referenced this pull request Jul 9, 2024
Theres a data race between ossl_method_store_insert and
ossl_method_store_do_all, as the latter doesn't take the property lock
before iterating.

However, we can't lock in do_all, as the call stack in several cases
later attempts to take the write lock.

The choices to fix it are I think:
1) add an argument to indicate to ossl_method_store_do_all weather to
   take the read or write lock when doing iterations, and add an
   is_locked api to the ossl_property_[read|write] lock family so that
   subsequent callers can determine if they need to take a lock or not

2) Clone the algs sparse array in ossl_method_store_do_all and use the
   clone to iterate with no lock held, ensuring that updates to the
   parent copy of the sparse array are left untoucheTheres a data race
   between ossl_method_store_insert and ossl_method_store_do_all, as the
   latter doesn't take the property lock before iterating.

I think method (2), while being a bit more expensive, is probably the
far less invasive way to go here

Fixes #24672

Reviewed-by: Paul Dale <[email protected]>
Reviewed-by: Matt Caswell <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
(Merged from #24782)

(cherry picked from commit d8def79)
openssl-machine pushed a commit that referenced this pull request Jul 9, 2024
Theres a data race between ossl_method_store_insert and
ossl_method_store_do_all, as the latter doesn't take the property lock
before iterating.

However, we can't lock in do_all, as the call stack in several cases
later attempts to take the write lock.

The choices to fix it are I think:
1) add an argument to indicate to ossl_method_store_do_all weather to
   take the read or write lock when doing iterations, and add an
   is_locked api to the ossl_property_[read|write] lock family so that
   subsequent callers can determine if they need to take a lock or not

2) Clone the algs sparse array in ossl_method_store_do_all and use the
   clone to iterate with no lock held, ensuring that updates to the
   parent copy of the sparse array are left untoucheTheres a data race
   between ossl_method_store_insert and ossl_method_store_do_all, as the
   latter doesn't take the property lock before iterating.

I think method (2), while being a bit more expensive, is probably the
far less invasive way to go here

Fixes #24672

Reviewed-by: Paul Dale <[email protected]>
Reviewed-by: Matt Caswell <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
(Merged from #24782)
openssl-machine pushed a commit that referenced this pull request Jul 9, 2024
Theres a data race between ossl_method_store_insert and
ossl_method_store_do_all, as the latter doesn't take the property lock
before iterating.

However, we can't lock in do_all, as the call stack in several cases
later attempts to take the write lock.

The choices to fix it are I think:
1) add an argument to indicate to ossl_method_store_do_all weather to
   take the read or write lock when doing iterations, and add an
   is_locked api to the ossl_property_[read|write] lock family so that
   subsequent callers can determine if they need to take a lock or not

2) Clone the algs sparse array in ossl_method_store_do_all and use the
   clone to iterate with no lock held, ensuring that updates to the
   parent copy of the sparse array are left untoucheTheres a data race
   between ossl_method_store_insert and ossl_method_store_do_all, as the
   latter doesn't take the property lock before iterating.

I think method (2), while being a bit more expensive, is probably the
far less invasive way to go here

Fixes #24672

Reviewed-by: Paul Dale <[email protected]>
Reviewed-by: Matt Caswell <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
(Merged from #24782)

(cherry picked from commit d8def79)
openssl-machine pushed a commit that referenced this pull request Jul 9, 2024
Theres a data race between ossl_method_store_insert and
ossl_method_store_do_all, as the latter doesn't take the property lock
before iterating.

However, we can't lock in do_all, as the call stack in several cases
later attempts to take the write lock.

The choices to fix it are I think:
1) add an argument to indicate to ossl_method_store_do_all weather to
   take the read or write lock when doing iterations, and add an
   is_locked api to the ossl_property_[read|write] lock family so that
   subsequent callers can determine if they need to take a lock or not

2) Clone the algs sparse array in ossl_method_store_do_all and use the
   clone to iterate with no lock held, ensuring that updates to the
   parent copy of the sparse array are left untoucheTheres a data race
   between ossl_method_store_insert and ossl_method_store_do_all, as the
   latter doesn't take the property lock before iterating.

I think method (2), while being a bit more expensive, is probably the
far less invasive way to go here

Fixes #24672

Reviewed-by: Paul Dale <[email protected]>
Reviewed-by: Matt Caswell <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
(Merged from #24782)

(cherry picked from commit d8def79)
openssl-machine pushed a commit that referenced this pull request Jul 9, 2024
Theres a data race between ossl_method_store_insert and
ossl_method_store_do_all, as the latter doesn't take the property lock
before iterating.

However, we can't lock in do_all, as the call stack in several cases
later attempts to take the write lock.

The choices to fix it are I think:
1) add an argument to indicate to ossl_method_store_do_all weather to
   take the read or write lock when doing iterations, and add an
   is_locked api to the ossl_property_[read|write] lock family so that
   subsequent callers can determine if they need to take a lock or not

2) Clone the algs sparse array in ossl_method_store_do_all and use the
   clone to iterate with no lock held, ensuring that updates to the
   parent copy of the sparse array are left untoucheTheres a data race
   between ossl_method_store_insert and ossl_method_store_do_all, as the
   latter doesn't take the property lock before iterating.

I think method (2), while being a bit more expensive, is probably the
far less invasive way to go here

Fixes #24672

Reviewed-by: Paul Dale <[email protected]>
Reviewed-by: Matt Caswell <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
(Merged from #24782)

(cherry picked from commit d8def79)
rschu1ze added a commit to ClickHouse/openssl that referenced this pull request Jul 14, 2024
This reverts commit ee2bb85.

The PR was not finished yet, more commits were added later on.
rschu1ze pushed a commit to ClickHouse/openssl that referenced this pull request Jul 14, 2024
read lock store on ossl_method_store_do_all

Theres a data race between ossl_method_store_insert and
ossl_method_store_do_all, as the latter doesn't take the property lock
before iterating.

However, we can't lock in do_all, as the call stack in several cases
later attempts to take the write lock.

The choices to fix it are I think:
1) add an argument to indicate to ossl_method_store_do_all weather to
   take the read or write lock when doing iterations, and add an
   is_locked api to the ossl_property_[read|write] lock family so that
   subsequent callers can determine if they need to take a lock or not

2) Clone the algs sparse array in ossl_method_store_do_all and use the
   clone to iterate with no lock held, ensuring that updates to the
   parent copy of the sparse array are left untoucheTheres a data race
   between ossl_method_store_insert and ossl_method_store_do_all, as the
   latter doesn't take the property lock before iterating.

I think method (2), while being a bit more expensive, is probably the
far less invasive way to go here

Fixes openssl#24672

Reviewed-by: Paul Dale <[email protected]>
Reviewed-by: Matt Caswell <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
(Merged from openssl#24782)

(cherry picked from commit d8def79)
eclipse-oniro-oh-bot pushed a commit to eclipse-oniro-mirrors/third_party_openssl that referenced this pull request Sep 6, 2024
Theres a data race between ossl_method_store_insert and
ossl_method_store_do_all, as the latter doesn't take the property lock
before iterating.

However, we can't lock in do_all, as the call stack in several cases
later attempts to take the write lock.

The choices to fix it are I think:
1) add an argument to indicate to ossl_method_store_do_all weather to
   take the read or write lock when doing iterations, and add an
   is_locked api to the ossl_property_[read|write] lock family so that
   subsequent callers can determine if they need to take a lock or not

2) Clone the algs sparse array in ossl_method_store_do_all and use the
   clone to iterate with no lock held, ensuring that updates to the
   parent copy of the sparse array are left untoucheTheres a data race
   between ossl_method_store_insert and ossl_method_store_do_all, as the
   latter doesn't take the property lock before iterating.

I think method (2), while being a bit more expensive, is probably the
far less invasive way to go here

Fixes #24672

Reviewed-by: Paul Dale <[email protected]>
Reviewed-by: Matt Caswell <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
(Merged from openssl/openssl#24782)

(cherry picked from commit d8def79838cd0d5e7c21d217aa26edb5229f0ab4)
Signed-off-by: 王静 <[email protected]>
rschu1ze pushed a commit to ClickHouse/openssl that referenced this pull request Sep 6, 2024
read lock store on ossl_method_store_do_all

Theres a data race between ossl_method_store_insert and
ossl_method_store_do_all, as the latter doesn't take the property lock
before iterating.

However, we can't lock in do_all, as the call stack in several cases
later attempts to take the write lock.

The choices to fix it are I think:
1) add an argument to indicate to ossl_method_store_do_all weather to
   take the read or write lock when doing iterations, and add an
   is_locked api to the ossl_property_[read|write] lock family so that
   subsequent callers can determine if they need to take a lock or not

2) Clone the algs sparse array in ossl_method_store_do_all and use the
   clone to iterate with no lock held, ensuring that updates to the
   parent copy of the sparse array are left untoucheTheres a data race
   between ossl_method_store_insert and ossl_method_store_do_all, as the
   latter doesn't take the property lock before iterating.

I think method (2), while being a bit more expensive, is probably the
far less invasive way to go here

Fixes openssl#24672

Reviewed-by: Paul Dale <[email protected]>
Reviewed-by: Matt Caswell <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
(Merged from openssl#24782)

(cherry picked from commit d8def79)
eclipse-oniro-oh-bot pushed a commit to eclipse-oniro-mirrors/third_party_openssl that referenced this pull request Sep 7, 2024
Theres a data race between ossl_method_store_insert and
ossl_method_store_do_all, as the latter doesn't take the property lock
before iterating.

However, we can't lock in do_all, as the call stack in several cases
later attempts to take the write lock.

The choices to fix it are I think:
1) add an argument to indicate to ossl_method_store_do_all weather to
   take the read or write lock when doing iterations, and add an
   is_locked api to the ossl_property_[read|write] lock family so that
   subsequent callers can determine if they need to take a lock or not

2) Clone the algs sparse array in ossl_method_store_do_all and use the
   clone to iterate with no lock held, ensuring that updates to the
   parent copy of the sparse array are left untoucheTheres a data race
   between ossl_method_store_insert and ossl_method_store_do_all, as the
   latter doesn't take the property lock before iterating.

I think method (2), while being a bit more expensive, is probably the
far less invasive way to go here

Fixes #24672

Reviewed-by: Paul Dale <[email protected]>
Reviewed-by: Matt Caswell <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
(Merged from openssl/openssl#24782)

(cherry picked from commit d8def79838cd0d5e7c21d217aa26edb5229f0ab4)
Signed-off-by: 王静 <[email protected]>
eclipse-oniro-oh-bot pushed a commit to eclipse-oniro-mirrors/third_party_openssl that referenced this pull request Oct 4, 2024
Theres a data race between ossl_method_store_insert and
ossl_method_store_do_all, as the latter doesn't take the property lock
before iterating.

However, we can't lock in do_all, as the call stack in several cases
later attempts to take the write lock.

The choices to fix it are I think:
1) add an argument to indicate to ossl_method_store_do_all weather to
   take the read or write lock when doing iterations, and add an
   is_locked api to the ossl_property_[read|write] lock family so that
   subsequent callers can determine if they need to take a lock or not

2) Clone the algs sparse array in ossl_method_store_do_all and use the
   clone to iterate with no lock held, ensuring that updates to the
   parent copy of the sparse array are left untoucheTheres a data race
   between ossl_method_store_insert and ossl_method_store_do_all, as the
   latter doesn't take the property lock before iterating.

I think method (2), while being a bit more expensive, is probably the
far less invasive way to go here

Fixes #24672

Reviewed-by: Paul Dale <[email protected]>
Reviewed-by: Matt Caswell <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
(Merged from openssl/openssl#24782)

(cherry picked from commit d8def79838cd0d5e7c21d217aa26edb5229f0ab4)
Signed-off-by: 王静 <[email protected]>
@vavroch2010 vavroch2010 moved this from Waiting Review to Done in Development Board Mar 2, 2025
nhorman added a commit to nhorman/openssl that referenced this pull request Oct 8, 2025
PR openssl#24782 introduced a copying of
the algs stack in ossl_method_store_do all, so that the subsequent
iteration of elements through alg_do_one could be done without a lock,
and without triggering a tsan error as reported in:
openssl#24672

However, the problem wasn't completely fixed.  Issue:
openssl#27726

Noted that, sometimes we still get a crash when iterating over each algs
impls stack.  This occurs because, even though we've cloned the algs to
a private data area, the impls stack for each alg still points to shared
data, which we are accessing without the benefit of a lock.  Because of
that, if some other thread calls a function that mutates the impl stack
(say ossl_method_store_remove()), we may encounter a NULL or garbage
value in one of the impl stack values, leading to an unexpected NULL
pointer or simmilar, which in turn leads to a crash.

Unfortunately we can't use a lock to create exclusive access here, as
there are several paths that lead to a recursive mutation of the stack,
which would deadlock.

So the only way that I see to prevent this (which is admittedly ugly),
is to not only clone the alg stack, but to duplicate each algs impl
stack with the read lock held, prior to doing the iteration.

Further, we've been unable to test this, as the problem is rare, and we
don't have a solid reproducer for the issue, but visual inspection
suggests this should fix that.  Hopefully:

Fixes openssl#27726
openssl-machine pushed a commit that referenced this pull request Oct 23, 2025
PR #24782 introduced a copying of
the algs stack in ossl_method_store_do all, so that the subsequent
iteration of elements through alg_do_one could be done without a lock,
and without triggering a tsan error as reported in:
#24672

However, the problem wasn't completely fixed.  Issue:
#27726

Noted that, sometimes we still get a crash when iterating over each algs
impls stack.  This occurs because, even though we've cloned the algs to
a private data area, the impls stack for each alg still points to shared
data, which we are accessing without the benefit of a lock.  Because of
that, if some other thread calls a function that mutates the impl stack
(say ossl_method_store_remove()), we may encounter a NULL or garbage
value in one of the impl stack values, leading to an unexpected NULL
pointer or simmilar, which in turn leads to a crash.

Unfortunately we can't use a lock to create exclusive access here, as
there are several paths that lead to a recursive mutation of the stack,
which would deadlock.

So the only way that I see to prevent this (which is admittedly ugly),
is to not only clone the alg stack, but to duplicate each algs impl
stack with the read lock held, prior to doing the iteration.

Further, we've been unable to test this, as the problem is rare, and we
don't have a solid reproducer for the issue, but visual inspection
suggests this should fix that.  Hopefully:

Fixes #27726

Reviewed-by: Saša Nedvědický <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
(Merged from #28783)

(cherry picked from commit 9ef4f42)
openssl-machine pushed a commit that referenced this pull request Oct 23, 2025
PR #24782 introduced a copying of
the algs stack in ossl_method_store_do all, so that the subsequent
iteration of elements through alg_do_one could be done without a lock,
and without triggering a tsan error as reported in:
#24672

However, the problem wasn't completely fixed.  Issue:
#27726

Noted that, sometimes we still get a crash when iterating over each algs
impls stack.  This occurs because, even though we've cloned the algs to
a private data area, the impls stack for each alg still points to shared
data, which we are accessing without the benefit of a lock.  Because of
that, if some other thread calls a function that mutates the impl stack
(say ossl_method_store_remove()), we may encounter a NULL or garbage
value in one of the impl stack values, leading to an unexpected NULL
pointer or simmilar, which in turn leads to a crash.

Unfortunately we can't use a lock to create exclusive access here, as
there are several paths that lead to a recursive mutation of the stack,
which would deadlock.

So the only way that I see to prevent this (which is admittedly ugly),
is to not only clone the alg stack, but to duplicate each algs impl
stack with the read lock held, prior to doing the iteration.

Further, we've been unable to test this, as the problem is rare, and we
don't have a solid reproducer for the issue, but visual inspection
suggests this should fix that.  Hopefully:

Fixes #27726

Reviewed-by: Saša Nedvědický <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
(Merged from #28783)
openssl-machine pushed a commit that referenced this pull request Oct 23, 2025
PR #24782 introduced a copying of
the algs stack in ossl_method_store_do all, so that the subsequent
iteration of elements through alg_do_one could be done without a lock,
and without triggering a tsan error as reported in:
#24672

However, the problem wasn't completely fixed.  Issue:
#27726

Noted that, sometimes we still get a crash when iterating over each algs
impls stack.  This occurs because, even though we've cloned the algs to
a private data area, the impls stack for each alg still points to shared
data, which we are accessing without the benefit of a lock.  Because of
that, if some other thread calls a function that mutates the impl stack
(say ossl_method_store_remove()), we may encounter a NULL or garbage
value in one of the impl stack values, leading to an unexpected NULL
pointer or simmilar, which in turn leads to a crash.

Unfortunately we can't use a lock to create exclusive access here, as
there are several paths that lead to a recursive mutation of the stack,
which would deadlock.

So the only way that I see to prevent this (which is admittedly ugly),
is to not only clone the alg stack, but to duplicate each algs impl
stack with the read lock held, prior to doing the iteration.

Further, we've been unable to test this, as the problem is rare, and we
don't have a solid reproducer for the issue, but visual inspection
suggests this should fix that.  Hopefully:

Fixes #27726

Reviewed-by: Saša Nedvědický <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
(Merged from #28783)

(cherry picked from commit 9ef4f42)
openssl-machine pushed a commit that referenced this pull request Oct 23, 2025
PR #24782 introduced a copying of
the algs stack in ossl_method_store_do all, so that the subsequent
iteration of elements through alg_do_one could be done without a lock,
and without triggering a tsan error as reported in:
#24672

However, the problem wasn't completely fixed.  Issue:
#27726

Noted that, sometimes we still get a crash when iterating over each algs
impls stack.  This occurs because, even though we've cloned the algs to
a private data area, the impls stack for each alg still points to shared
data, which we are accessing without the benefit of a lock.  Because of
that, if some other thread calls a function that mutates the impl stack
(say ossl_method_store_remove()), we may encounter a NULL or garbage
value in one of the impl stack values, leading to an unexpected NULL
pointer or simmilar, which in turn leads to a crash.

Unfortunately we can't use a lock to create exclusive access here, as
there are several paths that lead to a recursive mutation of the stack,
which would deadlock.

So the only way that I see to prevent this (which is admittedly ugly),
is to not only clone the alg stack, but to duplicate each algs impl
stack with the read lock held, prior to doing the iteration.

Further, we've been unable to test this, as the problem is rare, and we
don't have a solid reproducer for the issue, but visual inspection
suggests this should fix that.  Hopefully:

Fixes #27726

Reviewed-by: Saša Nedvědický <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
(Merged from #28783)

(cherry picked from commit 9ef4f42)
openssl-machine pushed a commit that referenced this pull request Oct 23, 2025
PR #24782 introduced a copying of
the algs stack in ossl_method_store_do all, so that the subsequent
iteration of elements through alg_do_one could be done without a lock,
and without triggering a tsan error as reported in:
#24672

However, the problem wasn't completely fixed.  Issue:
#27726

Noted that, sometimes we still get a crash when iterating over each algs
impls stack.  This occurs because, even though we've cloned the algs to
a private data area, the impls stack for each alg still points to shared
data, which we are accessing without the benefit of a lock.  Because of
that, if some other thread calls a function that mutates the impl stack
(say ossl_method_store_remove()), we may encounter a NULL or garbage
value in one of the impl stack values, leading to an unexpected NULL
pointer or simmilar, which in turn leads to a crash.

Unfortunately we can't use a lock to create exclusive access here, as
there are several paths that lead to a recursive mutation of the stack,
which would deadlock.

So the only way that I see to prevent this (which is admittedly ugly),
is to not only clone the alg stack, but to duplicate each algs impl
stack with the read lock held, prior to doing the iteration.

Further, we've been unable to test this, as the problem is rare, and we
don't have a solid reproducer for the issue, but visual inspection
suggests this should fix that.  Hopefully:

Fixes #27726

Reviewed-by: Saša Nedvědický <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
(Merged from #28783)

(cherry picked from commit 9ef4f42)
openssl-machine pushed a commit that referenced this pull request Oct 23, 2025
PR #24782 introduced a copying of
the algs stack in ossl_method_store_do all, so that the subsequent
iteration of elements through alg_do_one could be done without a lock,
and without triggering a tsan error as reported in:
#24672

However, the problem wasn't completely fixed.  Issue:
#27726

Noted that, sometimes we still get a crash when iterating over each algs
impls stack.  This occurs because, even though we've cloned the algs to
a private data area, the impls stack for each alg still points to shared
data, which we are accessing without the benefit of a lock.  Because of
that, if some other thread calls a function that mutates the impl stack
(say ossl_method_store_remove()), we may encounter a NULL or garbage
value in one of the impl stack values, leading to an unexpected NULL
pointer or simmilar, which in turn leads to a crash.

Unfortunately we can't use a lock to create exclusive access here, as
there are several paths that lead to a recursive mutation of the stack,
which would deadlock.

So the only way that I see to prevent this (which is admittedly ugly),
is to not only clone the alg stack, but to duplicate each algs impl
stack with the read lock held, prior to doing the iteration.

Further, we've been unable to test this, as the problem is rare, and we
don't have a solid reproducer for the issue, but visual inspection
suggests this should fix that.  Hopefully:

Fixes #27726

Reviewed-by: Saša Nedvědický <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
(Merged from #28783)

(cherry picked from commit 9ef4f42)
openssl-machine pushed a commit that referenced this pull request Oct 23, 2025
PR #24782 introduced a copying of
the algs stack in ossl_method_store_do all, so that the subsequent
iteration of elements through alg_do_one could be done without a lock,
and without triggering a tsan error as reported in:
#24672

However, the problem wasn't completely fixed.  Issue:
#27726

Noted that, sometimes we still get a crash when iterating over each algs
impls stack.  This occurs because, even though we've cloned the algs to
a private data area, the impls stack for each alg still points to shared
data, which we are accessing without the benefit of a lock.  Because of
that, if some other thread calls a function that mutates the impl stack
(say ossl_method_store_remove()), we may encounter a NULL or garbage
value in one of the impl stack values, leading to an unexpected NULL
pointer or simmilar, which in turn leads to a crash.

Unfortunately we can't use a lock to create exclusive access here, as
there are several paths that lead to a recursive mutation of the stack,
which would deadlock.

So the only way that I see to prevent this (which is admittedly ugly),
is to not only clone the alg stack, but to duplicate each algs impl
stack with the read lock held, prior to doing the iteration.

Further, we've been unable to test this, as the problem is rare, and we
don't have a solid reproducer for the issue, but visual inspection
suggests this should fix that.  Hopefully:

Fixes #27726

Reviewed-by: Saša Nedvědický <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
(Merged from #28783)

(cherry picked from commit 9ef4f42)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approval: ready to merge The 24 hour grace period has passed, ready to merge branch: master Applies to master branch branch: 3.0 Applies to openssl-3.0 branch (EOL) branch: 3.1 Applies to openssl-3.1 (EOL) branch: 3.2 Applies to openssl-3.2 (EOL) branch: 3.3 Applies to openssl-3.3 (EOL) severity: fips change The pull request changes FIPS provider sources tests: exempted The PR is exempt from requirements for testing triaged: bug The issue/pr is/fixes a bug

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Tsan data race between sa_doall and ossl_sa_set

6 participants