ipa: fall back to in-process mode when isolation fails
diff mbox series

Message ID 20260323170700.105171-1-dev@fredfunk.tech
State New
Headers show
Series
  • ipa: fall back to in-process mode when isolation fails
Related show

Commit Message

Frederic Laing March 23, 2026, 5:07 p.m. UTC
When the isolated IPA proxy fails to start (e.g. because fork() is
blocked by a sandbox's seccomp filter), fall back to loading the IPA
module in-process using the Threaded proxy instead of failing entirely.

This enables libcamera to work inside Flatpak and other sandboxed
environments where process isolation via clone3() with CLONE_NEWUSER
and CLONE_NEWNET is not permitted.

When isolation is explicitly forced via LIBCAMERA_IPA_FORCE_ISOLATION
or the ipa.force_isolation configuration option, the fallback is
suppressed and the proxy creation fails with an error instead, to
preserve the intended security policy.

Tested on OnePlus 6T (Qualcomm SDM845) with IMX371 front camera.
Tested on Google Pixel 3a (Qualcomm SDM670) with IMX355 front camera.

Signed-off-by: Frederic Laing <dev@fredfunk.tech>
---
 include/libcamera/internal/ipa_manager.h | 29 ++++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)

Comments

Kieran Bingham March 23, 2026, 5:14 p.m. UTC | #1
Quoting Frederic Laing (2026-03-23 17:07:58)
> When the isolated IPA proxy fails to start (e.g. because fork() is
> blocked by a sandbox's seccomp filter), fall back to loading the IPA
> module in-process using the Threaded proxy instead of failing entirely.

I'm sorry - but I don't think we can do this.


> This enables libcamera to work inside Flatpak and other sandboxed
> environments where process isolation via clone3() with CLONE_NEWUSER
> and CLONE_NEWNET is not permitted.
> 
> When isolation is explicitly forced via LIBCAMERA_IPA_FORCE_ISOLATION
> or the ipa.force_isolation configuration option, the fallback is
> suppressed and the proxy creation fails with an error instead, to
> preserve the intended security policy.

But the isolation for unsigned modules *is* the default intended
security policy. This patch would completely bypass it.

I feel bad, as I would rarely do this but:

Nacked-by: Kieran Bingham <kieran.bingham@ideasonboard.com>




> 
> Tested on OnePlus 6T (Qualcomm SDM845) with IMX371 front camera.
> Tested on Google Pixel 3a (Qualcomm SDM670) with IMX355 front camera.


But why are you hitting this ? If you are running on those platforms you
should be running with the softIPA with signatures - so you should not
be running an isolated module.

This makes me suspect you have a build configuration issue rather than a
security issue here to solve.

--
Kieran



> 
> Signed-off-by: Frederic Laing <dev@fredfunk.tech>
> ---
>  include/libcamera/internal/ipa_manager.h | 29 ++++++++++++++++++++++--
>  1 file changed, 27 insertions(+), 2 deletions(-)
> 
> diff --git a/include/libcamera/internal/ipa_manager.h b/include/libcamera/internal/ipa_manager.h
> index f8ce7801..03553711 100644
> --- a/include/libcamera/internal/ipa_manager.h
> +++ b/include/libcamera/internal/ipa_manager.h
> @@ -48,8 +48,33 @@ public:
>                 auto proxy = [&]() -> std::unique_ptr<T> {
>                         if (self->isSignatureValid(m))
>                                 return std::make_unique<typename T::Threaded>(m, configuration);
> -                       else
> -                               return std::make_unique<typename T::Isolated>(m, configuration);
> +
> +                       auto isolated = std::make_unique<typename T::Isolated>(m, configuration);
> +                       if (isolated->isValid())
> +                               return isolated;
> +
> +#if HAVE_IPA_PUBKEY
> +                       if (self->forceIsolation_) {
> +                               LOG(IPAManager, Error)
> +                                       << "IPA process isolation failed for "
> +                                       << m->path()
> +                                       << " and isolation is forced";
> +                               return isolated;
> +                       }
> +#endif
> +
> +                       /*
> +                        * Fall back to in-process loading when process
> +                        * isolation fails. This typically happens inside
> +                        * sandboxed environments (e.g. Flatpak) where
> +                        * fork() is blocked by the seccomp filter.
> +                        */
> +                       LOG(IPAManager, Warning)
> +                               << "IPA process isolation failed for "
> +                               << m->path()
> +                               << ", falling back to in-process mode";
> +
> +                       return std::make_unique<typename T::Threaded>(m, configuration);
>                 }();
>  
>                 if (!proxy->isValid()) {
> -- 
> 2.53.0
> 
>
Barnabás Pőcze March 23, 2026, 5:24 p.m. UTC | #2
Hi


Thanks for the patch.

2026. 03. 23. 18:07 keltezéssel, Frederic Laing írta:
> When the isolated IPA proxy fails to start (e.g. because fork() is
> blocked by a sandbox's seccomp filter), fall back to loading the IPA
> module in-process using the Threaded proxy instead of failing entirely.
> 
> This enables libcamera to work inside Flatpak and other sandboxed
> environments where process isolation via clone3() with CLONE_NEWUSER
> and CLONE_NEWNET is not permitted.
> 
> When isolation is explicitly forced via LIBCAMERA_IPA_FORCE_ISOLATION
> or the ipa.force_isolation configuration option, the fallback is
> suppressed and the proxy creation fails with an error instead, to
> preserve the intended security policy.

I am afraid I'll have to disagree here. As far as I understand, the security
policy is: no valid signature -> no in-process operation. This change obviously
breaks that.


> 
> Tested on OnePlus 6T (Qualcomm SDM845) with IMX371 front camera.
> Tested on Google Pixel 3a (Qualcomm SDM670) with IMX355 front camera.

Those use the simple pipeline handler, no? In that case there should be
no IPA isolation in the first place. If there is, that is a (partly) distribution
issue. There is https://gitlab.freedesktop.org/camera/libcamera/-/issues/233
to track the conflict with reproducible builds. It would be very helpful
if you could determine why IPA isolation is chosen on your devices.

Furthermore, the idea that a sandbox disallows fork but allows access to
media and v4l2 devices seems somewhat odd. The latter is arguably a much
larger attack surface. Also, it's probably best to use pipewire to get
video stream into a flatpak sandbox via the camera portal.


Regards,
Barnabás Pőcze


> 
> Signed-off-by: Frederic Laing <dev@fredfunk.tech>
> ---
>   include/libcamera/internal/ipa_manager.h | 29 ++++++++++++++++++++++--
>   1 file changed, 27 insertions(+), 2 deletions(-)
> 
> diff --git a/include/libcamera/internal/ipa_manager.h b/include/libcamera/internal/ipa_manager.h
> index f8ce7801..03553711 100644
> --- a/include/libcamera/internal/ipa_manager.h
> +++ b/include/libcamera/internal/ipa_manager.h
> @@ -48,8 +48,33 @@ public:
>   		auto proxy = [&]() -> std::unique_ptr<T> {
>   			if (self->isSignatureValid(m))
>   				return std::make_unique<typename T::Threaded>(m, configuration);
> -			else
> -				return std::make_unique<typename T::Isolated>(m, configuration);
> +
> +			auto isolated = std::make_unique<typename T::Isolated>(m, configuration);
> +			if (isolated->isValid())
> +				return isolated;
> +
> +#if HAVE_IPA_PUBKEY
> +			if (self->forceIsolation_) {
> +				LOG(IPAManager, Error)
> +					<< "IPA process isolation failed for "
> +					<< m->path()
> +					<< " and isolation is forced";
> +				return isolated;
> +			}
> +#endif
> +
> +			/*
> +			 * Fall back to in-process loading when process
> +			 * isolation fails. This typically happens inside
> +			 * sandboxed environments (e.g. Flatpak) where
> +			 * fork() is blocked by the seccomp filter.
> +			 */
> +			LOG(IPAManager, Warning)
> +				<< "IPA process isolation failed for "
> +				<< m->path()
> +				<< ", falling back to in-process mode";
> +
> +			return std::make_unique<typename T::Threaded>(m, configuration);
>   		}();
>   
>   		if (!proxy->isValid()) {

Patch
diff mbox series

diff --git a/include/libcamera/internal/ipa_manager.h b/include/libcamera/internal/ipa_manager.h
index f8ce7801..03553711 100644
--- a/include/libcamera/internal/ipa_manager.h
+++ b/include/libcamera/internal/ipa_manager.h
@@ -48,8 +48,33 @@  public:
 		auto proxy = [&]() -> std::unique_ptr<T> {
 			if (self->isSignatureValid(m))
 				return std::make_unique<typename T::Threaded>(m, configuration);
-			else
-				return std::make_unique<typename T::Isolated>(m, configuration);
+
+			auto isolated = std::make_unique<typename T::Isolated>(m, configuration);
+			if (isolated->isValid())
+				return isolated;
+
+#if HAVE_IPA_PUBKEY
+			if (self->forceIsolation_) {
+				LOG(IPAManager, Error)
+					<< "IPA process isolation failed for "
+					<< m->path()
+					<< " and isolation is forced";
+				return isolated;
+			}
+#endif
+
+			/*
+			 * Fall back to in-process loading when process
+			 * isolation fails. This typically happens inside
+			 * sandboxed environments (e.g. Flatpak) where
+			 * fork() is blocked by the seccomp filter.
+			 */
+			LOG(IPAManager, Warning)
+				<< "IPA process isolation failed for "
+				<< m->path()
+				<< ", falling back to in-process mode";
+
+			return std::make_unique<typename T::Threaded>(m, configuration);
 		}();
 
 		if (!proxy->isValid()) {