summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2015-11-25 09:22:08 +0100
committerKarolin Seeger <kseeger@samba.org>2016-01-11 11:21:09 +0100
commit4a0f277c00f8a7a82f48e9a3eb284c434bf23295 (patch)
treefa6834e2e8076120ec01fabbfefa625dd65583f6
parenta9071dcf8a7eec7c2f45fd17fc8b37367377e2d7 (diff)
downloadsamba-4a0f277c00f8a7a82f48e9a3eb284c434bf23295.tar.gz
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> (cherry picked from commit 590507951fc514a679f44b8bfdd03c721189c3fa)
-rw-r--r--lib/dbwrap/dbwrap_rbt.c71
1 files changed, 40 insertions, 31 deletions
diff --git a/lib/dbwrap/dbwrap_rbt.c b/lib/dbwrap/dbwrap_rbt.c
index 2d656472219..d4cb40d3d93 100644
--- a/lib/dbwrap/dbwrap_rbt.c
+++ b/lib/dbwrap/dbwrap_rbt.c
@@ -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;
+
+ if (ctx->traverse_write) {
+ return -1;
+ };
+
+ if (ctx->traverse_read > 0) {
+ return db_rbt_traverse_read(db, f, private_data);
+ }
- int ret = db_rbt_traverse_internal(db, ctx->tree.rb_node,
- f, private_data, &count,
- false /* rw */);
+ 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;
}