1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-11 05:18:09 +03:00

dbwrap_rbt: add nested traverse protection

Multiple dbwrap_traverse_read() calls are possible.

store() and delete() on a fetch locked record
are rejected during dbwrap_traverse_read().

A dbwrap_traverse() within a dbwrap_traverse_read()
behaves like a dbwrap_traverse_read().

Nested dbwrap_traverse() calls are not possible.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11375
BUG: https://bugzilla.samba.org/show_bug.cgi?id=11394

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
This commit is contained in:
Stefan Metzmacher 2015-11-25 09:22:08 +01:00
parent f3d1fc1d06
commit 590507951f

View File

@ -27,6 +27,8 @@
struct db_rbt_ctx {
struct rb_root tree;
size_t traverse_read;
bool traverse_write;
};
struct db_rbt_rec {
@ -126,6 +128,10 @@ static NTSTATUS db_rbt_store(struct db_record *rec, TDB_DATA data, int flag)
ssize_t reclen;
TDB_DATA this_key, this_val;
if (db_ctx->traverse_read > 0) {
return NT_STATUS_MEDIA_WRITE_PROTECTED;
}
if (rec_priv->node != NULL) {
/*
@ -222,6 +228,10 @@ static NTSTATUS db_rbt_delete(struct db_record *rec)
rec->db->private_data, struct db_rbt_ctx);
struct db_rbt_rec *rec_priv = (struct db_rbt_rec *)rec->private_data;
if (db_ctx->traverse_read > 0) {
return NT_STATUS_MEDIA_WRITE_PROTECTED;
}
if (rec_priv->node == NULL) {
return NT_STATUS_OK;
}
@ -232,16 +242,6 @@ static NTSTATUS db_rbt_delete(struct db_record *rec)
return NT_STATUS_OK;
}
static NTSTATUS db_rbt_store_deny(struct db_record *rec, TDB_DATA data, int flag)
{
return NT_STATUS_MEDIA_WRITE_PROTECTED;
}
static NTSTATUS db_rbt_delete_deny(struct db_record *rec)
{
return NT_STATUS_MEDIA_WRITE_PROTECTED;
}
struct db_rbt_search_result {
TDB_DATA key;
TDB_DATA val;
@ -414,13 +414,8 @@ static int db_rbt_traverse_internal(struct db_context *db,
ZERO_STRUCT(rec);
rec.db = db;
rec.private_data = &rec_priv;
if (rw) {
rec.store = db_rbt_store;
rec.delete_rec = db_rbt_delete;
} else {
rec.store = db_rbt_store_deny;
rec.delete_rec = db_rbt_delete_deny;
}
rec.store = db_rbt_store;
rec.delete_rec = db_rbt_delete;
db_rbt_parse_node(rec_priv.node, &rec.key, &rec.value);
ret = f(&rec, private_data);
@ -440,18 +435,21 @@ static int db_rbt_traverse_internal(struct db_context *db,
return db_rbt_traverse_internal(db, rb_right, f, private_data, count, rw);
}
static int db_rbt_traverse(struct db_context *db,
int (*f)(struct db_record *db,
void *private_data),
void *private_data)
static int db_rbt_traverse_read(struct db_context *db,
int (*f)(struct db_record *db,
void *private_data),
void *private_data)
{
struct db_rbt_ctx *ctx = talloc_get_type_abort(
db->private_data, struct db_rbt_ctx);
uint32_t count = 0;
int ret;
int ret = db_rbt_traverse_internal(db, ctx->tree.rb_node,
f, private_data, &count,
true /* rw */);
ctx->traverse_read++;
ret = db_rbt_traverse_internal(db, ctx->tree.rb_node,
f, private_data, &count,
false /* rw */);
ctx->traverse_read--;
if (ret != 0) {
return -1;
}
@ -461,18 +459,29 @@ static int db_rbt_traverse(struct db_context *db,
return count;
}
static int db_rbt_traverse_read(struct db_context *db,
int (*f)(struct db_record *db,
void *private_data),
void *private_data)
static int db_rbt_traverse(struct db_context *db,
int (*f)(struct db_record *db,
void *private_data),
void *private_data)
{
struct db_rbt_ctx *ctx = talloc_get_type_abort(
db->private_data, struct db_rbt_ctx);
uint32_t count = 0;
int ret;
int ret = db_rbt_traverse_internal(db, ctx->tree.rb_node,
f, private_data, &count,
false /* rw */);
if (ctx->traverse_write) {
return -1;
};
if (ctx->traverse_read > 0) {
return db_rbt_traverse_read(db, f, private_data);
}
ctx->traverse_write = true;
ret = db_rbt_traverse_internal(db, ctx->tree.rb_node,
f, private_data, &count,
true /* rw */);
ctx->traverse_write = false;
if (ret != 0) {
return -1;
}