Skip to content

Commit 170ae09

Browse files
authored
Merge pull request #370 from dpw13/fix/audit-strcpy
Fix/audit strcpy
2 parents 69abc83 + bd6fd9b commit 170ae09

File tree

134 files changed

+1746
-2029
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

134 files changed

+1746
-2029
lines changed

CMakeLists.txt

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -388,9 +388,6 @@ message(STATUS "Excluding main.c from CORE_SOURCES (library build)")
388388
file(GLOB DATABASE_SOURCES "src/database/*.c")
389389
file(GLOB STORAGE_SOURCES "src/storage/*.c")
390390
file(GLOB UTILS_SOURCES "src/utils/*.c")
391-
# Exclude rebuild_recordings.c from UTILS_SOURCES to avoid multiple main functions
392-
list(FILTER UTILS_SOURCES EXCLUDE REGEX ".*rebuild_recordings\\.c$")
393-
message(STATUS "Excluding rebuild_recordings.c from main executable")
394391
file(GLOB_RECURSE WEB_SOURCES "src/web/*.c")
395392

396393
# Filter web sources - exclude libuv sources (they're added separately via LIBUV_SERVER_SOURCES)
@@ -410,10 +407,10 @@ list(APPEND ROOT_SOURCES
410407
# errors when linking test executables against lightnvr_lib.
411408
list(FILTER ROOT_SOURCES EXCLUDE REGEX ".*sod/sod\\.c$")
412409
list(FILTER ROOT_SOURCES EXCLUDE REGEX ".*core/main\\.c$")
413-
list(FILTER ROOT_SOURCES EXCLUDE REGEX ".*utils/rebuild_recordings\\.c$")
410+
list(FILTER ROOT_SOURCES EXCLUDE REGEX ".*tools/.*\\.c$")
414411
# Also exclude libuv sources from ROOT_SOURCES (they're added separately)
415412
list(FILTER ROOT_SOURCES EXCLUDE REGEX ".*libuv_.*\\.c$")
416-
message(STATUS "Excluding main.c and rebuild_recordings.c from ROOT_SOURCES")
413+
message(STATUS "Excluding main.c and tools from ROOT_SOURCES")
417414

418415
# Collect video sources from src/video, then exclude motion_detection_optimized.c,
419416
# detection_thread_pool.c, and the original hls_writer_thread.c (since we're using our split version).
@@ -504,9 +501,10 @@ add_executable(lightnvr src/core/main.c)
504501
505502
# Define source files for rebuild_recordings utility (excluding inih)
506503
set(REBUILD_RECORDINGS_SOURCES
507-
src/utils/rebuild_recordings.c
504+
src/tools/rebuild_recordings.c
508505
src/core/config.c
509506
src/core/logger.c
507+
src/utils/strings.c
510508
src/database/db_core.c
511509
src/database/db_streams.c
512510
src/database/db_recordings.c

examples/onvif_motion_recording_example.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ void example_enable_motion_recording(void) {
3030
};
3131

3232
// Set codec and quality
33-
strncpy(config.codec, "h264", sizeof(config.codec) - 1);
34-
strncpy(config.quality, "high", sizeof(config.quality) - 1);
33+
safe_strcpy(config.codec, "h264", sizeof(config.codec), 0);
34+
safe_strcpy(config.quality, "high", sizeof(config.quality), 0);
3535

3636
// Enable for a stream
3737
const char *stream_name = "front_door";
@@ -115,7 +115,7 @@ void example_check_status(void) {
115115
}
116116

117117
// Get current recording path
118-
char path[512];
118+
char path[MAX_PATH_LENGTH];
119119
if (get_current_motion_recording_path(stream_name, path, sizeof(path)) == 0) {
120120
printf("Current recording: %s\n", path);
121121
} else {
@@ -140,8 +140,8 @@ void example_update_configuration(void) {
140140
.retention_days = 60 // Increased to 60 days
141141
};
142142

143-
strncpy(new_config.codec, "h265", sizeof(new_config.codec) - 1);
144-
strncpy(new_config.quality, "medium", sizeof(new_config.quality) - 1);
143+
safe_strcpy(new_config.codec, "h265", sizeof(new_config.codec), 0);
144+
safe_strcpy(new_config.quality, "medium", sizeof(new_config.quality), 0);
145145

146146
int result = update_motion_recording_config(stream_name, &new_config);
147147

@@ -199,8 +199,8 @@ void example_multiple_cameras(void) {
199199
.retention_days = 30
200200
};
201201

202-
strncpy(config.codec, "h264", sizeof(config.codec) - 1);
203-
strncpy(config.quality, "high", sizeof(config.quality) - 1);
202+
safe_strcpy(config.codec, "h264", sizeof(config.codec), 0);
203+
safe_strcpy(config.quality, "high", sizeof(config.quality), 0);
204204

205205
int result = enable_motion_recording(cameras[i], &config);
206206

include/core/config.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ typedef struct {
127127

128128
// New recording format options
129129
bool record_mp4_directly; // Record directly to MP4 alongside HLS
130-
char mp4_storage_path[256]; // Path for MP4 recordings storage
130+
char mp4_storage_path[MAX_PATH_LENGTH]; // Path for MP4 recordings storage
131131
int mp4_segment_duration; // Duration of each MP4 segment in seconds
132132
int mp4_retention_days; // Number of days to keep MP4 recordings
133133

include/database/db_recordings.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
#include <stdbool.h>
66
#include <time.h>
77

8+
#include "core/config.h"
9+
810
// Recording metadata structure
911
typedef struct {
1012
uint64_t id;
1113
char stream_name[64];
12-
char file_path[256];
14+
char file_path[MAX_PATH_LENGTH];
1315
time_t start_time;
1416
time_t end_time;
1517
uint64_t size_bytes;

include/storage/storage_manager.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
#include <stdbool.h>
66
#include <time.h>
77

8+
#include "core/config.h"
9+
810
// Recording file information structure
911
typedef struct {
10-
char path[256];
12+
char path[MAX_PATH_LENGTH];
1113
char stream_name[64];
1214
time_t start_time;
1315
time_t end_time;

include/utils/memory.h

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -40,34 +40,6 @@ void *safe_calloc(size_t nmemb, size_t size);
4040
*/
4141
void safe_free(void *ptr);
4242

43-
/**
44-
* Safe string duplication
45-
*
46-
* @param str String to duplicate
47-
* @return Pointer to duplicated string or NULL on failure
48-
*/
49-
char *safe_strdup(const char *str);
50-
51-
/**
52-
* Safe string copy with size checking
53-
*
54-
* @param dest Destination buffer
55-
* @param src Source string
56-
* @param size Size of destination buffer
57-
* @return 0 on success, -1 on failure
58-
*/
59-
int safe_strcpy(char *dest, const char *src, size_t size);
60-
61-
/**
62-
* Safe string concatenation with size checking
63-
*
64-
* @param dest Destination buffer
65-
* @param src Source string
66-
* @param size Size of destination buffer
67-
* @return 0 on success, -1 on failure
68-
*/
69-
int safe_strcat(char *dest, const char *src, size_t size);
70-
7143
/**
7244
* Secure memory clearing function that won't be optimized away
7345
*

include/utils/strings.h

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,40 @@
33
#ifndef STRINGS_H
44
#define STRINGS_H
55

6+
#include <ctype.h>
7+
#include <stdlib.h>
68
#include <stdbool.h>
9+
#include <string.h>
10+
11+
/**
12+
* Safe string duplication
13+
*
14+
* @param str String to duplicate
15+
* @return Pointer to duplicated string or NULL on failure
16+
*/
17+
char *safe_strdup(const char *str);
18+
19+
/**
20+
* Safe string copy with size checking. It is safe to pass an unterminated
21+
* string in `src`: the string will not be checked beyond `src_size` bytes.
22+
*
23+
* @param dest Destination buffer
24+
* @param src Source string
25+
* @param dst_size Size of destination buffer
26+
* @param src_size Size of source buffer if not null-terminated
27+
* @return 0 on success (including if the string is truncated), -1 on failure
28+
*/
29+
int safe_strcpy(char *dest, const char *src, size_t dst_size, size_t src_size);
30+
31+
/**
32+
* Safe string concatenation with size checking
33+
*
34+
* @param dest Destination buffer
35+
* @param src Source string
36+
* @param size Size of destination buffer
37+
* @return 0 on success, -1 on failure
38+
*/
39+
int safe_strcat(char *dest, const char *src, size_t size);
740

841
/**
942
* Check if a string ends with a given suffix
@@ -14,4 +47,70 @@
1447
*/
1548
bool ends_with(const char *str, const char *suffix);
1649

50+
/**
51+
* Returns a pointer to the first printable non-space character in the input string
52+
* and terminates the string after the last printable non-space character.
53+
*
54+
* @param value The input string
55+
* @return A pointer into the original string
56+
*/
57+
char *trim_ascii_whitespace(char *value);
58+
59+
/**
60+
* Copies up to `output_size` bytes of the input string excluding any leading
61+
* and trailing whitespace or non-printing characters into the output buffer.
62+
* Guaranteed to null-terminate the output buffer.
63+
*
64+
* @param output The output buffer
65+
* @param output_size The size of the output buffer
66+
* @param input The input string
67+
* @param input_size The maximum size of the input string to check, or zero to
68+
* not limit the input string size
69+
* @return The number of bytes copied, not counting the terminator
70+
*/
71+
size_t copy_trimmed_value(char *output, size_t output_size, const char *input, size_t input_size);
72+
73+
/**
74+
* Returns a pointer to the first printable character in the input string.
75+
*/
76+
static inline const char *ltrim_pos(const char *input) {
77+
if (!input) {
78+
return NULL;
79+
}
80+
81+
unsigned char *start = (unsigned char *)input;
82+
while (*start && !isgraph(*start)) {
83+
start++;
84+
}
85+
return (const char *)start;
86+
}
87+
88+
/**
89+
* Returns a pointer to the byte _after_ the last printable character
90+
* in the input string. Set the returned pointer to '\0' to terminate
91+
* the string after the last printable character.
92+
*/
93+
static inline const char *rtrim_pos(const char *input, size_t input_size) {
94+
if (!input) {
95+
return NULL;
96+
}
97+
98+
const char *end;
99+
if (input_size > 0) {
100+
end = (input + strnlen(input, input_size) - 1);
101+
} else {
102+
// If input_size is zero, use the unbounded strlen
103+
end = (input + strlen(input) - 1);
104+
}
105+
// `end` will now point to the last non-null character. If the input is
106+
// empty, `end` will be (input-1), the character *before* the terminating
107+
// null.
108+
while (end > input && !isgraph((unsigned char)*end)) {
109+
end--;
110+
}
111+
// Point to the character after the last printable character. If input was
112+
// empty, this will now point to the terminating null.
113+
return end + 1;
114+
}
115+
17116
#endif //STRINGS_H

include/video/onvif_soap.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,13 @@ char *onvif_create_security_header(const char *username, const char *password);
2828
* can be parsed at the error level. If the XML cannot be parsed at all,
2929
* logs the raw response (truncated) as a fallback.
3030
*
31-
* @param response The raw XML response body (will be modified by the
32-
* XML parser — pass a copy if the original is needed).
31+
* @param response The raw XML response body.
3332
* @param response_len Length of the response in bytes.
3433
* @param context A short description of the request that failed
3534
* (e.g. "PullMessages", "CreatePullPointSubscription"),
3635
* used to prefix the log message. May be NULL.
3736
*/
38-
void onvif_log_soap_fault(char *response, size_t response_len, const char *context);
37+
void onvif_log_soap_fault(const char *response, size_t response_len, const char *context);
3938

4039
#endif /* ONVIF_SOAP_H */
4140

include/web/api_handlers_timeline.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
typedef struct {
1111
uint64_t id;
1212
char stream_name[64];
13-
char file_path[256];
13+
char file_path[MAX_PATH_LENGTH];
1414
time_t start_time;
1515
time_t end_time;
1616
uint64_t size_bytes;

include/web/http_server.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ typedef struct {
2828
char allowed_methods[256]; // CORS allowed methods
2929
char allowed_headers[256]; // CORS allowed headers
3030
bool ssl_enabled; // SSL/TLS enabled
31-
char cert_path[256]; // SSL/TLS certificate path
32-
char key_path[256]; // SSL/TLS key path
31+
char cert_path[MAX_PATH_LENGTH]; // SSL/TLS certificate path
32+
char key_path[MAX_PATH_LENGTH]; // SSL/TLS key path
3333
int max_connections; // Maximum number of connections
3434
int connection_timeout; // Connection timeout in seconds
3535
bool daemon_mode; // Daemon mode
36-
char pid_file[256]; // PID file path
36+
char pid_file[MAX_PATH_LENGTH]; // PID file path
3737
} http_server_config_t;
3838

3939
/**

0 commit comments

Comments
 (0)