From 4b3cea8249337dd6e5037b5fb7e4557efa92de5a Mon Sep 17 00:00:00 2001 From: Nathaniel Clark Date: Fri, 11 Apr 2014 16:29:07 -0400 Subject: [PATCH] LU-4698 target: check for NULL tgt before deref In the case of and echo server during obdfilter-survey tests a target can be missing from the obd_device. Check for a valid pointer before dereferencing it, return error if it's NULL. Check for valid obt in class_exp2tgt otherwise return NULL target. Add checks for all places that call class_exp2tgt for NULL return value. Signed-off-by: Nathaniel Clark Change-Id: I27a3020dc7ef9943fb600c3ddb6432f7f67f8b39 Reviewed-on: http://review.whamcloud.com/9936 Tested-by: Jenkins Tested-by: Maloo Reviewed-by: Alex Zhuravlev Reviewed-by: Bob Glossman Reviewed-by: Oleg Drokin --- lustre/include/obd_class.h | 2 ++ lustre/target/tgt_handler.c | 30 ++++++++++++++++++++++++++++++ lustre/target/tgt_lastrcvd.c | 20 ++++++++++++++++---- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/lustre/include/obd_class.h b/lustre/include/obd_class.h index 46a6794..bfb5e9e 100644 --- a/lustre/include/obd_class.h +++ b/lustre/include/obd_class.h @@ -305,6 +305,8 @@ static inline enum obd_option exp_flags_from_obd(struct obd_device *obd) static inline struct lu_target *class_exp2tgt(struct obd_export *exp) { LASSERT(exp->exp_obd); + if (exp->exp_obd->u.obt.obt_magic != OBT_MAGIC) + return NULL; return exp->exp_obd->u.obt.obt_lut; } diff --git a/lustre/target/tgt_handler.c b/lustre/target/tgt_handler.c index 93ff6cb..39caceb 100644 --- a/lustre/target/tgt_handler.c +++ b/lustre/target/tgt_handler.c @@ -554,6 +554,11 @@ static struct tgt_handler *tgt_handler_find_check(struct ptlrpc_request *req) ENTRY; tgt = class_exp2tgt(req->rq_export); + if (unlikely(tgt == NULL)) { + DEBUG_REQ(D_ERROR, req, "%s: No target for connected export\n", + class_exp2obd(req->rq_export)->obd_name); + RETURN(ERR_PTR(-EINVAL)); + } for (s = tgt->lut_slice; s->tos_hs != NULL; s++) if (s->tos_opc_start <= opc && opc < s->tos_opc_end) @@ -627,6 +632,14 @@ int tgt_request_handle(struct ptlrpc_request *req) else tsi->tsi_jobid = NULL; + if (tgt == NULL) { + DEBUG_REQ(D_ERROR, req, "%s: No target for connected export\n", + class_exp2obd(req->rq_export)->obd_name); + req->rq_status = -EINVAL; + rc = ptlrpc_error(req); + GOTO(out, rc); + } + request_fail_id = tgt->lut_request_fail_id; tsi->tsi_reply_fail_id = tgt->lut_reply_fail_id; @@ -744,6 +757,12 @@ static int tgt_init_sec_level(struct ptlrpc_request *req) RETURN(0); } + if (unlikely(tgt == NULL)) { + DEBUG_REQ(D_ERROR, req, "%s: No target for connected export\n", + class_exp2obd(req->rq_export)->obd_name); + RETURN(-EINVAL); + } + client = libcfs_nid2str(req->rq_peer.nid); /* no GSS support case */ if (!req->rq_auth_gss) { @@ -884,6 +903,11 @@ int tgt_adapt_sptlrpc_conf(struct lu_target *tgt, int initial) struct sptlrpc_rule_set tmp_rset; int rc; + if (unlikely(tgt == NULL)) { + CERROR("No target passed"); + return -EINVAL; + } + sptlrpc_rule_set_init(&tmp_rset); rc = sptlrpc_conf_target_get_rules(tgt->lut_obd, &tmp_rset, initial); if (rc) { @@ -1148,6 +1172,12 @@ static int tgt_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc, tgt = class_exp2tgt(lock->l_export); + if (unlikely(tgt == NULL)) { + CDEBUG(D_ERROR, "%s: No target for connected export\n", + class_exp2obd(lock->l_export)->obd_name); + RETURN(-EINVAL); + } + if (flag == LDLM_CB_CANCELING && (lock->l_granted_mode & (LCK_PW | LCK_GROUP)) && (tgt->lut_sync_lock_cancel == ALWAYS_SYNC_ON_CANCEL || diff --git a/lustre/target/tgt_lastrcvd.c b/lustre/target/tgt_lastrcvd.c index c31e3f4..bf024bd 100644 --- a/lustre/target/tgt_lastrcvd.c +++ b/lustre/target/tgt_lastrcvd.c @@ -92,7 +92,7 @@ void tgt_client_free(struct obd_export *exp) if (ted->ted_lr_idx < 0) return; /* Clear bit when lcd is freed */ - LASSERT(lut->lut_client_bitmap); + LASSERT(lut && lut->lut_client_bitmap); if (!test_and_clear_bit(ted->ted_lr_idx, lut->lut_client_bitmap)) { CERROR("%s: client %u bit already clear in bitmap\n", exp->exp_obd->obd_name, ted->ted_lr_idx); @@ -157,6 +157,12 @@ static int tgt_client_data_update(const struct lu_env *env, ENTRY; + if (unlikely(tgt == NULL)) { + CDEBUG(D_ERROR, "%s: No target for connected export\n", + class_exp2obd(exp)->obd_name); + RETURN(-EINVAL); + } + th = dt_trans_create(env, tgt->lut_bottom); if (IS_ERR(th)) RETURN(PTR_ERR(th)); @@ -330,7 +336,7 @@ static void tgt_client_epoch_update(const struct lu_env *env, struct lsd_client_data *lcd = exp->exp_target_data.ted_lcd; struct lu_target *tgt = class_exp2tgt(exp); - LASSERT(tgt->lut_bottom); + LASSERT(tgt && tgt->lut_bottom); /** VBR: set client last_epoch to current epoch */ if (lcd->lcd_last_epoch >= tgt->lut_lsd.lsd_start_epoch) return; @@ -534,7 +540,7 @@ int tgt_client_new(const struct lu_env *env, struct obd_export *exp) ENTRY; - LASSERT(tgt->lut_client_bitmap != NULL); + LASSERT(tgt && tgt->lut_client_bitmap != NULL); if (!strcmp(ted->ted_lcd->lcd_uuid, tgt->lut_obd->obd_uuid.uuid)) RETURN(0); @@ -600,7 +606,7 @@ int tgt_client_add(const struct lu_env *env, struct obd_export *exp, int idx) ENTRY; - LASSERT(tgt->lut_client_bitmap != NULL); + LASSERT(tgt && tgt->lut_client_bitmap != NULL); LASSERTF(idx >= 0, "%d\n", idx); if (!strcmp(ted->ted_lcd->lcd_uuid, tgt->lut_obd->obd_uuid.uuid) || @@ -637,6 +643,12 @@ int tgt_client_del(const struct lu_env *env, struct obd_export *exp) LASSERT(ted->ted_lcd); + if (unlikely(tgt == NULL)) { + CDEBUG(D_ERROR, "%s: No target for connected export\n", + class_exp2obd(exp)->obd_name); + RETURN(-EINVAL); + } + /* XXX if lcd_uuid were a real obd_uuid, I could use obd_uuid_equals */ if (!strcmp((char *)ted->ted_lcd->lcd_uuid, (char *)tgt->lut_obd->obd_uuid.uuid) || -- 1.8.3.1