/* * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE.
*/
ret = security_ib_pkey_access(qp_sec->security, subnet_prefix, pkey); if (ret) return ret;
list_for_each_entry(shared_qp_sec,
&qp_sec->shared_qp_list,
shared_qp_list) {
ret = security_ib_pkey_access(shared_qp_sec->security,
subnet_prefix,
pkey); if (ret) return ret;
} return 0;
}
/* The caller of this function must hold the QP security * mutex of the QP of the security structure in *pps. * * It takes separate ports_pkeys and security structure * because in some cases the pps will be for a new settings * or the pps will be for the real QP and security structure * will be for a shared QP.
*/ staticint check_qp_port_pkey_settings(struct ib_ports_pkeys *pps, struct ib_qp_security *sec)
{
u64 subnet_prefix;
u16 pkey; int ret = 0;
if (!pps) return 0;
if (pps->main.state != IB_PORT_PKEY_NOT_VALID) {
ret = get_pkey_and_subnet_prefix(&pps->main,
&pkey,
&subnet_prefix); if (ret) return ret;
ret = enforce_qp_pkey_security(pkey,
subnet_prefix,
sec); if (ret) return ret;
}
if (pps->alt.state != IB_PORT_PKEY_NOT_VALID) {
ret = get_pkey_and_subnet_prefix(&pps->alt,
&pkey,
&subnet_prefix); if (ret) return ret;
ret = enforce_qp_pkey_security(pkey,
subnet_prefix,
sec);
}
return ret;
}
/* The caller of this function must hold the QP security * mutex.
*/ staticvoid qp_to_error(struct ib_qp_security *sec)
{ struct ib_qp_security *shared_qp_sec; struct ib_qp_attr attr = {
.qp_state = IB_QPS_ERR
}; struct ib_event event = {
.event = IB_EVENT_QP_FATAL
};
/* If the QP is in the process of being destroyed * the qp pointer in the security structure is * undefined. It cannot be modified now.
*/ if (sec->destroying) return;
/* The caller of this function must hold the QP security * mutex.
*/ staticint port_pkey_list_insert(struct ib_port_pkey *pp)
{ struct pkey_index_qp_list *tmp_pkey; struct pkey_index_qp_list *pkey; struct ib_device *dev;
u32 port_num = pp->port_num; int ret = 0;
if (pp->state != IB_PORT_PKEY_VALID) return 0;
dev = pp->sec->dev;
pkey = get_pkey_idx_qp_list(pp);
if (!pkey) { bool found = false;
pkey = kzalloc(sizeof(*pkey), GFP_KERNEL); if (!pkey) return -ENOMEM;
spin_lock(&dev->port_data[port_num].pkey_list_lock); /* Check for the PKey again. A racing process may * have created it.
*/
list_for_each_entry(tmp_pkey,
&dev->port_data[port_num].pkey_list,
pkey_index_list) { if (tmp_pkey->pkey_index == pp->pkey_index) {
kfree(pkey);
pkey = tmp_pkey;
found = true; break;
}
}
/* The caller of this function must hold the QP security * mutex.
*/ staticvoid port_pkey_list_remove(struct ib_port_pkey *pp)
{ struct pkey_index_qp_list *pkey;
/* The caller of this function must hold the QP security * mutex.
*/ staticstruct ib_ports_pkeys *get_new_pps(conststruct ib_qp *qp, conststruct ib_qp_attr *qp_attr, int qp_attr_mask)
{ struct ib_ports_pkeys *new_pps; struct ib_ports_pkeys *qp_pps = qp->qp_sec->ports_pkeys;
new_pps = kzalloc(sizeof(*new_pps), GFP_KERNEL); if (!new_pps) return NULL;
void ib_destroy_qp_security_begin(struct ib_qp_security *sec)
{ /* Return if not IB */ if (!sec) return;
mutex_lock(&sec->mutex);
/* Remove the QP from the lists so it won't get added to * a to_error_list during the destroy process.
*/ if (sec->ports_pkeys) {
port_pkey_list_remove(&sec->ports_pkeys->main);
port_pkey_list_remove(&sec->ports_pkeys->alt);
}
/* If the QP is already in one or more of those lists * the destroying flag will ensure the to error flow * doesn't operate on an undefined QP.
*/
sec->destroying = true;
/* Record the error list count to know how many completions * to wait for.
*/
sec->error_comps_pending = atomic_read(&sec->error_list_count);
mutex_unlock(&sec->mutex);
}
void ib_destroy_qp_security_abort(struct ib_qp_security *sec)
{ int ret; int i;
/* Return if not IB */ if (!sec) return;
/* If a concurrent cache update is in progress this * QP security could be marked for an error state * transition. Wait for this to complete.
*/ for (i = 0; i < sec->error_comps_pending; i++)
wait_for_completion(&sec->error_complete);
mutex_lock(&sec->mutex);
sec->destroying = false;
/* Restore the position in the lists and verify * access is still allowed in case a cache update * occurred while attempting to destroy. * * Because these setting were listed already * and removed during ib_destroy_qp_security_begin * we know the pkey_index_qp_list for the PKey * already exists so port_pkey_list_insert won't fail.
*/ if (sec->ports_pkeys) {
port_pkey_list_insert(&sec->ports_pkeys->main);
port_pkey_list_insert(&sec->ports_pkeys->alt);
}
ret = check_qp_port_pkey_settings(sec->ports_pkeys, sec); if (ret)
qp_to_error(sec);
mutex_unlock(&sec->mutex);
}
void ib_destroy_qp_security_end(struct ib_qp_security *sec)
{ int i;
/* Return if not IB */ if (!sec) return;
/* If a concurrent cache update is occurring we must * wait until this QP security structure is processed * in the QP to error flow before destroying it because * the to_error_list is in use.
*/ for (i = 0; i < sec->error_comps_pending; i++)
wait_for_completion(&sec->error_complete);
WARN_ONCE((qp_attr_mask & IB_QP_PORT &&
rdma_protocol_ib(real_qp->device, qp_attr->port_num) &&
!real_qp->qp_sec), "%s: QP security is not initialized for IB QP: %u\n",
__func__, real_qp->qp_num);
/* The port/pkey settings are maintained only for the real QP. Open * handles on the real QP will be in the shared_qp_list. When * enforcing security on the real QP all the shared QPs will be * checked as well.
*/
if (pps_change && !special_qp && real_qp->qp_sec) {
mutex_lock(&real_qp->qp_sec->mutex);
new_pps = get_new_pps(real_qp,
qp_attr,
qp_attr_mask); if (!new_pps) {
mutex_unlock(&real_qp->qp_sec->mutex); return -ENOMEM;
} /* Add this QP to the lists for the new port * and pkey settings before checking for permission * in case there is a concurrent cache update * occurring. Walking the list for a cache change * doesn't acquire the security mutex unless it's * sending the QP to error.
*/
ret = port_pkey_list_insert(&new_pps->main);
if (!ret)
ret = port_pkey_list_insert(&new_pps->alt);
if (!ret)
ret = check_qp_port_pkey_settings(new_pps,
real_qp->qp_sec);
}
if (!ret)
ret = real_qp->device->ops.modify_qp(real_qp,
qp_attr,
qp_attr_mask,
udata);
if (new_pps) { /* Clean up the lists and free the appropriate * ports_pkeys structure.
*/ if (ret) {
tmp_pps = new_pps;
} else {
tmp_pps = real_qp->qp_sec->ports_pkeys;
real_qp->qp_sec->ports_pkeys = new_pps;
}
int ib_mad_agent_security_setup(struct ib_mad_agent *agent, enum ib_qp_type qp_type)
{ int ret;
if (!rdma_protocol_ib(agent->device, agent->port_num)) return 0;
INIT_LIST_HEAD(&agent->mad_agent_sec_list);
ret = security_ib_alloc_security(&agent->security); if (ret) return ret;
if (qp_type != IB_QPT_SMI) return 0;
spin_lock(&mad_agent_list_lock);
ret = security_ib_endport_manage_subnet(agent->security,
dev_name(&agent->device->dev),
agent->port_num); if (ret) goto free_security;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.