fix(gateway): enforce audited production traversal

This commit is contained in:
sechmachine
2026-07-30 04:48:02 +07:00
parent d3852d15f3
commit 70667d5aee
17 changed files with 1368 additions and 317 deletions
+90 -12
View File
@@ -82,14 +82,18 @@ func TestNativeApolloSetupRejectsUnsupportedStreamPolicyBeforeProviderReadiness(
ClipboardPolicy: protocol.ClipboardPolicy{MaxTextBytes: 65536, MaxUpdatesPerMinute: 30},
}
for name, policy := range map[string]protocol.ProviderStreamPolicy{
"audio-disabled": {ResolutionWidth: 1920, ResolutionHeight: 1080, Fps: 60, Codec: "H264", BitrateKbps: 8000, AudioEnabled: false},
"av1": {ResolutionWidth: 3840, ResolutionHeight: 2160, Fps: 60, Codec: "AV1", BitrateKbps: 50000, AudioEnabled: true},
"audio-disabled": {ResolutionWidth: 1920, ResolutionHeight: 1080, Fps: 60, Codec: "H264", BitrateKbps: 8000, AudioEnabled: false},
"av1": {ResolutionWidth: 3840, ResolutionHeight: 2160, Fps: 60, Codec: "AV1", BitrateKbps: 50000, AudioEnabled: true},
"h264-resolution": {ResolutionWidth: 4097, ResolutionHeight: 2160, Fps: 60, Codec: "H264", BitrateKbps: 50000, AudioEnabled: true},
"hevc-resolution": {ResolutionWidth: 8193, ResolutionHeight: 4320, Fps: 60, Codec: "HEVC", BitrateKbps: 80000, AudioEnabled: true},
"fps": {ResolutionWidth: 1920, ResolutionHeight: 1080, Fps: 241, Codec: "H264", BitrateKbps: 8000, AudioEnabled: true},
"bitrate-cap": {ResolutionWidth: 1920, ResolutionHeight: 1080, Fps: 60, Codec: "H264", BitrateKbps: 125001, AudioEnabled: true},
} {
t.Run(name, func(t *testing.T) {
work.StreamPolicy = policy
_, err := NewNativeApolloBackend().Setup(context.Background(), LaunchRequest{
SessionID: "session-1", ProviderProfile: ProviderProfileApollo, ProviderWork: work,
})
}, nil)
if !errors.Is(err, ErrProviderMalformed) {
t.Fatalf("Setup() error = %v, want ErrProviderMalformed before provider readiness", err)
}
@@ -97,6 +101,73 @@ func TestNativeApolloSetupRejectsUnsupportedStreamPolicyBeforeProviderReadiness(
}
}
func TestNativeApolloRejectsProviderCapabilityMismatchBeforeInventoryOrLaunch(t *testing.T) {
serverTLS, clientTLS := testTLS(t)
var paths []string
management := httptest.NewUnstartedServer(http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
paths = append(paths, request.URL.Path)
switch request.URL.Path {
case "/serverinfo":
_, _ = response.Write([]byte("<root><uniqueid>apollo-server</uniqueid><ServerCodecModeSupport>1</ServerCodecModeSupport><MaxLumaPixelsHEVC>0</MaxLumaPixelsHEVC></root>"))
case "/applist":
_, _ = response.Write([]byte("<root><App><ID>42</ID></App></root>"))
default:
http.Error(response, "unexpected provider request", http.StatusBadRequest)
}
}))
management.TLS = serverTLS
management.StartTLS()
defer management.Close()
host, portText, err := net.SplitHostPort(management.Listener.Addr().String())
if err != nil {
t.Fatal(err)
}
port, err := strconv.ParseInt(portText, 10, 64)
if err != nil {
t.Fatal(err)
}
pinned := sha256.Sum256(serverTLS.Certificates[0].Certificate[0])
work := protocol.ProviderSessionWork{
Version: "1", SessionID: "session-source-policy", GatewayID: "gateway-1",
ExpiresAt: "2099-01-01T00:00:00Z", ProviderProfile: ProviderProfileApollo,
ProviderIdentity: "apollo-server#sha256:" + hex.EncodeToString(pinned[:]), PolicyVersionID: "policy-1",
ApplicationID: "42", ClientID: "paired-client",
StreamPolicy: protocol.ProviderStreamPolicy{
ResolutionWidth: 2560, ResolutionHeight: 1440, Fps: 120,
Codec: "HEVC", BitrateKbps: 40000, AudioEnabled: true,
},
ManagementHost: host, ManagementPort: port, StreamHost: host, StreamPort: 47984,
ClientCertificatePem: certificatePEM(t, clientTLS.Certificates[0]),
ClientPrivateKeyPem: privateKeyPEM(t, clientTLS.Certificates[0]),
ServerCertificatePem: certificatePEM(t, tls.Certificate{Certificate: [][]byte{serverTLS.Certificates[0].Certificate[1]}}),
ClipboardPolicy: protocol.ClipboardPolicy{MaxTextBytes: 65536, MaxUpdatesPerMinute: 30},
}
adapter := NewApolloAdapter(NewNativeApolloBackend(), ProviderIdentity{UniqueID: "apollo-server", Fingerprint: "sha256:" + hex.EncodeToString(pinned[:])})
if _, err := adapter.Start(context.Background(), LaunchRequest{
SessionID: work.SessionID, ProviderProfile: ProviderProfileApollo,
ProviderIdentity: work.ProviderIdentity, ProviderWork: work,
}); err == nil {
t.Fatal("Start() accepted a provider/source policy mismatch")
}
if got := strings.Join(paths, ","); got != "/serverinfo" {
t.Fatalf("provider requests before capability rejection = %s", got)
}
}
func TestApolloProviderCapabilityRejectsHEVCLumaDowngrade(t *testing.T) {
info := ManagementInfo{
ServerCodecModeSupport: 0x101, HasServerCodecModeSupport: true,
MaxLumaPixelsHEVC: 1920 * 1080, HasMaxLumaPixelsHEVC: true,
}
policy := protocol.ProviderStreamPolicy{
ResolutionWidth: 3840, ResolutionHeight: 2160, Fps: 60,
Codec: "HEVC", BitrateKbps: 80000, AudioEnabled: true,
}
if err := validateApolloProviderStreamPolicy(info, policy); !errors.Is(err, ErrProviderMalformed) {
t.Fatalf("provider HEVC luma downgrade error = %v", err)
}
}
func TestNativeApolloSetupRequiresModernEncryptedRTSPOrder(t *testing.T) {
serverTLS, clientTLS := testTLS(t)
streamListener, err := net.Listen("tcp", "127.0.0.1:0")
@@ -213,7 +284,7 @@ func TestNativeApolloSetupRequiresModernEncryptedRTSPOrder(t *testing.T) {
}
switch request.URL.Path {
case "/serverinfo":
_, _ = response.Write([]byte("<root><uniqueid>apollo-server</uniqueid></root>"))
_, _ = response.Write([]byte("<root><uniqueid>apollo-server</uniqueid><ServerCodecModeSupport>257</ServerCodecModeSupport><MaxLumaPixelsHEVC>1869449984</MaxLumaPixelsHEVC></root>"))
case "/applist":
if request.URL.Query().Get("uniqueid") != "paired-client" {
http.Error(response, "wrong client", http.StatusBadRequest)
@@ -291,7 +362,7 @@ func TestNativeApolloSetupRequiresModernEncryptedRTSPOrder(t *testing.T) {
ProviderApplicationTerminationAllowed: true,
}
backend := NewNativeApolloBackend()
response, err := backend.Setup(context.Background(), LaunchRequest{SessionID: "session-1", ProviderProfile: ProviderProfileApollo, ProviderWork: work})
response, err := backend.Setup(context.Background(), LaunchRequest{SessionID: "session-1", ProviderProfile: ProviderProfileApollo, ProviderWork: work}, []byte("<root><uniqueid>apollo-server</uniqueid><ServerCodecModeSupport>257</ServerCodecModeSupport><MaxLumaPixelsHEVC>1869449984</MaxLumaPixelsHEVC></root>"))
if err != nil {
t.Fatalf("Setup() error = %v", err)
}
@@ -474,7 +545,8 @@ func TestNativeApolloSetupRequiresModernEncryptedRTSPOrder(t *testing.T) {
t.Fatal("encrypted host termination was not forwarded")
}
select {
case payload := <-session.Video():
case media := <-session.Video():
payload := media.Payload
if len(payload) != 1001 || payload[0] != 'A' || payload[1000] != 'B' {
t.Fatalf("source-shaped video relay = %x", payload)
}
@@ -482,7 +554,8 @@ func TestNativeApolloSetupRequiresModernEncryptedRTSPOrder(t *testing.T) {
t.Fatal("source-shaped video was not relayed")
}
select {
case payload := <-session.Audio():
case media := <-session.Audio():
payload := media.Payload
if string(payload) != "A" {
t.Fatalf("source-shaped audio relay = %x", payload)
}
@@ -608,7 +681,8 @@ func TestNativeApolloSessionRelaysOnlyAuthenticatedEncodedUDPMedia(t *testing.T)
}
select {
case payload := <-session.Video():
case media := <-session.Video():
payload := media.Payload
if string(payload) != string([]byte{0x01, 0x02, 0x03}) {
t.Fatalf("video relay = %x, want encoded payload", payload)
}
@@ -617,7 +691,8 @@ func TestNativeApolloSessionRelaysOnlyAuthenticatedEncodedUDPMedia(t *testing.T)
}
for _, want := range wantAudio {
select {
case payload := <-session.Audio():
case media := <-session.Audio():
payload := media.Payload
if string(payload) != string(want) {
t.Fatalf("audio relay = %x, want %x", payload, want)
}
@@ -632,7 +707,8 @@ func TestNativeApolloSessionRelaysOnlyAuthenticatedEncodedUDPMedia(t *testing.T)
}
}
select {
case payload := <-session.Video():
case media := <-session.Video():
payload := media.Payload
if len(payload) != 1001 || payload[0] != 'A' || payload[999] != 'A' || payload[1000] != 'B' {
t.Fatalf("FEC video relay = %x", payload)
}
@@ -646,7 +722,8 @@ func TestNativeApolloSessionRelaysOnlyAuthenticatedEncodedUDPMedia(t *testing.T)
}
for _, want := range [][]byte{{'A'}, {'B'}, {'C'}, {'D'}} {
select {
case payload := <-session.Audio():
case media := <-session.Audio():
payload := media.Payload
if string(payload) != string(want) {
t.Fatalf("FEC audio relay = %x, want %x", payload, want)
}
@@ -670,7 +747,8 @@ func TestNativeApolloSessionRelaysOnlyAuthenticatedEncodedUDPMedia(t *testing.T)
}
for _, want := range [][]byte{{0xa0}, {0xa1}, {0xa2}, {0xa3}} {
select {
case payload := <-session.Audio():
case media := <-session.Audio():
payload := media.Payload
if string(payload) != string(want) {
t.Fatalf("post-loss audio relay = %x, want %x", payload, want)
}