secure file path in upload/download

This commit is contained in:
Suvendhu Hansa
2025-07-16 19:52:57 +05:30
parent 6b88881229
commit 65dabfdb8f

View File

@@ -38,6 +38,8 @@
#include <dirent.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <limits.h>
#include <errno.h>
#include "usp_api.h"
#include "usp_err_codes.h"
@@ -62,13 +64,78 @@ static char *upload_out_args[] = { "Content", "Length", "Filesize", "Checksum",
// cppcheck-suppress cert-STR05-C
static char *session_start_arg[] = { "Timeout" };
#if defined(OBUSPA_ENABLE_DOWNLOAD_EXT) || defined(OBUSPA_ENABLE_UPLOAD_EXT)
static int validate_file_path(char *filename, char **filepath)
{
char abs_path[PATH_MAX] = {0};
char real_path[PATH_MAX] = {0};
if (filename == NULL || filepath == NULL) {
USP_LOG_Error("filename or filepath is NULL");
return -1;
}
int len = strlen(filename);
if (len == 0) {
USP_LOG_Error("Filename should not be empty");
return -1;
}
/* filename should not end with '/' */
if (filename[len - 1] == '/') {
USP_LOG_Error("Filename should not end with /");
return -1;
}
snprintf(abs_path, sizeof(abs_path), "/tmp/obuspa/%s", filename);
char *tmp_p = strrchr(abs_path, '/');
if (tmp_p == NULL) {
USP_LOG_Error("String processing error");
return -1;
}
*tmp_p = '\0';
/* filename should not be '.' or '..' */
tmp_p = tmp_p + 1;
if (strcmp(tmp_p, "..") == 0 || strcmp(tmp_p, ".") == 0) {
USP_LOG_Error("%s could not be used as filename", tmp_p);
return -1;
}
char *res = realpath(abs_path, real_path);
if (res == NULL) {
char* errStr = strerror(errno);
USP_LOG_Error("%s:%d (%s) %s", __FUNCTION__, __LINE__, abs_path, errStr);
return -1;
}
if (strcmp(real_path, "/tmp/obuspa") != 0 && strncmp(real_path, "/tmp/obuspa/", 12) != 0) {
USP_LOG_Error("%s:%d File path: (%s) can not be used", __FUNCTION__, __LINE__, real_path);
return -1;
}
size_t size = strlen(real_path) + strlen(tmp_p) + 2;
*filepath = (char*)USP_MALLOC(sizeof(char) * size);
if (*filepath == NULL) {
USP_LOG_Error("Memory allocation failed");
return -1;
}
snprintf(*filepath, size, "%s/%s", real_path, tmp_p);
return 0;
}
#endif
/************************************
* Upload functionality start
************************************/
#ifdef OBUSPA_ENABLE_UPLOAD_EXT
typedef struct {
int request_instance;
char file_path[4096];
char file_path[PATH_MAX];
} file_upload_input_cond_t;
void *FileUploadThreadMain(void *param)
@@ -217,6 +284,8 @@ static int upload_file_cb(dm_req_t *req, kv_vector_t *input_args,
int instance)
{
int i, err;
char *filename = NULL;
char *real_path = NULL;
if (req == NULL)
return USP_ERR_INTERNAL_ERROR;
@@ -239,17 +308,24 @@ static int upload_file_cb(dm_req_t *req, kv_vector_t *input_args,
cond->request_instance = instance;
for (i = 0; i < input_args->num_entries; i++) {
if (strcmp(input_args->vector[i].key, "Filename") == 0 && input_args->vector[i].value != NULL) {
snprintf(cond->file_path, sizeof(cond->file_path), "/tmp/obuspa/%s", input_args->vector[i].value);
filename = input_args->vector[i].value;
break;
}
}
if (strlen(cond->file_path) == 0) {
if (filename == NULL || strlen(filename) == 0) {
USP_FREE(cond);
return USP_ERR_COMMAND_FAILURE;
}
USP_LOG_Info("Filepath: %s", cond->file_path);
if (validate_file_path(filename, &real_path) != 0) {
USP_FREE(cond);
return USP_ERR_COMMAND_FAILURE;
}
snprintf(cond->file_path, sizeof(cond->file_path), "%s", real_path);
USP_SAFE_FREE(real_path);
USP_LOG_Info("Upload Filepath: %s", cond->file_path);
err = OS_UTILS_CreateThread("UploadFile", FileUploadThreadMain, cond);
if (err != USP_ERR_OK) {
@@ -324,7 +400,8 @@ static int download_file(kv_vector_t *in, kv_vector_t *out)
int i;
char *content = NULL, *filename = NULL, *checksum = NULL;
size_t filesize = 0, length = 0, total_frag = 1, frag_num = 1, req_id = 0;
char file_path[4096] = {0};
char file_path[PATH_MAX] = {0};
char *real_path = NULL;
FILE *fp = NULL;
size_t file_count = 0;
@@ -394,6 +471,12 @@ static int download_file(kv_vector_t *in, kv_vector_t *out)
return USP_ERR_OK;
}
if (validate_file_path(filename, &real_path) != 0) {
USP_ARG_Add(out, "Result", "Failed");
USP_ARG_Add(out, "Error", "File name can not be used");
return USP_ERR_OK;
}
/* check if 15 seconds expired from the last fragment download time, then
* cancel last download task and start a new one. */
time_t now = time(NULL);
@@ -410,6 +493,7 @@ static int download_file(kv_vector_t *in, kv_vector_t *out)
USP_ARG_Add(out, "Result", "Failed");
USP_ARG_Add(out, "Error", "One download task is ongoing, please wait to finish");
USP_LOG_Debug("%s:%d New download request rejected since one is going on", __FUNCTION__, __LINE__);
USP_SAFE_FREE(real_path);
return USP_ERR_OK;
}
@@ -430,6 +514,7 @@ static int download_file(kv_vector_t *in, kv_vector_t *out)
USP_LOG_Info("%s:%d Empty file content", __FUNCTION__, __LINE__);
remove_all_fragments();
reset_download_task();
USP_SAFE_FREE(real_path);
return USP_ERR_OK;
}
@@ -440,6 +525,7 @@ static int download_file(kv_vector_t *in, kv_vector_t *out)
USP_ARG_Add(out, "Error", "Failed to write data");
remove_all_fragments();
reset_download_task();
USP_SAFE_FREE(real_path);
return USP_ERR_OK;
}
@@ -450,6 +536,7 @@ static int download_file(kv_vector_t *in, kv_vector_t *out)
last_dw_time = time(NULL);
USP_ARG_Add(out, "Result", "Success");
USP_ARG_Add(out, "Error", "");
USP_SAFE_FREE(real_path);
return USP_ERR_OK;
}
@@ -461,6 +548,7 @@ static int download_file(kv_vector_t *in, kv_vector_t *out)
USP_ARG_Add(out, "Error", "Failed to start reassembling the package");
remove_all_fragments();
reset_download_task();
USP_SAFE_FREE(real_path);
return USP_ERR_OK;
}
@@ -495,40 +583,45 @@ static int download_file(kv_vector_t *in, kv_vector_t *out)
USP_ARG_Add(out, "Result", "Failed");
USP_ARG_Add(out, "Error", "Failed to reassemble the package");
reset_download_task();
USP_SAFE_FREE(real_path);
return USP_ERR_OK;
}
USP_LOG_Info("Download Filepath: %s", real_path);
size_t datalen = 0;
snprintf(file_path, sizeof(file_path), "/tmp/obuspa/%s", filename);
if (0 != base64_decode(frag_merge_path, &datalen, file_path)) {
if (0 != base64_decode(frag_merge_path, &datalen, real_path)) {
USP_LOG_Debug("%s: Failed to decode the content", __FUNCTION__);
remove(frag_merge_path);
USP_ARG_Add(out, "Result", "Failed");
USP_ARG_Add(out, "Error", "Failed to decode the data");
reset_download_task();
USP_SAFE_FREE(real_path);
return USP_ERR_OK;
}
remove(frag_merge_path);
if (filesize != datalen) {
remove(file_path);
remove(real_path);
char tmp[512] = {0};
snprintf(tmp, sizeof(tmp), "Received filesize: %lu mismatched with decoded filesize:%lu", (unsigned long)filesize, (unsigned long)datalen);
USP_LOG_Info("%s", tmp);
USP_ARG_Add(out, "Result", "Failed");
USP_ARG_Add(out, "Error", tmp);
reset_download_task();
USP_SAFE_FREE(real_path);
return USP_ERR_OK;
}
// Calculate md5sum
// cppcheck-suppress cert-MSC24-C
fp = fopen(file_path, "rb");
fp = fopen(real_path, "rb");
if (fp == NULL) {
USP_ARG_Add(out, "Result", "Failed");
USP_ARG_Add(out, "Error", "Failed to get checksum");
remove(file_path);
remove(real_path);
reset_download_task();
USP_SAFE_FREE(real_path);
return USP_ERR_OK;
}
@@ -557,14 +650,16 @@ static int download_file(kv_vector_t *in, kv_vector_t *out)
USP_ARG_Add(out, "Result", "Failed");
USP_ARG_Add(out, "Error", "Checksum mismatched");
USP_LOG_Debug("%s: checksum %s not matched %s", __FUNCTION__, checksum, hash);
remove(file_path);
remove(real_path);
reset_download_task();
USP_SAFE_FREE(real_path);
return USP_ERR_OK;
}
USP_ARG_Add(out, "Result", "Success");
USP_ARG_Add(out, "Error", "");
reset_download_task();
USP_SAFE_FREE(real_path);
return USP_ERR_OK;
}