Bugfix/validate-user-provided-file-object-paths (#1197)
* Fixed BACnet file object path name unintended path traversals by optionally restricting path name content with BACNET_FILE_PATH_RESTRICTED define. * Added POSIX file path name checking for AtomicReadFile and AtomicWriteFile example applications. Prohibits use of relative and absolute file paths when BACNET_FILE_PATH_RESTRICTED is non-zero.
This commit is contained in:
@@ -29,9 +29,6 @@
|
||||
#include "bacnet/basic/sys/keylist.h"
|
||||
#include "bacnet/basic/tsm/tsm.h"
|
||||
|
||||
#ifndef FILE_RECORD_SIZE
|
||||
#define FILE_RECORD_SIZE MAX_OCTET_STRING_BYTES
|
||||
#endif
|
||||
struct object_data {
|
||||
char *Object_Name;
|
||||
char *Pathname;
|
||||
|
||||
@@ -1,14 +1,25 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Function for filename manipulation
|
||||
* @brief Function for filename and path manipulation and validation
|
||||
* @author Steve Karg <skarg@users.sourceforge.net>
|
||||
* @date 2007
|
||||
* @copyright SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "bacnet/basic/sys/debug.h"
|
||||
#include "bacnet/basic/sys/filename.h"
|
||||
|
||||
/* restrict file paths */
|
||||
#ifndef BACNET_FILE_PATH_RESTRICTED
|
||||
#define BACNET_FILE_PATH_RESTRICTED 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Remove path from filename
|
||||
* @param filename_in - input filename with path
|
||||
* @return filename without path
|
||||
*/
|
||||
const char *filename_remove_path(const char *filename_in)
|
||||
{
|
||||
const char *filename_out = filename_in;
|
||||
@@ -30,3 +41,57 @@ const char *filename_remove_path(const char *filename_in)
|
||||
|
||||
return filename_out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Validate if pathname is valid by checking for patterns
|
||||
* such as relative paths and absolute paths which are prohibited.
|
||||
* @param pathname Path to validate
|
||||
* @return true if valid, false if not
|
||||
*/
|
||||
bool filename_path_valid(const char *pathname)
|
||||
{
|
||||
int path_len;
|
||||
|
||||
if (!pathname) {
|
||||
return false;
|
||||
}
|
||||
if (pathname[0] == 0) {
|
||||
return false;
|
||||
}
|
||||
#if BACNET_FILE_PATH_RESTRICTED
|
||||
/* check for relative directory patterns */
|
||||
if (strstr(pathname, "..") != NULL) {
|
||||
debug_printf_stderr("Relative paths are prohibited: %s\n", pathname);
|
||||
return false;
|
||||
}
|
||||
/* check for absolute paths */
|
||||
if (pathname[0] == '/') {
|
||||
debug_printf_stderr("Absolute paths are prohibited: %s\n", pathname);
|
||||
return false;
|
||||
}
|
||||
/* check for Windows drive letters (should be relative paths only) */
|
||||
path_len = strlen(pathname);
|
||||
if (path_len >= 2 && pathname[1] == ':') {
|
||||
debug_printf_stderr(
|
||||
"Windows drive letters are prohibited: %s\n", pathname);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* check for consecutive path separators */
|
||||
if (strstr(pathname, "//") != NULL || strstr(pathname, "\\\\") != NULL) {
|
||||
debug_printf_stderr(
|
||||
"Consecutive path separators are prohibited: %s\n", pathname);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* check for path components that are just dots */
|
||||
if (strstr(pathname, "/./") != NULL || strstr(pathname, "\\./") != NULL ||
|
||||
strstr(pathname, "/.\\") != NULL || strstr(pathname, "\\.\\") != NULL) {
|
||||
debug_printf_stderr(
|
||||
"Current directory references are prohibited: %s\n", pathname);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
#define BACNET_SYS_FILENAME_H
|
||||
/* BACnet Stack defines - first */
|
||||
#include "bacnet/bacdef.h"
|
||||
/* standard includes */
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -16,6 +20,8 @@ extern "C" {
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
const char *filename_remove_path(const char *filename_in);
|
||||
BACNET_STACK_EXPORT
|
||||
bool filename_path_valid(const char *pathname);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user