From 04dc3c52f6070d06a9e98da3085b8a2cccc5a16f Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 30 Nov 2020 21:45:57 -0600 Subject: [PATCH] Use safe string functions in C11 --- src/Limelight-internal.h | 4 ++++ src/Misc.c | 2 +- src/Platform.h | 3 +++ src/PlatformSockets.c | 4 ++-- src/RtspConnection.c | 15 ++++++------ src/RtspParser.c | 52 +++++++++++++++++++++------------------- src/SdpGenerator.c | 48 ++++++++++++++++++++----------------- src/SimpleStun.c | 2 +- 8 files changed, 72 insertions(+), 58 deletions(-) diff --git a/src/Limelight-internal.h b/src/Limelight-internal.h index e76012f..f1718f7 100644 --- a/src/Limelight-internal.h +++ b/src/Limelight-internal.h @@ -39,6 +39,10 @@ extern int AudioPacketDuration; #define isBefore24(x, y) (U24((x) - (y)) > (UINT24_MAX/2)) #define isBefore32(x, y) (U32((x) - (y)) > (UINT32_MAX/2)) +#ifndef ARRAYSIZE +#define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a))) +#endif + #define UDP_RECV_POLL_TIMEOUT_MS 100 // At this value or above, we will request high quality audio unless CAPABILITY_SLOW_OPUS_DECODER diff --git a/src/Misc.c b/src/Misc.c index 80b4a83..c1e5553 100644 --- a/src/Misc.c +++ b/src/Misc.c @@ -37,7 +37,7 @@ int extractVersionQuadFromString(const char* string, int* quad) { char* nextNumber; int i; - strcpy(versionString, string); + strcpy_s(versionString, ARRAYSIZE(versionString), string); nextNumber = versionString; for (i = 0; i < 4; i++) { diff --git a/src/Platform.h b/src/Platform.h index 598a1a4..8ad411b 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -1,5 +1,8 @@ #pragma once +// Don't warn for POSIX functions like strdup +#define _CRT_NONSTDC_NO_DEPRECATE + #include #include #include diff --git a/src/PlatformSockets.c b/src/PlatformSockets.c index f0ebef0..7937090 100644 --- a/src/PlatformSockets.c +++ b/src/PlatformSockets.c @@ -30,14 +30,14 @@ void addrToUrlSafeString(struct sockaddr_storage* addr, char* string) inet_ntop(addr->ss_family, &sin6->sin6_addr, addrstr, sizeof(addrstr)); // IPv6 addresses need to be enclosed in brackets for URLs - sprintf(string, "[%s]", addrstr); + sprintf_s(string, URLSAFESTRING_LEN, "[%s]", addrstr); } else { struct sockaddr_in* sin = (struct sockaddr_in*)addr; inet_ntop(addr->ss_family, &sin->sin_addr, addrstr, sizeof(addrstr)); // IPv4 addresses are returned without changes - sprintf(string, "%s", addrstr); + sprintf_s(string, URLSAFESTRING_LEN, "%s", addrstr); } } diff --git a/src/RtspConnection.c b/src/RtspConnection.c index faef8ce..c831448 100644 --- a/src/RtspConnection.c +++ b/src/RtspConnection.c @@ -71,8 +71,8 @@ static bool initializeRtspRequest(PRTSP_MESSAGE msg, char* command, char* target createRtspRequest(msg, NULL, 0, command, target, "RTSP/1.0", 0, NULL, NULL, 0); - sprintf(sequenceNumberStr, "%d", currentSeqNumber++); - sprintf(clientVersionStr, "%d", rtspClientVersion); + sprintf_s(sequenceNumberStr, ARRAYSIZE(sequenceNumberStr), "%d", currentSeqNumber++); + sprintf_s(clientVersionStr, ARRAYSIZE(clientVersionStr), "%d", rtspClientVersion); if (!addOption(msg, "CSeq", sequenceNumberStr) || !addOption(msg, "X-GS-ClientVersion", clientVersionStr) || (!useEnet && !addOption(msg, "Host", urlAddr))) { @@ -434,7 +434,7 @@ static bool sendVideoAnnounce(PRTSP_MESSAGE response, int* error) { request.flags |= FLAG_ALLOCATED_PAYLOAD; request.payloadLength = payloadLength; - sprintf(payloadLengthStr, "%d", payloadLength); + sprintf_s(payloadLengthStr, ARRAYSIZE(payloadLengthStr), "%d", payloadLength); if (!addOption(&request, "Content-length", payloadLengthStr)) { goto FreeMessage; } @@ -508,7 +508,7 @@ static int parseOpusConfigurations(PRTSP_MESSAGE response) { channelCount = CHANNEL_COUNT_FROM_AUDIO_CONFIGURATION(StreamConfig.audioConfiguration); // Find the correct audio parameter value - sprintf(paramsPrefix, "a=fmtp:97 surround-params=%d", channelCount); + sprintf_s(paramsPrefix, ARRAYSIZE(paramsPrefix), "a=fmtp:97 surround-params=%d", channelCount); paramStart = strstr(response->payload, paramsPrefix); if (paramStart) { // Skip the prefix @@ -596,12 +596,12 @@ int performRtspHandshake(void) { addrToUrlSafeString(&RemoteAddr, urlAddr); } else { - strcpy(urlAddr, "0.0.0.0"); + strcpy_s(urlAddr, ARRAYSIZE(urlAddr), "0.0.0.0"); } // Initialize global state useEnet = (AppVersionQuad[0] >= 5) && (AppVersionQuad[0] <= 7) && (AppVersionQuad[2] < 404); - sprintf(rtspTargetUrl, "rtsp%s://%s:48010", useEnet ? "ru" : "", urlAddr); + sprintf_s(rtspTargetUrl, ARRAYSIZE(rtspTargetUrl), "rtsp%s://%s:48010", useEnet ? "ru" : "", urlAddr); currentSeqNumber = 1; hasSessionId = false; @@ -740,6 +740,7 @@ int performRtspHandshake(void) { { RTSP_MESSAGE response; char* sessionId; + char* tokenizerContext; int error = -1; if (!setupStream(&response, @@ -770,7 +771,7 @@ int performRtspHandshake(void) { // resolves any 454 session not found errors on // standard RTSP server implementations. // (i.e - sessionId = "DEADBEEFCAFE;timeout = 90") - sessionIdString = strdup(strtok(sessionId, ";")); + sessionIdString = strdup(strtok_s(sessionId, ";", &tokenizerContext)); if (sessionIdString == NULL) { Limelog("Failed to duplicate session ID string\n"); ret = -1; diff --git a/src/RtspParser.c b/src/RtspParser.c index bb4cd46..efc5314 100644 --- a/src/RtspParser.c +++ b/src/RtspParser.c @@ -1,3 +1,4 @@ +#include "Limelight-internal.h" #include "Rtsp.h" // Check if String s begins with the given prefix @@ -26,7 +27,7 @@ static int getMessageLength(PRTSP_MESSAGE msg) { // Add length of response-specific strings else { char statusCodeStr[16]; - sprintf(statusCodeStr, "%d", msg->message.response.statusCode); + sprintf_s(statusCodeStr, ARRAYSIZE(statusCodeStr), "%d", msg->message.response.statusCode); count += strlen(statusCodeStr); count += strlen(msg->message.response.statusString); // two spaces and \r\n @@ -53,6 +54,7 @@ static int getMessageLength(PRTSP_MESSAGE msg) { // Given an RTSP message string rtspMessage, parse it into an RTSP_MESSAGE struct msg int parseRtspMessage(PRTSP_MESSAGE msg, char* rtspMessage, int length) { char* token; + char* tokenizerContext; char* protocol; char* endCheck; char* target; @@ -88,7 +90,7 @@ int parseRtspMessage(PRTSP_MESSAGE msg, char* rtspMessage, int length) { messageBuffer[length] = 0; // Get the first token of the message - token = strtok(messageBuffer, delim); + token = strtok_s(messageBuffer, delim, &tokenizerContext); if (token == NULL) { exitCode = RTSP_ERROR_MALFORMED; goto ExitFailure; @@ -101,7 +103,7 @@ int parseRtspMessage(PRTSP_MESSAGE msg, char* rtspMessage, int length) { protocol = token; // Get the status code - token = strtok(NULL, delim); + token = strtok_s(NULL, delim, &tokenizerContext); statusCode = atoi(token); if (token == NULL) { exitCode = RTSP_ERROR_MALFORMED; @@ -109,7 +111,7 @@ int parseRtspMessage(PRTSP_MESSAGE msg, char* rtspMessage, int length) { } // Get the status string - statusStr = strtok(NULL, end); + statusStr = strtok_s(NULL, end, &tokenizerContext); if (statusStr == NULL) { exitCode = RTSP_ERROR_MALFORMED; goto ExitFailure; @@ -124,12 +126,12 @@ int parseRtspMessage(PRTSP_MESSAGE msg, char* rtspMessage, int length) { else { flag = TYPE_REQUEST; command = token; - target = strtok(NULL, delim); + target = strtok_s(NULL, delim, &tokenizerContext); if (target == NULL) { exitCode = RTSP_ERROR_MALFORMED; goto ExitFailure; } - protocol = strtok(NULL, delim); + protocol = strtok_s(NULL, delim, &tokenizerContext); if (protocol == NULL) { exitCode = RTSP_ERROR_MALFORMED; goto ExitFailure; @@ -144,7 +146,7 @@ int parseRtspMessage(PRTSP_MESSAGE msg, char* rtspMessage, int length) { // Parse remaining options while (token != NULL) { - token = strtok(NULL, typeFlag == TOKEN_OPTION ? optDelim : end); + token = strtok_s(NULL, typeFlag == TOKEN_OPTION ? optDelim : end, &tokenizerContext); if (token != NULL) { if (typeFlag == TOKEN_OPTION) { opt = token; @@ -322,37 +324,37 @@ char* serializeRtspMessage(PRTSP_MESSAGE msg, int* serializedLength) { if (msg->type == TYPE_REQUEST) { // command [space] - strcpy(serializedMessage, msg->message.request.command); - strcat(serializedMessage, " "); + strcpy_s(serializedMessage, size, msg->message.request.command); + strcat_s(serializedMessage, size, " "); // target [space] - strcat(serializedMessage, msg->message.request.target); - strcat(serializedMessage, " "); + strcat_s(serializedMessage, size, msg->message.request.target); + strcat_s(serializedMessage, size, " "); // protocol \r\n - strcat(serializedMessage, msg->protocol); - strcat(serializedMessage, "\r\n"); + strcat_s(serializedMessage, size, msg->protocol); + strcat_s(serializedMessage, size, "\r\n"); } else { // protocol [space] - strcpy(serializedMessage, msg->protocol); - strcat(serializedMessage, " "); + strcpy_s(serializedMessage, size, msg->protocol); + strcat_s(serializedMessage, size, " "); // status code [space] - sprintf(statusCodeStr, "%d", msg->message.response.statusCode); - strcat(serializedMessage, statusCodeStr); - strcat(serializedMessage, " "); + sprintf_s(statusCodeStr, ARRAYSIZE(statusCodeStr), "%d", msg->message.response.statusCode); + strcat_s(serializedMessage, size, statusCodeStr); + strcat_s(serializedMessage, size, " "); // status str\r\n - strcat(serializedMessage, msg->message.response.statusString); - strcat(serializedMessage, "\r\n"); + strcat_s(serializedMessage, size, msg->message.response.statusString); + strcat_s(serializedMessage, size, "\r\n"); } // option content\r\n while (current != NULL) { - strcat(serializedMessage, current->option); - strcat(serializedMessage, ": "); - strcat(serializedMessage, current->content); - strcat(serializedMessage, "\r\n"); + strcat_s(serializedMessage, size, current->option); + strcat_s(serializedMessage, size, ": "); + strcat_s(serializedMessage, size, current->content); + strcat_s(serializedMessage, size, "\r\n"); current = current->next; } // Final \r\n - strcat(serializedMessage, "\r\n"); + strcat_s(serializedMessage, size, "\r\n"); // payload if (msg->payload != NULL) { diff --git a/src/SdpGenerator.c b/src/SdpGenerator.c index 3719845..c4c4a4f 100644 --- a/src/SdpGenerator.c +++ b/src/SdpGenerator.c @@ -39,14 +39,14 @@ static int getSerializedAttributeListSize(PSDP_OPTION head) { } // Populate the serialized attribute list into a string -static int fillSerializedAttributeList(char* buffer, PSDP_OPTION head) { +static int fillSerializedAttributeList(char* buffer, int bufferLength, PSDP_OPTION head) { PSDP_OPTION currentEntry = head; int offset = 0; while (currentEntry != NULL) { - offset += sprintf(&buffer[offset], "a=%s:", currentEntry->name); + offset += sprintf_s(&buffer[offset], bufferLength - offset, "a=%s:", currentEntry->name); memcpy(&buffer[offset], currentEntry->payload, currentEntry->payloadLen); offset += currentEntry->payloadLen; - offset += sprintf(&buffer[offset], " \r\n"); + offset += sprintf_s(&buffer[offset], bufferLength - offset, " \r\n"); currentEntry = currentEntry->next; } @@ -64,7 +64,7 @@ static int addAttributeBinary(PSDP_OPTION* head, char* name, const void* payload option->next = NULL; option->payloadLen = payloadLen; - strcpy(option->name, name); + strcpy_s(option->name, ARRAYSIZE(option->name), name); option->payload = (void*)(option + 1); memcpy(option->payload, payload, payloadLen); @@ -133,7 +133,7 @@ static int addGen4Options(PSDP_OPTION* head, char* addrStr) { char payloadStr[92]; int err = 0; - sprintf(payloadStr, "rtsp://%s:48010", addrStr); + sprintf_s(payloadStr, ARRAYSIZE(payloadStr), "rtsp://%s:48010", addrStr); err |= addAttributeString(head, "x-nv-general.serverAddress", payloadStr); return err; @@ -175,15 +175,15 @@ static PSDP_OPTION getAttributesList(char*urlSafeAddr) { optionHead = NULL; err = 0; - sprintf(payloadStr, "%d", StreamConfig.width); + sprintf_s(payloadStr, ARRAYSIZE(payloadStr), "%d", StreamConfig.width); err |= addAttributeString(&optionHead, "x-nv-video[0].clientViewportWd", payloadStr); - sprintf(payloadStr, "%d", StreamConfig.height); + sprintf_s(payloadStr, ARRAYSIZE(payloadStr), "%d", StreamConfig.height); err |= addAttributeString(&optionHead, "x-nv-video[0].clientViewportHt", payloadStr); - sprintf(payloadStr, "%d", StreamConfig.fps); + sprintf_s(payloadStr, ARRAYSIZE(payloadStr), "%d", StreamConfig.fps); err |= addAttributeString(&optionHead, "x-nv-video[0].maxFPS", payloadStr); - sprintf(payloadStr, "%d", StreamConfig.packetSize); + sprintf_s(payloadStr, ARRAYSIZE(payloadStr), "%d", StreamConfig.packetSize); err |= addAttributeString(&optionHead, "x-nv-video[0].packetSize", payloadStr); err |= addAttributeString(&optionHead, "x-nv-video[0].rateControlMode", "4"); @@ -222,7 +222,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); + sprintf_s(payloadStr, ARRAYSIZE(payloadStr), "%d", bitrate); err |= addAttributeString(&optionHead, "x-nv-video[0].initialBitrateKbps", payloadStr); err |= addAttributeString(&optionHead, "x-nv-video[0].initialPeakBitrateKbps", payloadStr); @@ -236,7 +236,7 @@ static PSDP_OPTION getAttributesList(char*urlSafeAddr) { err |= addAttributeString(&optionHead, "x-nv-video[0].peakBitrate", "4"); } - sprintf(payloadStr, "%d", bitrate); + sprintf_s(payloadStr, ARRAYSIZE(payloadStr), "%d", bitrate); err |= addAttributeString(&optionHead, "x-nv-vqos[0].bw.minimumBitrate", payloadStr); err |= addAttributeString(&optionHead, "x-nv-vqos[0].bw.maximumBitrate", payloadStr); } @@ -286,7 +286,7 @@ static PSDP_OPTION getAttributesList(char*urlSafeAddr) { // If not using slicing, we request 1 slice per frame slicesPerFrame = 1; } - sprintf(payloadStr, "%d", slicesPerFrame); + sprintf_s(payloadStr, ARRAYSIZE(payloadStr), "%d", slicesPerFrame); err |= addAttributeString(&optionHead, "x-nv-video[0].videoEncoderSlicesPerFrame", payloadStr); if (NegotiatedVideoFormat & VIDEO_FORMAT_MASK_H265) { @@ -340,13 +340,13 @@ static PSDP_OPTION getAttributesList(char*urlSafeAddr) { err |= addAttributeString(&optionHead, "x-nv-video[0].maxNumReferenceFrames", "1"); } - sprintf(payloadStr, "%d", StreamConfig.clientRefreshRateX100); + sprintf_s(payloadStr, ARRAYSIZE(payloadStr), "%d", StreamConfig.clientRefreshRateX100); err |= addAttributeString(&optionHead, "x-nv-video[0].clientRefreshRateX100", payloadStr); } - sprintf(payloadStr, "%d", audioChannelCount); + sprintf_s(payloadStr, ARRAYSIZE(payloadStr), "%d", audioChannelCount); err |= addAttributeString(&optionHead, "x-nv-audio.surround.numChannels", payloadStr); - sprintf(payloadStr, "%d", audioChannelMask); + sprintf_s(payloadStr, ARRAYSIZE(payloadStr), "%d", audioChannelMask); err |= addAttributeString(&optionHead, "x-nv-audio.surround.channelMask", payloadStr); if (audioChannelCount > 2) { err |= addAttributeString(&optionHead, "x-nv-audio.surround.enable", "1"); @@ -389,7 +389,7 @@ static PSDP_OPTION getAttributesList(char*urlSafeAddr) { } } - sprintf(payloadStr, "%d", AudioPacketDuration); + sprintf_s(payloadStr, ARRAYSIZE(payloadStr), "%d", AudioPacketDuration); err |= addAttributeString(&optionHead, "x-nv-aqos.packetDuration", payloadStr); } else { @@ -401,7 +401,7 @@ static PSDP_OPTION getAttributesList(char*urlSafeAddr) { } if (AppVersionQuad[0] >= 7) { - sprintf(payloadStr, "%d", (StreamConfig.colorSpace << 1) | StreamConfig.colorRange); + sprintf_s(payloadStr, ARRAYSIZE(payloadStr), "%d", (StreamConfig.colorSpace << 1) | StreamConfig.colorRange); err |= addAttributeString(&optionHead, "x-nv-video[0].encoderCscMode", payloadStr); } @@ -415,7 +415,7 @@ 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, + return sprintf_s(buffer, MAX_SDP_HEADER_LEN, "v=0\r\n" "o=android 0 %d IN %s %s\r\n" "s=NVIDIA Streaming Client\r\n", @@ -426,7 +426,7 @@ static int fillSdpHeader(char* buffer, int rtspClientVersion, char*urlSafeAddr) // Populate the SDP tail with required information static int fillSdpTail(char* buffer) { - return sprintf(buffer, + return sprintf_s(buffer, MAX_SDP_TAIL_LEN, "t=0 0\r\n" "m=video %d \r\n", AppVersionQuad[0] < 4 ? 47996 : 47998); @@ -435,6 +435,7 @@ static int fillSdpTail(char* buffer) { // Get the SDP attributes for the stream config char* getSdpPayloadForStreamConfig(int rtspClientVersion, int* length) { PSDP_OPTION attributeList; + int attributeListSize; int offset; char* payload; char urlSafeAddr[URLSAFESTRING_LEN]; @@ -446,15 +447,18 @@ 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); + + // Add 1 for the null terminator (which will immediately be overwritten by fillSdpTail()) + offset += fillSerializedAttributeList(&payload[offset], attributeListSize + 1, attributeList); + offset += fillSdpTail(&payload[offset]); freeAttributeList(attributeList); diff --git a/src/SimpleStun.c b/src/SimpleStun.c index f85708e..1b6a177 100644 --- a/src/SimpleStun.c +++ b/src/SimpleStun.c @@ -67,7 +67,7 @@ int LiFindExternalAddressIP4(const char* stunServer, unsigned short stunPort, un hints.ai_protocol = IPPROTO_UDP; hints.ai_flags = AI_ADDRCONFIG; - sprintf(stunPortStr, "%u", stunPort); + sprintf_s(stunPortStr, ARRAYSIZE(stunPortStr), "%u", stunPort); err = getaddrinfo(stunServer, stunPortStr, &hints, &stunAddrs); if (err != 0 || stunAddrs == NULL) { Limelog("Failed to resolve STUN server: %d\n", err);