Add MOSQUITTO_UNSAFE_ALLOW_SYMLINKS env var

Setting this environment variable allows sensitive files to be read
through symlinks.

Closes #3461. Thanks to Jeff Cutsinger
This commit is contained in:
Roger A. Light
2026-02-02 16:33:37 +00:00
parent d4b5adbd49
commit 16f41e61fc
11 changed files with 173 additions and 1 deletions
+3
View File
@@ -3,6 +3,9 @@
# Broker
- Fix PUID/PGID checking for docker
- Add MOSQUITTO_UNSAFE_ALLOW_SYMLINKS environment variable to allow the
restrictions on reading files through symlinks to be lifted in safe
environments like kubernetes. Closes #3461.
2.1.0 - 2026-01-29
+4 -1
View File
@@ -166,7 +166,10 @@ FILE *mosquitto_fopen(const char *path, const char *mode, bool restrict_read)
old_mask = umask(0077);
int open_flags = O_NOFOLLOW;
int open_flags = 0;
if(!getenv("MOSQUITTO_UNSAFE_ALLOW_SYMLINKS")){
open_flags |= O_NOFOLLOW;
}
for(size_t i = 0; i<strlen(mode); i++){
if(mode[i] == 'r'){
open_flags |= O_RDONLY;
@@ -0,0 +1,14 @@
<varlistentry>
<term><envar>MOSQUITTO_UNSAFE_ALLOW_SYMLINKS</envar></term>
<listitem>
<para>
By default, sensitive file with a path including a
symbolic link will be refused to be loaded. Set this
environment variable to any value to allow load files
through symbolic links. Note that making use of this
variable could expose you to symlink attacks and so it
should only be used in cases where you are absolutely
sure this is not a risk.
</para>
</listitem>
</varlistentry>
+7
View File
@@ -974,6 +974,13 @@
</variablelist>
</refsect1>
<refsect1>
<title>Environment Variables</title>
<variablelist>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="common/env-var-mosquitto-unsafe-allow-symlinks.xml" />
</variablelist>
</refsect1>
<refsect1>
<title>Files</title>
<variablelist>
+8
View File
@@ -267,6 +267,14 @@
</refsect1>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="common/section-exit-status.xml" />
<refsect1>
<title>Environment Variables</title>
<variablelist>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="common/env-var-mosquitto-unsafe-allow-symlinks.xml" />
</variablelist>
</refsect1>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="common/section-bugs.xml" />
<refsect1>
+7
View File
@@ -179,6 +179,13 @@
</itemizedlist>
</refsect1>
<refsect1>
<title>Environment Variables</title>
<variablelist>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="common/env-var-mosquitto-unsafe-allow-symlinks.xml" />
</variablelist>
</refsect1>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="common/section-bugs.xml" />
<refsect1>
+3
View File
@@ -327,6 +327,9 @@ static void report_features(void)
#else
log__printf(NULL, MOSQ_LOG_INFO, "Websockets support NOT available.");
#endif
if(getenv("MOSQUITTO_UNSAFE_ALLOW_SYMLINKS")){
log__printf(NULL, MOSQ_LOG_NOTICE, "MOSQUITTO_UNSAFE_ALLOW_SYMLINKS is set, loading of sensitive files through symbolic links is allowed.");
}
}
+1
View File
@@ -1,5 +1,6 @@
add_executable(libcommon-test
base64_test.c
file_test.c
property_add.c
property_value.c
strings_test.c
+1
View File
@@ -14,6 +14,7 @@ endif
TEST_OBJS = \
base64_test.o \
file_test.o \
property_add.o \
property_value.o \
strings_test.o \
+123
View File
@@ -0,0 +1,123 @@
#include <CUnit/CUnit.h>
#include <CUnit/Basic.h>
#ifndef WIN32
# include <unistd.h>
#endif
#include <stdlib.h>
#include "mosquitto.h"
#define ALLOW_SYMLINKS "MOSQUITTO_UNSAFE_ALLOW_SYMLINKS"
#ifndef WIN32
static bool symlink_create(void)
{
FILE *fptr = mosquitto_fopen("libcommon_test", "rb", false);
/* Verify we are in the right path */
CU_ASSERT_PTR_NOT_NULL(fptr);
if(!fptr){
return false;
}
fclose(fptr);
int rc = symlink("libcommon_test", "libcommon_symlink");
CU_ASSERT_EQUAL(rc, 0);
return rc == 0?true:false;
}
static void symlink_remove(void)
{
unlink("libcommon_symlink");
}
#endif
#ifndef WIN32
static void TEST_restrict_read_default(void)
{
FILE *fptr;
if(!symlink_create()){
return;
}
unsetenv(ALLOW_SYMLINKS);
/* No restrict read, so symlink ok */
fptr = mosquitto_fopen("libcommon_symlink", "rb", false);
CU_ASSERT_PTR_NOT_NULL(fptr);
if(fptr){
fclose(fptr);
}
/* Restricted read, so symlink not allowed */
fptr = mosquitto_fopen("libcommon_symlink", "rb", true);
CU_ASSERT_PTR_NULL(fptr);
if(fptr){
fclose(fptr);
}
symlink_remove();
}
static void TEST_restrict_read_with_symlinks(void)
{
FILE *fptr;
if(!symlink_create()){
return;
}
int rc = setenv(ALLOW_SYMLINKS, "1", true);
CU_ASSERT_EQUAL(rc, 0);
/* No restrict read, so symlink ok */
fptr = mosquitto_fopen("libcommon_symlink", "rb", false);
CU_ASSERT_PTR_NOT_NULL(fptr);
if(fptr){
fclose(fptr);
}
/* Restricted read but with override so symlink ok */
fptr = mosquitto_fopen("libcommon_symlink", "rb", true);
CU_ASSERT_PTR_NOT_NULL(fptr);
if(fptr){
fclose(fptr);
}
symlink_remove();
unsetenv(ALLOW_SYMLINKS);
}
#endif
/* ========================================================================
* TEST SUITE SETUP
* ======================================================================== */
int init_file_tests(void)
{
CU_pSuite test_suite = NULL;
test_suite = CU_add_suite("file", NULL, NULL);
if(!test_suite){
printf("Error adding CUnit file test suite.\n");
return 1;
}
if(0
#ifndef WIN32
|| !CU_add_test(test_suite, "Restrict read default", TEST_restrict_read_default)
|| !CU_add_test(test_suite, "Restrict read with symlinks", TEST_restrict_read_with_symlinks)
#endif
){
printf("Error adding file CUnit tests.\n");
return 1;
}
return 0;
}
+2
View File
@@ -5,6 +5,7 @@
#include <CUnit/Basic.h>
int init_base64_tests(void);
int init_file_tests(void);
int init_property_add_tests(void);
int init_property_value_tests(void);
int init_strings_tests(void);
@@ -27,6 +28,7 @@ int main(int argc, char *argv[])
if(0
|| init_base64_tests()
|| init_file_tests()
|| init_property_add_tests()
|| init_property_value_tests()
|| init_strings_tests()