arXiv:2609.22900v1 [cs.CR] 19 Sep 2026
SMS-delivered network-initiated SUPL on Pixel 8: a privacy assessment Douglas Leith Trinity College Dublin, Ireland [email protected] 19 September 2026
1. Summary A SUPL_INIT message is a network-initiated trigger that can be sent to a handset using an SMS to unilaterally start a location session: on receipt, the handset is instructed to determine its own position and report it, together with an identifier such as its IMSI, to a server specified in the message, without any action by the phone’s user. The concern motivating this investigation is therefore whether such a message could be used to silently exfiltrate a handset’s location and subscriber identity to a server under an attacker’s control, with no consent from or visibility to the device’s owner. We investigated this on a Google Pixel 8 handset, which uses a Samsung Exynos modem and a Broadcom GPS/GNSS subsystem; the conclusions below are specific to this combination of modem and GNSS vendor and may not apply to phones built around different components. On this device, an SMS-delivered SUPL_INIT is received by the Samsung modem, but essentially all of the SUPL-specific processing (every check on whether and how to act on the message) takes place in the Broadcom GNSS vendor code, principally the gpsd daemon; the modem’s role is limited to passing the raw message on to gpsd. We find no privacy issue: the handset never sends location data to an attacker-chosen server as a result of an unsolicited SUPL_INIT delivered by SMS. This follows from three checks and behaviours we identify in gpsd, established by static analysis of the decompiled binary and confirmed by dynamic, live testing with a real SMS delivered over the air: 1. A SUPL_INIT packet is ignored unless the handset is already in an active emergency call. The response to a network-initiated SUPL_INIT gates on the handset’s own emergency-call state at the time the message arrives, not on any claim made by the packet itself. An attacker sending an SMS cannot place the handset into a real emergency call, so this check blocks every SUPL_INIT an attacker could actually deliver. 2. When the handset is already in an active emergency call, and the received SUPL_INIT is itself flagged emergency with a valid SLP address, that address is used. The code supports restricting this to APNs on a configured allowlist, but on this device that allowlist is empty (unconfigured in gps.xml), so the check is skipped and does not currently restrict anything. This is the one path in the code by which an attacker-supplied server address could be used at all, and, regardless of the allowlist, it requires a precondition (a live emergency call) that is outside an SMS attacker’s control. 3. For a non-emergency SUPL_INIT, the server address carried in the message is ignored. This is the message any purely SMS-based attack must send, since it cannot place the handset into a real emergency call. The destination is always the handset’s own configured SLP server (or a standard, SIM-derived hostname if that is unset), never an address supplied in the packet: the attacker cannot control where location data is sent. Separately, and independently of any network-initiated SUPL_INIT message, the handset also generates its
1
own SUPL requests to supl.google.com as part of normal operation (background assisted-GPS synchronisation). These internally generated requests are not affected by network-initiated SUPL_INIT messages.
2. SUPL in the public specifications This section summarises what the publicly available Open Mobile Alliance (OMA) specifications say about SUPL, SUPL_INIT, its delivery mechanism and its authentication requirements, independently of anything found by static or dynamic analysis of this specific handset. We draw on the SUPL 2.0 Architecture Document [OMA-AD-SUPL] and the SUPL 2.0 User Plane Location Protocol technical specification [OMA-TS-ULP] (full references in Section 6). 2.1 Purpose of SUPL Secure User Plane Location (SUPL) is an OMA enabler that carries assistance data and positioning data over an IP (user-plane) bearer “to aid network and SET based positioning technologies in the calculation of a SET’s position” [OMA-AD-SUPL, §5] (“SET”, SUPL Enabled Terminal, is the specification’s term for the handset). It exists as an alternative to legacy control-plane positioning, using ordinary IP connectivity rather than signalling channels, and defines both device-initiated flows (the handset requests its own position) and network-initiated flows, in which the network-side server, an SLP (SUPL Location Platform), unilaterally starts a location session with a handset. 2.2 What SUPL_INIT is, and how it reaches the handset SUPL_INIT is the message used to start a network-initiated session, sent by the Home SUPL Location Platform (H-SLP, the SLP belonging to the SET’s home network): in every network-initiated call flow in the specification, “the H-SLP initiates the SUPL Session with the SET by sending a ULP SUPL INIT message” [OMA-TS-ULP, §6, call-flow steps]. Its ASN.1 definition carries, at minimum, a session identifier and the intended positioning method, plus (when the network’s own privacy check decides notification or verification is needed) a Notification element: SUPLINIT ::= SEQUENCE { posMethod PosMethod, notification Notification OPTIONAL, sLPAddress SLPAddress OPTIONAL, qoP QoP OPTIONAL, sLPMode SLPMode, mac MAC OPTIONAL, -- backwards compatibility keyIdentity KeyIdentity OPTIONAL, -- backwards compatibility ..., ver2-SUPL-INIT-extension Ver2-SUPL-INIT-extension OPTIONAL } NotificationType ::= ENUMERATED { noNotificationNoVerification(0), notificationOnly(1), notificationAndVerficationAllowedNA(2), notificationAndVerficationDeniedNA(3), privacyOverride(4), ...} [OMA-TS-ULP, §11] privacyOverride allows the location session to proceed with no notification shown to the user at all: this is the notification type used throughout this investigation’s test payloads. The specification defines four transport mechanisms for delivering SUPL_INIT to the handset: OMA Push (WAP Push), SMS directly, UDP/IP, and SIP Push. It mandates that “For GSM/WCDMA/TD-SCDMA deployments, the SIF [SUPL Initiation Function] using OMA Push SHALL be supported by both the SET and the SLP” [OMA-AD-SUPL, §5.3.1.2]. WAP-Push-over-SMS delivery, as used throughout this investigation, is therefore a mandatory transport for the class of network the test handset operates on, not an implementation quirk of this particular device. 2
The handset’s own response to a SUPL_INIT is one of SUPL POS INIT, SUPL AUTH REQ or SUPL TRIGGERED START [OMA-TS-ULP, §6.1.6.1], and a session normally concludes with a SUPL END message. Both SUPLPOSINIT and SUPLEND carry an optional position field [OMA-TS-ULP, §11], and every message in the session, including these, carries a SetSessionID identifying which handset it belongs to. The specification defines this identifier as explicitly allowed to be the handset’s own IMSI: SetSessionID ::= SEQUENCE {sessionId INTEGER(0..65535), setId SETId} SETId ::= CHOICE { msisdn OCTET STRING(SIZE (8)), mdn OCTET STRING(SIZE (8)), min BIT STRING(SIZE (34)), imsi OCTET STRING(SIZE (8)), nai IA5String(SIZE (1..1000)), iPAddress IPAddress, ..., ver2-imei OCTET STRING(SIZE(8))} [OMA-TS-ULP, §11] So the handset’s response to a SUPL_INIT is designed to deliver both its own computed position and a uniquely identifying value (IMSI, MSISDN or IMEI) to whichever server the session was directed to. This is the basis for the concern in Section 1: it is not merely that the handset computes its own position, but that its response is designed to carry that position together with a unique subscriber or device identifier, to a server the network message itself specifies. 2.3 Authentication and verification mandated for SUPL_INIT The specification’s own security model for SUPL_INIT is markedly weaker than for the rest of the protocol: “All SUPL Messages except ‘SUPL INIT’ MUST be delivered within a TLS or PSK-TLS session between a SET and an SLP” [OMA-AD-SUPL, §4.2.3]. SUPL_INIT itself is explicitly excluded, since it is the trigger that precedes any session or TLS connection. Two independent protections are defined for SUPL_INIT [OMA-TS-ULP, §6.1.6]: • Network-based authentication (mandatory): the first message the handset sends back after acting on a SUPL_INIT (SUPL POS INIT, SUPL AUTH REQ, etc.) must carry a verification field computed as an HMAC over the received SUPL_INIT; if this fails, the SLP terminates the session. This is a check the network performs on the handset’s response, after the handset has already processed the SUPL_INIT and acted on it; it cannot itself prevent the handset acting on a forged message. • End-to-end protection (optional): a Protection Level field in SUPL_INIT is either Null (“no end-to-end integrity protection, no end-to-end replay protection and no confidentiality protection”) or Basic (a 32-bit HMAC-SHA256 MAC plus a replay counter, keyed from a key established during a prior GBA/SEK-authenticated TLS session with the home SLP) [OMA-TS-ULP, §6.1.6.3, §6.1.6.6]. Critically, Null protection is explicitly spec-compliant, is the assigned default “at power-up or when the lifetime of the SUPL_INIT_Root_Key has expired” [§6.1.6.4], and under it “the SET considers the [received] message to be authentic, and no security related processing is required” [§6.1.6.5]. That is, by design, a handset that has not recently negotiated Basic protection with its home SLP accepts any correctly-tagged SUPL_INIT as authentic, with no cryptographic check at all. In short: the public specification’s own authentication model for SUPL_INIT is optional, falls back to no protection whenever a prior key-establishment session has not occurred, and even when active only protects against a network guessing wrong, not a third party constructing a well-formed message. The behaviour we found on this device (gating on the handset’s own emergency-call state) is an Android/vendor-level defence that goes beyond what SUPL 2.0 itself requires; it is not something the specification mandates. A later version, SUPL 3.0 [OMA-TS-ULP-V3], adds a third protection mode but does not change this picture. Null protection (no end-to-end protection at all) remains explicitly listed as “Optional” and stays the mandatory fallback whenever no key has been established, and support for the newer Mode A protection is only recommended (“SHOULD”), not required, for a SET to implement at all [OMA-TS-ULP-V3, §6.3.1, Table 5]. Its emergency exemption is, if anything, stronger than SUPL 2.0’s: “During an emergency call, a SET SHALL NOT apply end-to-end protection of emergency SUPL INIT messages” [OMA-TS-ULP-V3, 3
§6.2.4]. The test handset’s own configuration declares SuplVersion="2", SuplMinorVersion="0" (gps.xml), so it runs SUPL 2.0 rather than 3.0; this paragraph is included for completeness, not because it changes any finding in this report. 2.4 SUPL_INIT for emergency calls The specification treats emergency positioning as a distinct case with, if anything, weaker message-level protection than ordinary sessions: “End-to-End Protection of SUPL INIT Messages applies only to nonemergency SUPL INIT messages” [OMA-TS-ULP, §6.1.6.3]. An emergency SUPL_INIT can only ever rely on the after-the-fact network-based check above. The specification also allows a handset with no SIM/UICC at all to use SUPL for emergency positioning, authenticated only weakly “using (e.g.) the session ID and the received hash of the SUPL INIT” [§6.1.5.4], and provides a mechanism for an emergency SLP to resend a corrected SUPL_INIT over an established TLS session if it detects the original was altered, explicitly noting “the ability to resend SUPL INIT is only intended for emergency sessions” [§6.1.5.5]. Beyond these provisions, the public documents give little detail on how an individual network operator or device vendor actually gates emergency SUPL_INIT processing in practice: for example, on what signal a handset uses to decide it is “in an emergency call” for this purpose, or what (if any) allowlisting of destination addresses is applied. The Architecture Document notes only that the network’s privacy function should “allow override of the target SET User privacy settings as mandated or allowed by local regulations for positioning for an emergency services call” [OMA-AD-SUPL, §5.3.1.1]. That is, it delegates the actual policy to regulation and implementation, rather than specifying it. The emergency-call-state gate and APN allowlist described in Section 1 (findings 1–2) are exactly this kind of implementation-specific policy, found by analysing this handset’s own code rather than documented in the public SUPL specifications.
3. Experimental setup Handset. Google Pixel 8 (“shiba”), Samsung Exynos Modem 5300 baseband, Broadcom BCM4776family GNSS RF front-end (RfType is configured as GL_RF_4776_BRCM in gps.xml), Android 14 (build AP2A.240905.003, security patch level 5 September 2024). Rooted with Magisk. All testing was performed by the researcher sending SMS messages to their own device. Static analysis. The vendor GNSS daemon binary (/vendor/bin/hw/gpsd, Broadcom’s proprietary glw/GPS HAL library, statically linked, stripped but with recoverable C++ symbol names) was decompiled with Ghidra 11.4.2. The binary self-identifies as Broadcom GLL ver. 154.20.24 (build 587347, build_job_id 477614240, dated 12 January 2024), built against Google’s “P23” Android target. Dynamic analysis. Frida 17.18.0 was used to instrument the running gpsd process on-device. Instrumentation attached to the already-running, normally init-started gpsd process. SMS trigger. A minimal Android app (apk/, package com.test.suplsms) sends one binary/port SMS (SmsManager.sendDataMessage, port 2948) containing a WAP-push-wrapped SUPL_INIT to the device’s own number. Both parts of this trigger are fully defined in the public specification: the ULP-PDU/SUPL_INIT ASN.1 grammar in [OMA-TS-ULP, §11], and the exact WSP/WAP-Push OTA byte layout (PDU type, content-type value 0x0312 application/vnd.omaloc-supl-init, and the OMNA-registered application id x-oma-application:ulp.ua) as a fully worked, byte-level example in [OMA-TS-ULP, Annex B.2–B.3, Table 82]. The ULP-PDU payload itself was built with Python’s asn1tools (0.169.0) against this ASN.1 schema (payload_builder/ulp.asn), producing genuine, standards-conformant SUPL_INIT messages. The trigger payload set posMethod to agpsSETassisted, notificationType to privacyOverride (the no-notification, no-verification case described in Section 2.3), and sLPAddress to the IPv4 address of the test server (Section 3, Test server, encoded as an iPAddress choice rather than a fQDN), with sLPMode set to nonProxy. The public specification, on its own, was sufficient to construct a byte-correct trigger SMS; no analysis of Android or vendor code was needed for this part. Test server. For dynamic testing of the connection-establishment logic, a Python TLS server was built presenting a leaf certificate signed by a CA installed as a trusted system CA on the test handset.
4
AI assistance. Claude Sonnet 5 (Anthropic) was used to assist with (i) running the tests, (ii) the static analysis, and (iii) preparation of this report.
4. Static analysis 4.1 System-level message flow An SMS-delivered SUPL_INIT travels from the carrier network, through the modem baseband and Android’s RIL layer, into gpsd. If gpsd decides to act on it, the message goes on via inter-process communication (IPC) to scd, the separate daemon that owns the actual outbound network socket. Handset Attacker SMS (SUPL_INIT)
cellular network
Baseband modem
rild daemon
HIDL callback (hwbinder)
gpsd daemon (libsitril-gps.so)
Unix pipe
scd
TLS
SLP server
Figure 1: System-level flow of a network-initiated SUPL message from SMS delivery to the outbound network connection. gpsd and scd are separate processes communicating over a named-pipe IPC channel (/data/vendor/gps/.pipe.gpsd_to_scd.*); gpsd decides whether and where to connect, scd owns the socket that actually does so. 4.2 Execution flow and key checks inside gpsd Figure 2 shows the execution flow inside gpsd from SUPL_INIT message to connection request, with the two decision points that determine outcome: the emergency-APN allowlist check (node E, only relevant to emergency-flagged packets) and the NFW permission gate (node G), which applies unconditionally. 4.3 The permission gate RildClientHelper::HasPermissionSuplNi is the check corresponding to node G in Figure 2. Decompiled (cleaned up for readability; original at file offset 0x339640): bool RildClientHelper::HasPermissionSuplNi( RildClientHelper *this, bool isEmergencySuplNi, bool isInEmergencyState) { char cVar1 = *SuplIgnoreNfwLocPolicy; // configuration property if (cVar1 == '\0' && !isInEmergencyState) { ILog::Log(..., "SUPL: SUPL NI is not allowed. attribution app - %s", attributionAppPkgName); } return cVar1 != '\0' || isInEmergencyState; } The decision depends only on isInEmergencyState (whether the handset itself is currently in an active emergency call, passed in from the telephony stack, outside the SMS attacker’s control) and a configuration flag SuplIgnoreNfwLocPolicy that is false on this device (gps.xml, no override). It does not depend on isEmergencySuplNi: whether the packet itself claims to be an emergency SUPL_INIT is irrelevant to this check. This substantiates conclusion 1. 4.4 The emergency-SLP extraction and APN allowlist Node E/F in Figure 2, inside GlSuplHalPlatform::OnNetworkRequest (file offset 0x3d1718): if (decoded_ok && packet_is_emergency_notification) { this->isEmergencySuplNi = true;
5
ProcessSuplNiMessage
OnNetworkRequest (decode)
emergency flagged?
yes
E: APN allowlist matches?
continued from Figure 2a
no
no
yes / n/a
dropped
F: extract packet's E-SLP address
H: autoConfigSlp
E-SLP address valid? (emergency only)
G: HasPermissionSuplNi (active emergency call?)
deny
allow
silently dropped
continues in Figure 2b
yes
no
connect to packet's SLP address
connect to configured server / 3GPP default
RequestConnectionForNetwork
(a)
(b)
Figure 2: Execution flow inside gpsd from SUPL_INIT message to connection request, with the two decision points that determine outcome: the emergency-APN allowlist check (node E, only relevant to emergencyflagged packets) and the NFW permission gate (node G), which applies unconditionally. The left part (2a) covers decode through the permission gate; the right part (2b) continues from there through destination resolution (node H) to the connection request. Function names are as recovered from the binary’s C++ symbols and can be located directly in the decompiled output.
6
if (SuplConfig::Instance()->emergencyApnList[0] != '\0') { if (!apn_in_list(current_apn, SuplConfig::Instance()->emergencyApnList)) { ILog::Log(..., "SUPL: Current APN \"%s\" does not match " "emergency APN list \"%s\"\n", current_apn, ...); ILog::Log(..., "SUPL: Emergency SUPL INIT will be dropped\n"); goto dropped; } } if (packet_has_slp_address) { this->eslpHost = decode_slp_address(...); // this+0x89 this->eslpPort = decode_slp_port_or_default(...); ILog::Log(..., "SUPL: E-SLP: %s:%d\n", this->eslpHost, this->eslpPort); } } The packet’s own SLP address is only extracted at all when the packet is flagged emergency, and, if an emergency-APN allowlist is configured, only when the handset’s current APN matches an entry in it. On this device, the allowlist is not configured. SuplConfig’s constructor zero-initialises the field (*(undefined8 *)(this + 0x577) = 0;), and neither of the two gps.xml attribute names SetCfgValue accepts for it (E911Apns, SuplEmergencyApns) appears in this device’s gps.xml. The APN check is therefore inactive here: an emergency-flagged SUPL_INIT with a decoded SLP address, once past the permission gate in Section 4.3, would have that address used unconditionally, with no APN restriction. This substantiates conclusion 2: an attacker-controlled destination address is reachable through this code only for emergency-flagged messages, subject to an APN allowlist that exists in the code but is not actually configured on this device. Per Section 4.3, it also only ever takes effect if the handset is already in a genuine active emergency call. 4.5 Destination-address resolution Node H in Figure 2, GlSuplHalPlatform::autoConfigSlp (file offset 0x4cff08): void GlSuplHalPlatform::autoConfigSlp(GlSuplHalPlatform *this, bool force) { if (!force) { if (this->isEmergencySuplNi) { char *addr = this->eslpHost[0] ? this->eslpHost : SuplConfig::Instance()->server; this->connectHost = addr; this->connectPort = eslp_port_or_configured_default(); if (strcmp(addr, "none") != 0 && strcmp(addr, "auto") != 0) goto use_address; } if (!server_is("none") && !server_is("auto")) { this->connectHost = SuplConfig::Instance()->server; // e.g. supl.google.com this->connectPort = SuplConfig::Instance()->port; // e.g. 7275 goto use_address; } } // fall back to the standard 3GPP well-known H-SLP hostname, // derived from the device's own SIM IMSI (MCC/MNC) -- not // attacker-influenceable at all snprintf(hostBuf, sizeof(hostBuf), "h-slp.mnc%03d.mcc%03d.pub.3gppnetwork.org", mnc, mcc);
7
this->connectHost = hostBuf; this->connectPort = SuplConfig::Instance()->port; use_address: ... } For a non-emergency SUPL_INIT (isEmergencySuplNi == false, which is what any purely SMS-based attack must send, since it cannot place the handset into a real emergency call), the packet’s own address (this->eslpHost) is never consulted at all. The destination is either the configured server (acSuplServer in gps.xml, supl.google.com on this device) or, if that is unset, a standard hostname derived from the device’s own SIM identity. This substantiates conclusion 3 and, for the non-emergency case, closes off any possibility of an attacker-chosen destination.
5. Dynamic analysis Dynamic testing had two goals: (a) confirm that a genuine, over-the-air SMS actually reaches this code, and (b) confirm the static-analysis conclusions above against the real, running binary rather than decompiled pseudocode alone. 5.1 Confirming real SMS delivery Sending the test SUPL_INIT produces, in the device’s own RIL client log, delivery of the expected unsolicited message to gpsd’s registered RIL client: RILClient: [OemClient]IND: (clientId = 16, msgId = 4011, dataLength = 259, channel = 0) msgId = 4011 is RILC_UNSOL_GPS_SUPL_NI_MESSAGE; clientId = 16 is gpsd’s own process/thread, confirming the message reached gpsd’s registered handler rather than merely the modem/RIL layer. 5.2 Confirming the permission gate denies under normal conditions With gpsd instrumented to log entry and return value of RildClientHelper::HasPermissionSuplNi and every function downstream of it, sending the test (non-emergency) SUPL_INIT SMS while the handset was in its normal, idle state (no active call) produced: [RildClientHelper::HasPermissionSuplNi] ENTER isEmergencySuplNi=0x0 isInEmergencyState=0x0 [RildClientHelper::HasPermissionSuplNi] RETURNED 0x0 (0 = DENY, 1 = ALLOW) No hook downstream of this call (session creation, connection requests, IPC to scd) fired at all. This is the live confirmation of conclusion 1: under real conditions, the message is processed as far as this check and then silently discarded. 5.3 Confirming the destination address for a bypassed, non-emergency request To verify Section 4.5’s destination-resolution logic against the actual running code, the permission gate was forced to return “allow” (Interceptor.attach return-value override on HasPermissionSuplNi) so that the connection logic downstream could be observed operating on our still-non-emergency test payload. This is not something an SMS attacker can do; it isolates and directly tests the autoConfigSlp logic identified statically in Section 4.5. [RildClientHelper::HasPermissionSuplNi] ENTER isEmergencySuplNi=0x0 isInEmergencyState=0x0 [PATCH] HasPermissionSuplNi forced to 1 (ALLOW) [BrcmGpsHalScdClient::RequestConnectionForNetwork] ENTER param2(network)="supl.google.com" param3(port)=7275 [WRITE fd=23] len=904 <- connection request sent to scd over IPC [BrcmGpsHalScdClient::OnIpcMessage] type=4 (OnConnect) [BrcmGpsHalScdClient::OnIpcMessage] type=5 (OnClose) <- ~6 ms later
8
Even with the permission gate bypassed, the connection request carries supl.google.com:7275 (the handset’s own configured SLP server), not any address from the attacker’s SUPL_INIT payload. A direct live read of the running process’s configuration singleton confirmed the same value: SuplConfig::Instance()->server = "supl.google.com" SuplConfig::Instance()->port = 7275 This is the live confirmation of Section 4.5 and conclusion 3: for a non-emergency message, the destination is never attacker-controlled, under any condition tested, including with the permission gate itself bypassed. 5.4 Summary of dynamic results against static predictions Static prediction (Section 4)
Dynamic result
Non-emergency SUPL_INIT denied by HasPermissionSuplNi unless in an active emergency call (4.3) Emergency-only path required for attacker-address use (4.4)
Confirmed: gate returned DENY for our test payload in the handset’s normal (non-call) state (5.2) Consistent: our test payload was never emergency-flagged, and, per 5.3, its address was never used even with the gate bypassed Confirmed: live connection request and live config read both showed supl.google.com:7275 (5.3)
Non-emergency destination resolves to configured server, not packet content (4.5)
6. References • [OMA-AD-SUPL] Open Mobile Alliance, “Secure User Plane Location Architecture,” OMA-AD-SUPLV2_0-20120417-A, 17 April 2012. • [OMA-TS-ULP] Open Mobile Alliance, “UserPlane Location Protocol,” OMA-TS-ULP-V2_0_520191028-A, 28 October 2019. • [OMA-TS-ULP-V3] Open Mobile Alliance, “UserPlane Location Protocol,” OMA-TS-ULP-V3_020181213-C, 13 December 2018.
9