diff options
author | Stefan Metzmacher <metze@samba.org> | 2015-11-25 09:22:08 +0100 |
---|---|---|
committer | Karolin Seeger <kseeger@samba.org> | 2016-01-11 11:21:09 +0100 |
commit | 4a0f277c00f8a7a82f48e9a3eb284c434bf23295 (patch) | |
tree | fa6834e2e8076120ec01fabbfefa625dd65583f6 | |
parent | a9071dcf8a7eec7c2f45fd17fc8b37367377e2d7 (diff) | |
download | samba-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.c | 71 |
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; } |