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 toperformance. - 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 (fdatasyncwriting 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
- Enable lingering to persist processes outside of active sessions:
loginctl enable-linger
- Exploit an audio IPC override:
libxorgxrdpincludes an internal checkXRDP_SESMAN_AUDIO_DISABLE_IDLETIMEOUT=1. A lightweight background daemon writing syntheticsound_playingheartbeat 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:
- 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.
-
Unprivileged SSH: Run OpenSSH server bound to non-standard user port
2222with a customsshd_config. -
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:
Source: r/linux · by /u/aagauMulga