Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ option(USE_WERROR "Treat compiler warnings as errors (-Werror)" ON)
option(FAKE_ANDROID "Target Android but do not use actual cross compile/Android cmake to build for simple compile checks on Linux")

option(ENABLE_DNS_UPDOWN_BY_DEFAULT "Run --dns-updown hook by default" ON)

# Optional Clang -fbounds-safety. Default OFF: OVPN_*SIZED_BY* / OVPN_*COUNTED_BY*
# macros in src/openvpn/buffer_bounds_safety.h are inert and the ABI/build is unchanged.
# When ON, requires a Clang that provides -fbounds-safety / <ptrcheck.h>.
option(ENABLE_FBOUNDS_SAFETY "Enable experimental Clang -fbounds-safety annotations (OFF by default)" OFF)
if(ENABLE_FBOUNDS_SAFETY)
message(STATUS "ENABLE_FBOUNDS_SAFETY enabled")
else()
message(STATUS "ENABLE_FBOUNDS_SAFETY disabled")
endif()
set(DNS_UPDOWN_PATH "${CMAKE_INSTALL_PREFIX}/libexec/openvpn/dns-updown" CACHE STRING "Default location for the DNS up/down script")

set(PLUGIN_DIR "${CMAKE_INSTALL_PREFIX}/lib/openvpn/plugins" CACHE FILEPATH "Location of the plugin directory")
Expand Down Expand Up @@ -431,6 +441,7 @@ set(SOURCE_FILES
src/openvpn/basic.h
src/openvpn/buffer.c
src/openvpn/buffer.h
src/openvpn/buffer_bounds_safety.h
src/openvpn/check_file_access.c
src/openvpn/check_file_access.h
src/openvpn/circ_list.h
Expand Down Expand Up @@ -637,6 +648,12 @@ add_executable(openvpn ${SOURCE_FILES})

add_library_deps(openvpn)

# Optional -fbounds-safety (inert macros unless ENABLE_FBOUNDS_SAFETY)
if(ENABLE_FBOUNDS_SAFETY)
target_compile_definitions(openvpn PRIVATE OVPN_SUPPORT_FBOUNDS_SAFETY)
target_compile_options(openvpn PRIVATE -fbounds-safety)
endif()

target_compile_options(openvpn PRIVATE -DDEFAULT_DNS_UPDOWN=\"${DNS_UPDOWN_PATH}\")

if(MINGW)
Expand Down
14 changes: 14 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1327,6 +1327,20 @@ AC_SUBST([sampledir])
AC_SUBST([systemdunitdir])
AC_SUBST([tmpfilesdir])

AC_ARG_ENABLE(
[fbounds-safety],
[AS_HELP_STRING([--enable-fbounds-safety],
[enable experimental Clang -fbounds-safety annotations @<:@default=no@:>@])],
[enable_fbounds_safety="$enableval"],
[enable_fbounds_safety="no"]
)
if test "${enable_fbounds_safety}" = "yes"; then
AC_MSG_NOTICE([ENABLE_FBOUNDS_SAFETY enabled])
CFLAGS="${CFLAGS} -DOVPN_SUPPORT_FBOUNDS_SAFETY -fbounds-safety"
else
AC_MSG_NOTICE([ENABLE_FBOUNDS_SAFETY disabled])
fi

AC_ARG_ENABLE(
[unit-tests],
[AS_HELP_STRING([--disable-unit-tests],
Expand Down
1 change: 1 addition & 0 deletions src/openvpn/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ openvpn_SOURCES = \
base64.c base64.h \
basic.h \
buffer.c buffer.h \
buffer_bounds_safety.h \
check_file_access.c check_file_access.h \
circ_list.h \
clinat.c clinat.h \
Expand Down
4 changes: 4 additions & 0 deletions src/openvpn/buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ alloc_buf(size_t size)
{
buf_size_error(size);
}
/* Capacity before pointer so sized_by invariants hold under -fbounds-safety. */
buf.capacity = (int)size;
buf.data = calloc(1, size);
check_malloc_return(buf.data);
Expand All @@ -83,6 +84,7 @@ alloc_buf_gc(size_t size, struct gc_arena *gc)
{
buf_size_error(size);
}
/* Capacity before pointer so sized_by invariants hold under -fbounds-safety. */
buf.capacity = (int)size;
buf.data = (uint8_t *)gc_malloc(size, false, gc);
if (size)
Expand All @@ -100,6 +102,7 @@ clone_buf(const struct buffer *buf)
#endif
{
struct buffer ret;
/* Capacity before pointer so sized_by invariants hold under -fbounds-safety. */
ret.capacity = buf->capacity;
ret.offset = buf->offset;
ret.len = buf->len;
Expand Down Expand Up @@ -213,6 +216,7 @@ buf_sub(struct buffer *buf, int size, bool prepend)
data = prepend ? buf_prepend(buf, size) : buf_write_alloc(buf, size);
if (data)
{
/* Capacity before pointer so sized_by invariants hold under -fbounds-safety. */
ret.capacity = size;
ret.data = data;
}
Expand Down
21 changes: 14 additions & 7 deletions src/openvpn/buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "basic.h"
#include "error.h"
#include "integer.h"
#include "buffer_bounds_safety.h" /* optional -fbounds-safety macros */

/** Maximum allowed size (in bytes) for a single buffer allocation. */
#define BUF_SIZE_MAX 1000000
Expand Down Expand Up @@ -69,13 +70,19 @@
*/
struct buffer
{
int capacity; /**< Size in bytes of memory allocated by
* \c malloc(). */
int offset; /**< Offset in bytes of the actual content
* within the allocated memory. */
int len; /**< Length in bytes of the actual content
* within the allocated memory. */
uint8_t *data; /**< Pointer to the allocated memory. */
int capacity; /**< Size in bytes of memory allocated by
* \c malloc(). Capacity companion for
* \c data under optional -fbounds-safety. */
int offset; /**< Offset in bytes of the actual content
* within the allocated memory. */
int len; /**< Length in bytes of the actual content
* within the allocated memory. */
/* Field order already has capacity before data; alloc / set
* paths assign capacity before the pointer so sized-by
* invariants hold under optional -fbounds-safety builds.
* data may be NULL when capacity is zero (buf_reset / CLEAR).
*/
uint8_t *OVPN_SIZED_BY_OR_NULL(capacity) data; /**< Pointer to the allocated memory. */

#ifdef BUF_INIT_TRACKING
const char *debug_file;
Expand Down
63 changes: 63 additions & 0 deletions src/openvpn/buffer_bounds_safety.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2026 Jeff Bindel <jeff@incrediblybased.co>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <https://www.gnu.org/licenses/>.
*/

/**
* @file
* @brief Portability macros for optional Clang -fbounds-safety.
*
* When OVPN_SUPPORT_FBOUNDS_SAFETY is defined (typically via
* -DOVPN_SUPPORT_FBOUNDS_SAFETY and a Clang toolchain that implements
* -fbounds-safety), these macros expand to Clang bounds annotations.
* Otherwise they expand to nothing so default builds are unchanged.
*
* Pattern matches libwebp / libpng / giflib / lz4 / zstd / libzip
* inert-macro -fbounds-safety adoption: annotations are inert unless
* explicitly enabled.
*/

#ifndef BUFFER_BOUNDS_SAFETY_H
#define BUFFER_BOUNDS_SAFETY_H

#ifdef OVPN_SUPPORT_FBOUNDS_SAFETY

#include <ptrcheck.h>
/* Non-ABI-breaking sized-by annotations for byte buffers whose companion
* field / argument is a capacity in bytes (e.g. buffer.capacity).
* Prefer OVPN_SIZED_BY for buffers that are non-NULL when live; use
* *_OR_NULL when the pointer may be NULL while the companion capacity
* is zero (struct buffer.data may be NULL after buf_reset / CLEAR).
*/
#define OVPN_SIZED_BY(n) __sized_by(n)
#define OVPN_SIZED_BY_OR_NULL(n) __sized_by_or_null(n)
#define OVPN_COUNTED_BY(n) __counted_by(n)
#define OVPN_COUNTED_BY_OR_NULL(n) __counted_by_or_null(n)

#else /* !OVPN_SUPPORT_FBOUNDS_SAFETY */

#define OVPN_SIZED_BY(n)
#define OVPN_SIZED_BY_OR_NULL(n)
#define OVPN_COUNTED_BY(n)
#define OVPN_COUNTED_BY_OR_NULL(n)

#endif /* OVPN_SUPPORT_FBOUNDS_SAFETY */

#endif /* BUFFER_BOUNDS_SAFETY_H */