diff options
author | Stefan Metzmacher <metze@samba.org> | 2015-11-25 09:22:08 +0100 |
---|---|---|
committer | Stefan Metzmacher <metze@samba.org> | 2015-11-27 10:10:18 +0100 |
commit | 590507951fc514a679f44b8bfdd03c721189c3fa (patch) | |
tree | f8ec34218660bbdadfa4babddb9db09aecfbba89 /lib | |
parent | f3d1fc1d06822a951a2a3eeb5aa53748b9b5b299 (diff) | |
download | samba-590507951fc514a679f44b8bfdd03c721189c3fa.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>
Diffstat (limited to 'lib')
-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 37d9649a759..622ab0dd24b 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; } |