Skip to content

fix(gcp): make gen2 Cloud Functions IAM policy query thread-safe#12107

Open
stefanobaldo wants to merge 1 commit into
prowler-cloud:masterfrom
stefanobaldo:fix/gcp-cloudfunction-gen2-iam-thread-safety
Open

fix(gcp): make gen2 Cloud Functions IAM policy query thread-safe#12107
stefanobaldo wants to merge 1 commit into
prowler-cloud:masterfrom
stefanobaldo:fix/gcp-cloudfunction-gen2-iam-thread-safety

Conversation

@stefanobaldo

@stefanobaldo stefanobaldo commented Jul 23, 2026

Copy link
Copy Markdown

Context

Fix #12106

CloudFunction._get_function_iam_policy is fanned out one thread per function by
GCPService.__threading_call__ (prowler/providers/gcp/lib/service/service.py:44,
which starts a raw threading.Thread per item). httplib2 is not thread-safe.

Every other threaded GCP call isolates each thread by passing a fresh transport to
.execute(http=self.__get_AuthorizedHttp_client__(), ...) — including the gen1
branch of this very method. The gen2 branch does not: it calls .execute() on
the shared self._run_client discovery client
(prowler/providers/gcp/services/cloudfunction/cloudfunction_service.py). When a
project has several gen2 Cloud Functions, the threads issue concurrent requests
through that one shared client and corrupt the process heap, aborting the whole
scan. It reproduces reliably in containerized, multi-vCPU environments (e.g. Cloud
Run). Captured with PYTHONFAULTHANDLER=1 — every crashing thread shares the same
frame, the classic non-thread-safe-httplib2 signature:

Fatal Python error: Aborted
  # also observed as SIGSEGV / "malloc(): unsorted double linked list corrupted"

Current thread (most recent call first):
  File ".../httplib2/__init__.py", line 1399 in _conn_request
  File ".../google_auth_httplib2.py", line 218 in request
  File ".../googleapiclient/http.py", line 923 in execute
  File ".../gcp/services/cloudfunction/cloudfunction_service.py", line 111 in _get_function_iam_policy
  File ".../threading.py", line 1012 in run

An audit of every __threading_call__ target in the GCP provider confirms this is
the only threaded call that shares a client instead of passing a per-request http.

Description

prowler/providers/gcp/services/cloudfunction/cloudfunction_service.py — pass a
per-request HTTP client to the gen2 getIamPolicy().execute() call, exactly as the
gen1 branch immediately below already does:

.execute(
    http=self.__get_AuthorizedHttp_client__(),
    num_retries=DEFAULT_RETRY_ATTEMPTS,
)

This gives each thread its own httplib2 transport, removing the shared-client data
race. Parallelism is unchanged (no serialization) and findings are unaffected.

Steps to review

  1. cloudfunction_service.py — the gen2 .execute() now receives
    http=self.__get_AuthorizedHttp_client__(), matching the gen1 branch a few lines
    below.

  2. New regression test asserts the gen2 IAM lookup is executed with a per-request
    http (a shared-client call would omit it):

    uv run pytest tests/providers/gcp/services/cloudfunction/cloudfunction_service_test.py -q
    

    (7 passed)

  3. Optional real-world repro: scan a GCP project with several gen2 Cloud
    Functions from a multi-vCPU container. Before: intermittent heap-corruption abort
    during the cloudfunction service. After: the scan completes and reports Cloud
    Function IAM findings.

Checklist

SDK/CLI

  • Are there new checks included in this PR? No
    • No new permissions required for the provider.

License

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Summary by CodeRabbit

  • Bug Fixes

    • Improved reliability when retrieving IAM policies for second-generation Cloud Functions.
    • Prevented potential process crashes when multiple functions are processed concurrently.
  • Tests

    • Added coverage to verify safe IAM policy retrieval for second-generation Cloud Functions.

CloudFunction._get_function_iam_policy runs once per function across a
thread pool (GCPService.__threading_call__), and httplib2 is not
thread-safe. The gen1 branch isolates each thread with its own
AuthorizedHttp via .execute(http=self.__get_AuthorizedHttp_client__()),
but the gen2 branch calls .execute() on the shared self._run_client. When
a project has several gen2 functions the concurrent requests corrupt the
process heap and abort the scan (SIGABRT/SIGSEGV, "malloc(): unsorted
double linked list corrupted").

Pass a per-request http client to the gen2 getIamPolicy().execute(),
mirroring the gen1 branch. This removes the shared-client data race while
keeping the per-resource parallelism. Adds a regression test and a
changelog fragment.
@stefanobaldo
stefanobaldo requested a review from a team as a code owner July 23, 2026 20:03
@github-actions github-actions Bot added the provider/gcp Issues/PRs related with the Google Cloud Platform provider label Jul 23, 2026
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d1dce7cc-e8a1-47d4-884f-92d36e4ddf25

📥 Commits

Reviewing files that changed from the base of the PR and between b80e3a7 and 14b0bfa.

📒 Files selected for processing (3)
  • prowler/changelog.d/gcp-cloudfunction-gen2-iam-thread-safety.fixed.md
  • prowler/providers/gcp/services/cloudfunction/cloudfunction_service.py
  • tests/providers/gcp/services/cloudfunction/cloudfunction_service_test.py

📝 Walkthrough

Walkthrough

Cloud Functions Gen2 IAM policy retrieval now passes a per-request authorized HTTP client to Cloud Run’s getIamPolicy request. A regression test verifies the transport argument, and the changelog records the thread-safety fix.

Changes

Cloud Functions Gen2 IAM thread safety

Layer / File(s) Summary
Per-request HTTP client for Gen2 IAM lookup
prowler/providers/gcp/services/cloudfunction/cloudfunction_service.py, tests/providers/gcp/services/cloudfunction/cloudfunction_service_test.py, prowler/changelog.d/...
The Gen2 getIamPolicy execution now receives an authorized HTTP client, with a regression test asserting the http argument and a changelog entry documenting the update.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested reviewers: s1ns3nz0

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the gen2 Cloud Functions IAM thread-safety fix.
Description check ✅ Passed The PR description follows the template and includes context, summary, review steps, checklist, and license.
Linked Issues check ✅ Passed The code and regression test address #12106 by using a fresh HTTP client for gen2 IAM policy requests.
Out of Scope Changes check ✅ Passed All changes are relevant to the fix: code, regression test, and changelog fragment.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the community Opened by the Community label Jul 23, 2026
@github-actions

Copy link
Copy Markdown
Contributor

No Conflicts

No conflict markers, and the branch merges cleanly into its base.

@HugoPBrito HugoPBrito self-assigned this Jul 24, 2026
@HugoPBrito

Copy link
Copy Markdown
Member

Thanks @stefanobaldo! We'll review this as soon as possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community Opened by the Community provider/gcp Issues/PRs related with the Google Cloud Platform provider

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GCP: scan aborts with heap corruption on projects with gen2 Cloud Functions (thread-unsafe httplib2)

2 participants