From 315d0bbfa3b9cbdd929acd250ddd13322122e047 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Tue, 12 Sep 2023 21:24:28 -0500 Subject: [PATCH] Use modern string parsing functions in SdpGenerator --- src/SdpGenerator.c | 120 +++++++++++++++++++++++++++++++++------------ 1 file changed, 88 insertions(+), 32 deletions(-) diff --git a/src/SdpGenerator.c b/src/SdpGenerator.c index 9f4bf98..e471851 100644 --- a/src/SdpGenerator.c +++ b/src/SdpGenerator.c @@ -35,21 +35,50 @@ static int getSerializedAttributeListSize(PSDP_OPTION head) { currentEntry = currentEntry->next; } - return (int)size; + // Add one for the null terminator + return (int)size + 1; } // Populate the serialized attribute list into a string -static int fillSerializedAttributeList(char* buffer, PSDP_OPTION head) { +static int fillSerializedAttributeList(char* buffer, size_t length, PSDP_OPTION head) { PSDP_OPTION currentEntry = head; int offset = 0; while (currentEntry != NULL) { - offset += sprintf(&buffer[offset], "a=%s:", currentEntry->name); - memcpy(&buffer[offset], currentEntry->payload, currentEntry->payloadLen); - offset += currentEntry->payloadLen; - offset += sprintf(&buffer[offset], " \r\n"); + int ret = snprintf(&buffer[offset], length, "a=%s:", currentEntry->name); + if (ret > 0 && (size_t)ret < length) { + offset += ret; + length -= ret; + } + else { + LC_ASSERT(false); + break; + } + + if ((size_t)currentEntry->payloadLen < length) { + memcpy(&buffer[offset], currentEntry->payload, currentEntry->payloadLen); + offset += currentEntry->payloadLen; + length -= currentEntry->payloadLen; + } + else { + LC_ASSERT(false); + break; + } + + ret = snprintf(&buffer[offset], length, " \r\n"); + if (ret > 0 && (size_t)ret < length) { + offset += ret; + length -= ret; + } + else { + LC_ASSERT(false); + break; + } currentEntry = currentEntry->next; } + + // We should have only space for the null terminator left over + LC_ASSERT(length == 1); return offset; } @@ -64,7 +93,8 @@ static int addAttributeBinary(PSDP_OPTION* head, char* name, const void* payload option->next = NULL; option->payloadLen = payloadLen; - strcpy(option->name, name); + strncpy(option->name, name, sizeof(option->name)); + option->name[sizeof(option->name) - 1] = '\0'; option->payload = (void*)(option + 1); memcpy(option->payload, payload, payloadLen); @@ -134,7 +164,7 @@ static int addGen4Options(PSDP_OPTION* head, char* addrStr) { int err = 0; LC_ASSERT(RtspPortNumber != 0); - sprintf(payloadStr, "rtsp://%s:%u", addrStr, RtspPortNumber); + snprintf(payloadStr, sizeof(payloadStr), "rtsp://%s:%u", addrStr, RtspPortNumber); err |= addAttributeString(head, "x-nv-general.serverAddress", payloadStr); return err; @@ -163,7 +193,7 @@ static int addGen5Options(PSDP_OPTION* head) { AudioEncryptionEnabled = true; } - sprintf(payloadStr, "%u", featureFlags); + snprintf(payloadStr, sizeof(payloadStr), "%u", featureFlags); err |= addAttributeString(head, "x-nv-general.featureFlags", payloadStr); // Ask for the encrypted control protocol to ensure remote input will be encrypted. @@ -236,19 +266,19 @@ static PSDP_OPTION getAttributesList(char*urlSafeAddr) { // Send client feature flags to Sunshine hosts if (IS_SUNSHINE()) { uint32_t moonlightFeatureFlags = ML_FF_FEC_STATUS; - sprintf(payloadStr, "%u", moonlightFeatureFlags); + snprintf(payloadStr, sizeof(payloadStr), "%u", moonlightFeatureFlags); err |= addAttributeString(&optionHead, "x-ml-general.featureFlags", payloadStr); } - sprintf(payloadStr, "%d", StreamConfig.width); + snprintf(payloadStr, sizeof(payloadStr), "%d", StreamConfig.width); err |= addAttributeString(&optionHead, "x-nv-video[0].clientViewportWd", payloadStr); - sprintf(payloadStr, "%d", StreamConfig.height); + snprintf(payloadStr, sizeof(payloadStr), "%d", StreamConfig.height); err |= addAttributeString(&optionHead, "x-nv-video[0].clientViewportHt", payloadStr); - sprintf(payloadStr, "%d", StreamConfig.fps); + snprintf(payloadStr, sizeof(payloadStr), "%d", StreamConfig.fps); err |= addAttributeString(&optionHead, "x-nv-video[0].maxFPS", payloadStr); - sprintf(payloadStr, "%d", StreamConfig.packetSize); + snprintf(payloadStr, sizeof(payloadStr), "%d", StreamConfig.packetSize); err |= addAttributeString(&optionHead, "x-nv-video[0].packetSize", payloadStr); err |= addAttributeString(&optionHead, "x-nv-video[0].rateControlMode", "4"); @@ -287,7 +317,7 @@ static PSDP_OPTION getAttributesList(char*urlSafeAddr) { // settle on the optimal bitrate if it's somewhere in the middle), so we'll just latch the bitrate // to the requested value. if (AppVersionQuad[0] >= 5) { - sprintf(payloadStr, "%d", bitrate); + snprintf(payloadStr, sizeof(payloadStr), "%d", bitrate); err |= addAttributeString(&optionHead, "x-nv-video[0].initialBitrateKbps", payloadStr); err |= addAttributeString(&optionHead, "x-nv-video[0].initialPeakBitrateKbps", payloadStr); @@ -301,7 +331,7 @@ static PSDP_OPTION getAttributesList(char*urlSafeAddr) { err |= addAttributeString(&optionHead, "x-nv-video[0].peakBitrate", "4"); } - sprintf(payloadStr, "%d", bitrate); + snprintf(payloadStr, sizeof(payloadStr), "%d", bitrate); err |= addAttributeString(&optionHead, "x-nv-vqos[0].bw.minimumBitrate", payloadStr); err |= addAttributeString(&optionHead, "x-nv-vqos[0].bw.maximumBitrate", payloadStr); } @@ -351,7 +381,7 @@ static PSDP_OPTION getAttributesList(char*urlSafeAddr) { // If not using slicing, we request 1 slice per frame slicesPerFrame = 1; } - sprintf(payloadStr, "%d", slicesPerFrame); + snprintf(payloadStr, sizeof(payloadStr), "%d", slicesPerFrame); err |= addAttributeString(&optionHead, "x-nv-video[0].videoEncoderSlicesPerFrame", payloadStr); if (NegotiatedVideoFormat & VIDEO_FORMAT_MASK_AV1) { @@ -397,13 +427,13 @@ static PSDP_OPTION getAttributesList(char*urlSafeAddr) { err |= addAttributeString(&optionHead, "x-nv-video[0].maxNumReferenceFrames", "1"); } - sprintf(payloadStr, "%d", StreamConfig.clientRefreshRateX100); + snprintf(payloadStr, sizeof(payloadStr), "%d", StreamConfig.clientRefreshRateX100); err |= addAttributeString(&optionHead, "x-nv-video[0].clientRefreshRateX100", payloadStr); } - sprintf(payloadStr, "%d", audioChannelCount); + snprintf(payloadStr, sizeof(payloadStr), "%d", audioChannelCount); err |= addAttributeString(&optionHead, "x-nv-audio.surround.numChannels", payloadStr); - sprintf(payloadStr, "%d", audioChannelMask); + snprintf(payloadStr, sizeof(payloadStr), "%d", audioChannelMask); err |= addAttributeString(&optionHead, "x-nv-audio.surround.channelMask", payloadStr); if (audioChannelCount > 2) { err |= addAttributeString(&optionHead, "x-nv-audio.surround.enable", "1"); @@ -443,7 +473,7 @@ static PSDP_OPTION getAttributesList(char*urlSafeAddr) { } } - sprintf(payloadStr, "%d", AudioPacketDuration); + snprintf(payloadStr, sizeof(payloadStr), "%d", AudioPacketDuration); err |= addAttributeString(&optionHead, "x-nv-aqos.packetDuration", payloadStr); } else { @@ -455,7 +485,7 @@ static PSDP_OPTION getAttributesList(char*urlSafeAddr) { } if (AppVersionQuad[0] >= 7) { - sprintf(payloadStr, "%d", (StreamConfig.colorSpace << 1) | StreamConfig.colorRange); + snprintf(payloadStr, sizeof(payloadStr), "%d", (StreamConfig.colorSpace << 1) | StreamConfig.colorRange); err |= addAttributeString(&optionHead, "x-nv-video[0].encoderCscMode", payloadStr); } @@ -468,8 +498,8 @@ static PSDP_OPTION getAttributesList(char*urlSafeAddr) { } // Populate the SDP header with required information -static int fillSdpHeader(char* buffer, int rtspClientVersion, char*urlSafeAddr) { - return sprintf(buffer, +static int fillSdpHeader(char* buffer, size_t length, int rtspClientVersion, char*urlSafeAddr) { + return snprintf(buffer, length, "v=0\r\n" "o=android 0 %d IN %s %s\r\n" "s=NVIDIA Streaming Client\r\n", @@ -479,9 +509,9 @@ static int fillSdpHeader(char* buffer, int rtspClientVersion, char*urlSafeAddr) } // Populate the SDP tail with required information -static int fillSdpTail(char* buffer) { +static int fillSdpTail(char* buffer, size_t length) { LC_ASSERT(VideoPortNumber != 0); - return sprintf(buffer, + return snprintf(buffer, length, "t=0 0\r\n" "m=video %d \r\n", AppVersionQuad[0] < 4 ? 47996 : VideoPortNumber); @@ -490,7 +520,8 @@ static int fillSdpTail(char* buffer) { // Get the SDP attributes for the stream config char* getSdpPayloadForStreamConfig(int rtspClientVersion, int* length) { PSDP_OPTION attributeList; - int offset; + int attributeListSize; + int offset, written; char* payload; char urlSafeAddr[URLSAFESTRING_LEN]; @@ -501,16 +532,41 @@ char* getSdpPayloadForStreamConfig(int rtspClientVersion, int* length) { return NULL; } - payload = malloc(MAX_SDP_HEADER_LEN + MAX_SDP_TAIL_LEN + - getSerializedAttributeListSize(attributeList)); + attributeListSize = getSerializedAttributeListSize(attributeList); + payload = malloc(MAX_SDP_HEADER_LEN + MAX_SDP_TAIL_LEN + attributeListSize); if (payload == NULL) { freeAttributeList(attributeList); return NULL; } - offset = fillSdpHeader(payload, rtspClientVersion, urlSafeAddr); - offset += fillSerializedAttributeList(&payload[offset], attributeList); - offset += fillSdpTail(&payload[offset]); + offset = 0; + written = fillSdpHeader(payload, MAX_SDP_HEADER_LEN, rtspClientVersion, urlSafeAddr); + if (written < 0 || written >= MAX_SDP_HEADER_LEN) { + LC_ASSERT(false); + freeAttributeList(attributeList); + return NULL; + } + else { + offset += written; + } + written = fillSerializedAttributeList(&payload[offset], attributeListSize, attributeList); + if (written < 0 || written >= attributeListSize) { + LC_ASSERT(false); + freeAttributeList(attributeList); + return NULL; + } + else { + offset += written; + } + written = fillSdpTail(&payload[offset], MAX_SDP_TAIL_LEN); + if (written < 0 || written >= MAX_SDP_TAIL_LEN) { + LC_ASSERT(false); + freeAttributeList(attributeList); + return NULL; + } + else { + offset += written; + } freeAttributeList(attributeList); *length = offset;