Skip to content
Closed
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
5 changes: 5 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
-*- coding: utf-8 -*-
Changes with Apache 2.4.70

*) mod_dav_fs: Serialize lock database access with a global mutex so
concurrent LOCK requests cannot race on the shared DBM record
(lost locks, duplicate exclusive locks, Berkeley DB corruption).
Backport of r1914438 (PR #395). [Manfred Kaiser (AUT-milCERT)]

Changes with Apache 2.4.69

*) SECURITY: CVE-2026-93546: mod_dav_fs namespace overflow
Expand Down
40 changes: 34 additions & 6 deletions modules/dav/fs/lock.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ struct dav_lockdb_private
{
request_rec *r; /* for accessing the uuid state */
apr_pool_t *pool; /* a pool to use */
const char *lockdb_path; /* where is the lock database? */
const dav_fs_server_conf *conf; /* lock database path and mutex */

int opened; /* we opened the database */
dav_db *db; /* if non-NULL, the lock database */
Expand Down Expand Up @@ -297,25 +297,53 @@ static int dav_fs_compare_locktoken(
**
** If the database hasn't been opened yet, then open the thing.
*/
static apr_status_t dav_fs_lockdb_cleanup(void *data)
{
dav_lockdb *lockdb = data;

apr_global_mutex_unlock(lockdb->info->conf->lockdb_mutex);

if (lockdb->info->db) {
dav_dbm_close(lockdb->info->db);
}

return APR_SUCCESS;
}

static dav_error * dav_fs_really_open_lockdb(dav_lockdb *lockdb)
{
apr_status_t rv;
dav_error *err;

if (lockdb->info->opened)
return NULL;

rv = apr_global_mutex_lock(lockdb->info->conf->lockdb_mutex);
if (rv) {
return dav_new_error(lockdb->info->pool,
HTTP_INTERNAL_SERVER_ERROR,
DAV_ERR_LOCK_OPENDB, rv,
"Could not lock mutex for lock database.");
}

err = dav_dbm_open_direct(lockdb->info->pool,
lockdb->info->lockdb_path,
lockdb->info->conf->lockdb_path,
lockdb->ro,
&lockdb->info->db);
if (err != NULL) {
apr_global_mutex_unlock(lockdb->info->conf->lockdb_mutex);

return dav_push_error(lockdb->info->pool,
HTTP_INTERNAL_SERVER_ERROR,
DAV_ERR_LOCK_OPENDB,
"Could not open the lock database.",
err);
}

apr_pool_cleanup_register(lockdb->info->pool, lockdb,
dav_fs_lockdb_cleanup,
dav_fs_lockdb_cleanup);

/* all right. it is opened now. */
lockdb->info->opened = 1;

Expand All @@ -342,8 +370,8 @@ static dav_error * dav_fs_open_lockdb(request_rec *r, int ro, int force,
comb->priv.r = r;
comb->priv.pool = r->pool;

comb->priv.lockdb_path = dav_get_lockdb_path(r);
if (comb->priv.lockdb_path == NULL) {
comb->priv.conf = dav_fs_get_server_conf(r);
if (comb->priv.conf == NULL || comb->priv.conf->lockdb_path == NULL) {
return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR,
DAV_ERR_LOCK_NO_DB, 0,
"A lock database was not specified with the "
Expand All @@ -369,8 +397,8 @@ static dav_error * dav_fs_open_lockdb(request_rec *r, int ro, int force,
*/
static void dav_fs_close_lockdb(dav_lockdb *lockdb)
{
if (lockdb->info->db != NULL)
dav_dbm_close(lockdb->info->db);
apr_pool_cleanup_run(lockdb->info->pool, lockdb,
dav_fs_lockdb_cleanup);
}

/*
Expand Down
72 changes: 68 additions & 4 deletions modules/dav/fs/mod_dav_fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,27 @@
#include "http_config.h"
#include "http_log.h"
#include "http_request.h"
#include "http_core.h"
#include "util_mutex.h"
#include "apr_strings.h"
#include "apr_global_mutex.h"

#include "mod_dav.h"
#include "repos.h"

/* per-server configuration */
typedef struct {
const char *lockdb_path;
/* The dav_fs_server_conf type lives in repos.h so lock.c can see it. */

} dav_fs_server_conf;
static const char dav_fs_mutexid[] = "dav_fs-lockdb";

static apr_global_mutex_t *dav_fs_lockdb_mutex;

extern module AP_MODULE_DECLARE_DATA dav_fs_module;

const dav_fs_server_conf *dav_fs_get_server_conf(const request_rec *r)
{
return ap_get_module_config(r->server->module_config, &dav_fs_module);
}

const char *dav_get_lockdb_path(const request_rec *r)
{
dav_fs_server_conf *conf;
Expand Down Expand Up @@ -123,8 +131,64 @@ static int dav_fs_fixups(request_rec *r)
return HTTP_FORBIDDEN;
}

static int dav_fs_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
apr_pool_t *ptemp)
{
if (ap_mutex_register(pconf, dav_fs_mutexid, NULL, APR_LOCK_DEFAULT, 0))
return !OK;
return OK;
}

static void dav_fs_child_init(apr_pool_t *p, server_rec *s)
{
apr_status_t rv;

rv = apr_global_mutex_child_init(&dav_fs_lockdb_mutex,
apr_global_mutex_lockfile(dav_fs_lockdb_mutex),
p);
if (rv) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
APLOGNO(10488) "child init failed for mutex");
}
}

static apr_status_t dav_fs_post_config(apr_pool_t *p, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *base_server)
{
server_rec *s;
apr_status_t rv;

/* Ignore first pass through the config. */
if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG)
return OK;

rv = ap_global_mutex_create(&dav_fs_lockdb_mutex, NULL, dav_fs_mutexid, NULL,
base_server, p, 0);
if (rv) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, base_server,
APLOGNO(10489) "could not create lock mutex");
return !OK;
}

for (s = base_server; s; s = s->next) {
dav_fs_server_conf *conf;

conf = ap_get_module_config(s->module_config, &dav_fs_module);

/* Mutex is common across all vhosts, but could have one per
* vhost if required. */
conf->lockdb_mutex = dav_fs_lockdb_mutex;
}

return OK;
}

static void register_hooks(apr_pool_t *p)
{
ap_hook_pre_config(dav_fs_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_post_config(dav_fs_post_config, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_child_init(dav_fs_child_init, NULL, NULL, APR_HOOK_MIDDLE);

/* before mod_dav's fixup, which takes over the request */
ap_hook_fixups(dav_fs_fixups, NULL, NULL, APR_HOOK_FIRST);

Expand Down
12 changes: 12 additions & 0 deletions modules/dav/fs/repos.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#ifndef _DAV_FS_REPOS_H_
#define _DAV_FS_REPOS_H_

#include "apr_global_mutex.h"

/* the name this repository provider is registered under */
#define DAV_FS_PROVIDER_NAME "filesystem"

Expand Down Expand Up @@ -73,6 +75,16 @@ void dav_dbm_close(dav_db *db);
/* where is the lock database located? */
const char *dav_get_lockdb_path(const request_rec *r);

/* Per-server configuration (lock database path and the global mutex that
* serializes access to it; backported from trunk / PR #395). */
typedef struct {
const char *lockdb_path;
apr_global_mutex_t *lockdb_mutex;
} dav_fs_server_conf;

/* Returns the server configuration for the request. */
const dav_fs_server_conf *dav_fs_get_server_conf(const request_rec *r);

const dav_hooks_locks *dav_fs_get_lock_hooks(request_rec *r);
const dav_hooks_propdb *dav_fs_get_propdb_hooks(request_rec *r);

Expand Down