Skip to content
DnsLister Forum

Where domain hunters compare notes

Dissecting JioPC: Flatpak sandbox breakout, reverse-engineering xrdp session limits, and running a headless remote server on locked-down cloud VDI

I recently got access to JioPC (a budget browser-based cloud desktop aimed at light office work in India) to see how the platform was provisioned and locked down.

While marketed as a low-cost, web-based thin client, inspecting the user environment revealed an enterprise Azure VM running an Ice Lake Xeon node. More interesting was the security model: a "walled garden" that omits default terminal binaries, aggressive session tear-downs in the display stack, and strict egress proxies.

Here is an architectural breakdown of how the environment is restricted, how to break out to an unconfined host shell via Flatpak, how the display daemon terminates idle sessions, and how to run a persistent headless SSH box over Tailscale.

Full whitepaper, disassembly notes, and reproduction scripts:

GitHub: sys-dissect/jiopc-architecture-whitepaper

1. Underlying Node & Kernel Environment

Poking around /proc and /sys shows the underlying compute instance is far heavier than standard thin-client specs:

  • CPU: 8-vCPU Intel Xeon Platinum 8370C (Ice Lake-SP) @ 2.80 GHz. AVX-512 (F, BW, DQ, VL) and VNNI vector extensions are exposed. The scaling governor is set to performance.
  • Memory: 16 GB virtualized RAM with Transparent Huge Pages (madvise/always) enabled.
  • Storage Topology: The root OS disk (/) is an ephemeral 64 GB virtual SSD. The persistent user home directory (/home/...) is an enterprise NFSv4.1 mount (storage-cons-prod-dp.jiopc.local). In raw unbuffered tests (fdatasync writing 100 GiB), the NFS pipe sustained 581 MB/s (~4.65 Gbps continuous network throughput).

2. The "No-Terminal" GUI & Flatpak Host Breakout

Stock JioPC ships without a terminal emulator—no gnome-terminal, konsole, xterm, or qterminal in $PATH, and desktop file entries for shells are stripped from the desktop environment menu. The apparent assumption was: no terminal binary = no shell access.

However, their curated software catalog provides VSCodium packaged as a Flatpak (com.vscodium.codium). Because development environments require host-level toolchains, the Flatpak manifest includes:

--talk-name=org.freedesktop.Flatpak 

From VSCodium's integrated terminal, you can call the session helper directly:

flatpak-spawn --host bash 

The Flatpak portal daemon immediately allocates a PTY and executes an unconfined shell directly in the host OS user namespace (UID 3387120), completely circumventing the Flatpak bubble and exposing the entire host userland across all 8 Xeon cores.

3. Dissecting the 15-Minute Session Guillotine (xrdp + systemd-logind)

A major usability hurdle in browser-delivered VDIs is aggressive idling: sessions are killed after 15 minutes of inactivity, terminating background builds and daemons.

Disassembly

Analyzing /usr/lib/xorg/modules/libxorgxrdp.so revealed hardcoded idle limits:

XRDP_SESMAN_MAX_IDLE_TIME=900 // 15-minute window XRDP_SESMAN_KILL_DISCONNECTED=1 

Why standard X11 jitter scripts fail

Injecting synthetic input via xdotool or xte does nothing. The custom xorgxrdp driver monitors incoming RDP protocol packets rather than X11 server input events. When browser WebRTC connections drop or sit idle, no RDP traffic reaches the driver.

Furthermore, with systemd-logind configured to KillUserProcesses=yes (or default Linger=no), disconnecting causes logind to issue a recursive SIGKILL against the entire user@UID.service slice.

The Bypass

  1. Enable lingering to persist processes outside of active sessions:

loginctl enable-linger 
  1. Exploit an audio IPC override: libxorgxrdp includes an internal check XRDP_SESMAN_AUDIO_DISABLE_IDLETIMEOUT=1. A lightweight background daemon writing synthetic sound_playing heartbeat frames to the XRDP audio IPC socket every 30 seconds prevents the idle watchdog from firing, keeping the session alive indefinitely.

4. Headless Remote Dev Environment (Userspace Tailscale + OpenSSH)

Direct outbound internet is filtered through a mandatory local HTTP proxy (127.0.0.1:3128), and /dev/net/tun is unavailable without root/CAP_NET_ADMIN.

To turn this into a permanent remote headless machine accessible outside the browser wrapper:

  1. Userspace Networking: Run Tailscale using its userspace engine via Google's gVisor network stack:

tailscale up --tun=userspace-networking --accept-dns=false 

Note: Setting --accept-dns=false is critical; otherwise, MagicDNS attempts to manage resolvers and breaks internal datacenter DNS (10.163.66.132), which the local HTTP proxy requires to resolve external hosts.

  1. Unprivileged SSH: Run OpenSSH server bound to non-standard user port 2222 with a custom sshd_config.

  2. Tailscale Serve: Expose the socket directly over the Tailnet:

    tailscale serve –bg –tcp 2222 127.0.0.1:2222

This bypasses the WebRTC browser client entirely (no more browser key intercept issues with Ctrl+W / Ctrl+T) and allows native ssh and VS Code Remote-SSH directly into the instance.

5. Quick Workload Benchmarks

Workload Metric / Output Observations
NFS I/O (fdatasync) 581 MB/s sustained Continuous 100 GiB sequential write (184 seconds total).
Qwen 3.5 9B (INT4) ~5.0 tok/s OpenVINO CPU inference; prefill is fast, generation is strictly memory-bandwidth bound.
SVT-AV1 (1080p60) 530% CPU load Efficient multi-threading across 8 Ice Lake cores.
libx265 HEVC (1080p24) 22.0 FPS ~1.0x real-time software encode on CPU.

Full architectural diagrams, reverse-engineered binaries breakdown, and reproducible configs are available in the repository:

Repo: sys-dissect/jiopc-architecture-whitepaper

Source: r/linux · by /u/aagauMulga

Leave a Reply

Your email address will not be published. Required fields are marked *