mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-25 16:50:52 -04:00
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma
Pull rdma fixes from Jason Gunthorpe:
"Several significant bug fixes of pre-existing issues:
- Missing validation on ucap fd types passed from userspace
- Missing validation of HW DMA space vs userpace expected sizes in
EFA queue setup
- DMA corruption when using DMA block sizes >= 4G when setting up MRs
in all drivers
- Missing validation of CPU IDs when setting up dma handles
- Missing validation of IB_MR_REREG_ACCESS when changing writability
of a MR
- Missing validation of received message/packet size in ISER and SRP"
* tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma:
RDMA/srp: bound SRP_RSP sense copy by the received length
IB/isert: Reject login PDUs shorter than ISER_HEADERS_LEN
RDMA: During rereg_mr ensure that REREG_ACCESS is compatible
RDMA/core: Validate cpu_id against nr_cpu_ids in DMAH alloc
RDMA/umem: Fix truncation for block sizes >= 4G
RDMA/efa: Validate SQ ring size against max LLQ size
RDMA/core: Validate the passed in fops for ib_get_ucaps()
This commit is contained in:
@@ -19,8 +19,8 @@ EXPORT_SYMBOL(__rdma_block_iter_start);
|
||||
|
||||
bool __rdma_block_iter_next(struct ib_block_iter *biter)
|
||||
{
|
||||
unsigned int block_offset;
|
||||
unsigned int delta;
|
||||
dma_addr_t block_offset;
|
||||
dma_addr_t delta;
|
||||
|
||||
if (!biter->__sg_nents || !biter->__sg)
|
||||
return false;
|
||||
|
||||
@@ -82,14 +82,12 @@ static int get_ucap_from_devt(dev_t devt, u64 *idx_mask)
|
||||
|
||||
static int get_devt_from_fd(unsigned int fd, dev_t *ret_dev)
|
||||
{
|
||||
struct file *file;
|
||||
CLASS(fd, f)(fd);
|
||||
|
||||
file = fget(fd);
|
||||
if (!file)
|
||||
if (fd_empty(f) || fd_file(f)->f_op != &ucaps_cdev_fops)
|
||||
return -EBADF;
|
||||
|
||||
*ret_dev = file_inode(file)->i_rdev;
|
||||
fput(file);
|
||||
*ret_dev = file_inode(fd_file(f))->i_rdev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -332,3 +332,19 @@ int ib_umem_copy_from(void *dst, struct ib_umem *umem, size_t offset,
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ib_umem_copy_from);
|
||||
|
||||
/*
|
||||
* Called during rereg mr if the driver is able to re-use a umem for
|
||||
* IB_MR_REREG_ACCESS.
|
||||
*/
|
||||
int ib_umem_check_rereg(struct ib_umem *umem, int flags, int new_access_flags)
|
||||
{
|
||||
if (!umem)
|
||||
return 0;
|
||||
|
||||
if ((flags & IB_MR_REREG_ACCESS) && !(flags & IB_MR_REREG_TRANS))
|
||||
if (ib_access_writable(new_access_flags) && !umem->writable)
|
||||
return -EACCES;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ib_umem_check_rereg);
|
||||
|
||||
@@ -47,6 +47,11 @@ static int UVERBS_HANDLER(UVERBS_METHOD_DMAH_ALLOC)(
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
if (dmah->cpu_id >= nr_cpu_ids) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!cpumask_test_cpu(dmah->cpu_id, current->cpus_ptr)) {
|
||||
ret = -EPERM;
|
||||
goto err;
|
||||
|
||||
@@ -613,7 +613,8 @@ static int qp_mmap_entries_setup(struct efa_qp *qp,
|
||||
}
|
||||
|
||||
static int efa_qp_validate_cap(struct efa_dev *dev,
|
||||
struct ib_qp_init_attr *init_attr)
|
||||
struct ib_qp_init_attr *init_attr,
|
||||
u32 sq_ring_size)
|
||||
{
|
||||
if (init_attr->cap.max_send_wr > dev->dev_attr.max_sq_depth) {
|
||||
ibdev_dbg(&dev->ibdev,
|
||||
@@ -622,6 +623,14 @@ static int efa_qp_validate_cap(struct efa_dev *dev,
|
||||
dev->dev_attr.max_sq_depth);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sq_ring_size > dev->dev_attr.max_llq_size) {
|
||||
ibdev_dbg(&dev->ibdev,
|
||||
"qp: requested sq ring size[%u] exceeds the max[%u]\n",
|
||||
sq_ring_size, dev->dev_attr.max_llq_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (init_attr->cap.max_recv_wr > dev->dev_attr.max_rq_depth) {
|
||||
ibdev_dbg(&dev->ibdev,
|
||||
"qp: requested receive wr[%u] exceeds the max[%u]\n",
|
||||
@@ -691,14 +700,6 @@ int efa_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *init_attr,
|
||||
ucontext = rdma_udata_to_drv_context(udata, struct efa_ucontext,
|
||||
ibucontext);
|
||||
|
||||
err = efa_qp_validate_cap(dev, init_attr);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
err = efa_qp_validate_attr(dev, init_attr);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
err = ib_copy_validate_udata_in_cm(udata, cmd, driver_qp_type, 0);
|
||||
if (err)
|
||||
goto err_out;
|
||||
@@ -720,6 +721,14 @@ int efa_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *init_attr,
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
err = efa_qp_validate_cap(dev, init_attr, cmd.sq_ring_size);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
err = efa_qp_validate_attr(dev, init_attr);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
create_qp_params.uarn = ucontext->uarn;
|
||||
create_qp_params.pd = to_epd(ibqp->pd)->pdn;
|
||||
|
||||
|
||||
@@ -300,6 +300,10 @@ struct ib_mr *hns_roce_rereg_user_mr(struct ib_mr *ibmr, int flags, u64 start,
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
ret = ib_umem_check_rereg(mr->pbl_mtr.umem, flags, mr_access_flags);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
mailbox = hns_roce_alloc_cmd_mailbox(hr_dev);
|
||||
ret = PTR_ERR_OR_ZERO(mailbox);
|
||||
if (ret)
|
||||
|
||||
@@ -3803,6 +3803,10 @@ static struct ib_mr *irdma_rereg_user_mr(struct ib_mr *ib_mr, int flags,
|
||||
if (flags & ~(IB_MR_REREG_TRANS | IB_MR_REREG_PD | IB_MR_REREG_ACCESS))
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
|
||||
ret = ib_umem_check_rereg(iwmr->region, flags, new_access);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
if (dmabuf_revocable) {
|
||||
umem_dmabuf = to_ib_umem_dmabuf(iwmr->region);
|
||||
|
||||
|
||||
@@ -209,6 +209,10 @@ struct ib_mr *mlx4_ib_rereg_user_mr(struct ib_mr *mr, int flags, u64 start,
|
||||
struct mlx4_mpt_entry **pmpt_entry = &mpt_entry;
|
||||
int err;
|
||||
|
||||
err = ib_umem_check_rereg(mmr->umem, flags, mr_access_flags);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
/* Since we synchronize this call and mlx4_ib_dereg_mr via uverbs,
|
||||
* we assume that the calls can't run concurrently. Otherwise, a
|
||||
* race exists.
|
||||
|
||||
@@ -1179,6 +1179,10 @@ struct ib_mr *mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start,
|
||||
if (flags & ~(IB_MR_REREG_TRANS | IB_MR_REREG_PD | IB_MR_REREG_ACCESS))
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
|
||||
err = ib_umem_check_rereg(mr->umem, flags, new_access_flags);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
if (!(flags & IB_MR_REREG_ACCESS))
|
||||
new_access_flags = mr->access_flags;
|
||||
if (!(flags & IB_MR_REREG_PD))
|
||||
|
||||
@@ -1319,6 +1319,7 @@ static struct ib_mr *rxe_rereg_user_mr(struct ib_mr *ibmr, int flags,
|
||||
struct rxe_mr *mr = to_rmr(ibmr);
|
||||
struct rxe_pd *old_pd = to_rpd(ibmr->pd);
|
||||
struct rxe_pd *pd = to_rpd(ibpd);
|
||||
int err;
|
||||
|
||||
/* for now only support the two easy cases:
|
||||
* rereg_pd and rereg_access
|
||||
@@ -1328,6 +1329,10 @@ static struct ib_mr *rxe_rereg_user_mr(struct ib_mr *ibmr, int flags,
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
err = ib_umem_check_rereg(mr->umem, flags, access);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
if (flags & IB_MR_REREG_PD) {
|
||||
rxe_put(old_pd);
|
||||
rxe_get(pd);
|
||||
|
||||
@@ -1383,6 +1383,12 @@ isert_login_recv_done(struct ib_cq *cq, struct ib_wc *wc)
|
||||
ib_dma_sync_single_for_cpu(ib_dev, isert_conn->login_desc->dma_addr,
|
||||
ISER_RX_SIZE, DMA_FROM_DEVICE);
|
||||
|
||||
if (unlikely(wc->byte_len < ISER_HEADERS_LEN)) {
|
||||
isert_dbg("login request length %u is too short\n",
|
||||
wc->byte_len);
|
||||
return;
|
||||
}
|
||||
|
||||
isert_conn->login_req_len = wc->byte_len - ISER_HEADERS_LEN;
|
||||
|
||||
if (isert_conn->conn) {
|
||||
|
||||
@@ -1932,7 +1932,8 @@ static int srp_post_recv(struct srp_rdma_ch *ch, struct srp_iu *iu)
|
||||
return ib_post_recv(ch->qp, &wr, NULL);
|
||||
}
|
||||
|
||||
static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp)
|
||||
static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp,
|
||||
u32 byte_len)
|
||||
{
|
||||
struct srp_target_port *target = ch->target;
|
||||
struct srp_request *req;
|
||||
@@ -1973,10 +1974,27 @@ static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp)
|
||||
scmnd->result = rsp->status;
|
||||
|
||||
if (rsp->flags & SRP_RSP_FLAG_SNSVALID) {
|
||||
memcpy(scmnd->sense_buffer, rsp->data +
|
||||
be32_to_cpu(rsp->resp_data_len),
|
||||
min_t(int, be32_to_cpu(rsp->sense_data_len),
|
||||
SCSI_SENSE_BUFFERSIZE));
|
||||
u32 resp_len = be32_to_cpu(rsp->resp_data_len);
|
||||
u32 sense_len = be32_to_cpu(rsp->sense_data_len);
|
||||
|
||||
/*
|
||||
* The sense data starts resp_data_len bytes past the
|
||||
* response data area; both lengths come from the
|
||||
* target-controlled response. Copy the sense data
|
||||
* only if it has not been truncated, that is, only if
|
||||
* the full sense region fits within the bytes actually
|
||||
* received. Otherwise the copy source would run past
|
||||
* the receive buffer (sized to the target-chosen
|
||||
* max_ti_iu_len), reading out of bounds.
|
||||
*/
|
||||
if (sizeof(*rsp) + (u64)resp_len + sense_len <= byte_len)
|
||||
memcpy(scmnd->sense_buffer,
|
||||
rsp->data + resp_len,
|
||||
min(sense_len, SCSI_SENSE_BUFFERSIZE));
|
||||
else
|
||||
shost_printk(KERN_ERR, target->scsi_host,
|
||||
"dropping truncated sense data (resp_data_len %u sense_data_len %u, %u bytes received)\n",
|
||||
resp_len, sense_len, byte_len);
|
||||
}
|
||||
|
||||
if (unlikely(rsp->flags & SRP_RSP_FLAG_DIUNDER))
|
||||
@@ -2086,7 +2104,7 @@ static void srp_recv_done(struct ib_cq *cq, struct ib_wc *wc)
|
||||
|
||||
switch (opcode) {
|
||||
case SRP_RSP:
|
||||
srp_process_rsp(ch, iu->buf);
|
||||
srp_process_rsp(ch, iu->buf, wc->byte_len);
|
||||
break;
|
||||
|
||||
case SRP_CRED_REQ:
|
||||
|
||||
@@ -156,6 +156,8 @@ void ib_umem_dmabuf_revoke_lock(struct ib_umem_dmabuf *umem_dmabuf);
|
||||
void ib_umem_dmabuf_revoke_unlock(struct ib_umem_dmabuf *umem_dmabuf);
|
||||
void ib_umem_dmabuf_revoke(struct ib_umem_dmabuf *umem_dmabuf);
|
||||
|
||||
int ib_umem_check_rereg(struct ib_umem *umem, int flags, int new_access_flags);
|
||||
|
||||
#else /* CONFIG_INFINIBAND_USER_MEM */
|
||||
|
||||
#include <linux/err.h>
|
||||
@@ -230,5 +232,11 @@ static inline void ib_umem_dmabuf_revoke_lock(struct ib_umem_dmabuf *umem_dmabuf
|
||||
static inline void ib_umem_dmabuf_revoke_unlock(struct ib_umem_dmabuf *umem_dmabuf) {}
|
||||
static inline void ib_umem_dmabuf_revoke(struct ib_umem_dmabuf *umem_dmabuf) {}
|
||||
|
||||
static inline int ib_umem_check_rereg(struct ib_umem *umem, int flags,
|
||||
int new_access_flags)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_INFINIBAND_USER_MEM */
|
||||
#endif /* IB_UMEM_H */
|
||||
|
||||
Reference in New Issue
Block a user