Merge git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
Pull SCSI target fixes from Nicholas Bellinger: "Mostly minor fixes this time around. The highlights include: - iscsi-target CHAP authentication fixes to enforce explicit key values (Tejas Vaykole + rahul.rane) - fix a long-standing OOPs in target-core when a alua configfs attribute is accessed after port symlink has been removed. (Sebastian Herbszt) - fix a v3.10.y iscsi-target regression causing the login reject status class/detail to be ignored (Christoph Vu-Brugier) - fix a v3.10.y iscsi-target regression to avoid rejecting an existing ITT during Data-Out when data-direction is wrong (Santosh Kulkarni + Arshad Hussain) - fix a iscsi-target related shutdown deadlock on UP kernels (Mikulas Patocka) - fix a v3.16-rc1 build issue with vhost-scsi + !CONFIG_NET (MST)" * git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: iscsi-target: fix iscsit_del_np deadlock on unload iovec: move memcpy_from/toiovecend to lib/iovec.c iscsi-target: Avoid rejecting incorrect ITT for Data-Out tcm_loop: Fix memory leak in tcm_loop_submission_work error path iscsi-target: Explicily clear login response PDU in exception path target: Fix left-over se_lun->lun_sep pointer OOPs iscsi-target; Enforce 1024 byte maximum for CHAP_C key value iscsi-target: Convert chap_server_compute_md5 to use kstrtoul
This commit is contained in:
commit
eb477e03fe
10 changed files with 82 additions and 70 deletions
|
@ -1309,7 +1309,7 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,
|
|||
if (cmd->data_direction != DMA_TO_DEVICE) {
|
||||
pr_err("Command ITT: 0x%08x received DataOUT for a"
|
||||
" NON-WRITE command.\n", cmd->init_task_tag);
|
||||
return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf);
|
||||
return iscsit_dump_data_payload(conn, payload_length, 1);
|
||||
}
|
||||
se_cmd = &cmd->se_cmd;
|
||||
iscsit_mod_dataout_timer(cmd);
|
||||
|
|
|
@ -174,7 +174,6 @@ static int chap_server_compute_md5(
|
|||
char *nr_out_ptr,
|
||||
unsigned int *nr_out_len)
|
||||
{
|
||||
char *endptr;
|
||||
unsigned long id;
|
||||
unsigned char id_as_uchar;
|
||||
unsigned char digest[MD5_SIGNATURE_SIZE];
|
||||
|
@ -320,9 +319,14 @@ static int chap_server_compute_md5(
|
|||
}
|
||||
|
||||
if (type == HEX)
|
||||
id = simple_strtoul(&identifier[2], &endptr, 0);
|
||||
ret = kstrtoul(&identifier[2], 0, &id);
|
||||
else
|
||||
id = simple_strtoul(identifier, &endptr, 0);
|
||||
ret = kstrtoul(identifier, 0, &id);
|
||||
|
||||
if (ret < 0) {
|
||||
pr_err("kstrtoul() failed for CHAP identifier: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
if (id > 255) {
|
||||
pr_err("chap identifier: %lu greater than 255\n", id);
|
||||
goto out;
|
||||
|
@ -351,6 +355,10 @@ static int chap_server_compute_md5(
|
|||
pr_err("Unable to convert incoming challenge\n");
|
||||
goto out;
|
||||
}
|
||||
if (challenge_len > 1024) {
|
||||
pr_err("CHAP_C exceeds maximum binary size of 1024 bytes\n");
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* During mutual authentication, the CHAP_C generated by the
|
||||
* initiator must not match the original CHAP_C generated by
|
||||
|
|
|
@ -1216,7 +1216,7 @@ void iscsi_target_login_sess_out(struct iscsi_conn *conn,
|
|||
static int __iscsi_target_login_thread(struct iscsi_np *np)
|
||||
{
|
||||
u8 *buffer, zero_tsih = 0;
|
||||
int ret = 0, rc, stop;
|
||||
int ret = 0, rc;
|
||||
struct iscsi_conn *conn = NULL;
|
||||
struct iscsi_login *login;
|
||||
struct iscsi_portal_group *tpg = NULL;
|
||||
|
@ -1230,6 +1230,9 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
|
|||
if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
|
||||
np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
|
||||
complete(&np->np_restart_comp);
|
||||
} else if (np->np_thread_state == ISCSI_NP_THREAD_SHUTDOWN) {
|
||||
spin_unlock_bh(&np->np_thread_lock);
|
||||
goto exit;
|
||||
} else {
|
||||
np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
|
||||
}
|
||||
|
@ -1422,10 +1425,8 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
|
|||
}
|
||||
|
||||
out:
|
||||
stop = kthread_should_stop();
|
||||
/* Wait for another socket.. */
|
||||
if (!stop)
|
||||
return 1;
|
||||
return 1;
|
||||
|
||||
exit:
|
||||
iscsi_stop_login_thread_timer(np);
|
||||
spin_lock_bh(&np->np_thread_lock);
|
||||
|
@ -1442,7 +1443,7 @@ int iscsi_target_login_thread(void *arg)
|
|||
|
||||
allow_signal(SIGINT);
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
while (1) {
|
||||
ret = __iscsi_target_login_thread(np);
|
||||
/*
|
||||
* We break and exit here unless another sock_accept() call
|
||||
|
|
|
@ -1295,6 +1295,8 @@ int iscsit_tx_login_rsp(struct iscsi_conn *conn, u8 status_class, u8 status_deta
|
|||
login->login_failed = 1;
|
||||
iscsit_collect_login_stats(conn, status_class, status_detail);
|
||||
|
||||
memset(&login->rsp[0], 0, ISCSI_HDR_LEN);
|
||||
|
||||
hdr = (struct iscsi_login_rsp *)&login->rsp[0];
|
||||
hdr->opcode = ISCSI_OP_LOGIN_RSP;
|
||||
hdr->status_class = status_class;
|
||||
|
|
|
@ -239,6 +239,7 @@ static void tcm_loop_submission_work(struct work_struct *work)
|
|||
return;
|
||||
|
||||
out_done:
|
||||
kmem_cache_free(tcm_loop_cmd_cache, tl_cmd);
|
||||
sc->scsi_done(sc);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -616,6 +616,7 @@ void core_dev_unexport(
|
|||
dev->export_count--;
|
||||
spin_unlock(&hba->device_lock);
|
||||
|
||||
lun->lun_sep = NULL;
|
||||
lun->lun_se_dev = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -305,8 +305,6 @@ struct ucred {
|
|||
/* IPX options */
|
||||
#define IPX_TYPE 1
|
||||
|
||||
extern int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov,
|
||||
int offset, int len);
|
||||
extern int csum_partial_copy_fromiovecend(unsigned char *kdata,
|
||||
struct iovec *iov,
|
||||
int offset,
|
||||
|
@ -315,8 +313,6 @@ extern unsigned long iov_pages(const struct iovec *iov, int offset,
|
|||
unsigned long nr_segs);
|
||||
|
||||
extern int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *address, int mode);
|
||||
extern int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata,
|
||||
int offset, int len);
|
||||
extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr);
|
||||
extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);
|
||||
|
||||
|
|
|
@ -123,6 +123,9 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)
|
|||
|
||||
int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len);
|
||||
int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len);
|
||||
|
||||
int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov,
|
||||
int offset, int len);
|
||||
int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata,
|
||||
int offset, int len);
|
||||
|
||||
#endif
|
||||
|
|
55
lib/iovec.c
55
lib/iovec.c
|
@ -51,3 +51,58 @@ int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len)
|
|||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(memcpy_toiovec);
|
||||
|
||||
/*
|
||||
* Copy kernel to iovec. Returns -EFAULT on error.
|
||||
*/
|
||||
|
||||
int memcpy_toiovecend(const struct iovec *iov, unsigned char *kdata,
|
||||
int offset, int len)
|
||||
{
|
||||
int copy;
|
||||
for (; len > 0; ++iov) {
|
||||
/* Skip over the finished iovecs */
|
||||
if (unlikely(offset >= iov->iov_len)) {
|
||||
offset -= iov->iov_len;
|
||||
continue;
|
||||
}
|
||||
copy = min_t(unsigned int, iov->iov_len - offset, len);
|
||||
if (copy_to_user(iov->iov_base + offset, kdata, copy))
|
||||
return -EFAULT;
|
||||
offset = 0;
|
||||
kdata += copy;
|
||||
len -= copy;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(memcpy_toiovecend);
|
||||
|
||||
/*
|
||||
* Copy iovec to kernel. Returns -EFAULT on error.
|
||||
*/
|
||||
|
||||
int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov,
|
||||
int offset, int len)
|
||||
{
|
||||
/* Skip over the finished iovecs */
|
||||
while (offset >= iov->iov_len) {
|
||||
offset -= iov->iov_len;
|
||||
iov++;
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
u8 __user *base = iov->iov_base + offset;
|
||||
int copy = min_t(unsigned int, len, iov->iov_len - offset);
|
||||
|
||||
offset = 0;
|
||||
if (copy_from_user(kdata, base, copy))
|
||||
return -EFAULT;
|
||||
len -= copy;
|
||||
kdata += copy;
|
||||
iov++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(memcpy_fromiovecend);
|
||||
|
|
|
@ -74,61 +74,6 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *a
|
|||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy kernel to iovec. Returns -EFAULT on error.
|
||||
*/
|
||||
|
||||
int memcpy_toiovecend(const struct iovec *iov, unsigned char *kdata,
|
||||
int offset, int len)
|
||||
{
|
||||
int copy;
|
||||
for (; len > 0; ++iov) {
|
||||
/* Skip over the finished iovecs */
|
||||
if (unlikely(offset >= iov->iov_len)) {
|
||||
offset -= iov->iov_len;
|
||||
continue;
|
||||
}
|
||||
copy = min_t(unsigned int, iov->iov_len - offset, len);
|
||||
if (copy_to_user(iov->iov_base + offset, kdata, copy))
|
||||
return -EFAULT;
|
||||
offset = 0;
|
||||
kdata += copy;
|
||||
len -= copy;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(memcpy_toiovecend);
|
||||
|
||||
/*
|
||||
* Copy iovec to kernel. Returns -EFAULT on error.
|
||||
*/
|
||||
|
||||
int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov,
|
||||
int offset, int len)
|
||||
{
|
||||
/* Skip over the finished iovecs */
|
||||
while (offset >= iov->iov_len) {
|
||||
offset -= iov->iov_len;
|
||||
iov++;
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
u8 __user *base = iov->iov_base + offset;
|
||||
int copy = min_t(unsigned int, len, iov->iov_len - offset);
|
||||
|
||||
offset = 0;
|
||||
if (copy_from_user(kdata, base, copy))
|
||||
return -EFAULT;
|
||||
len -= copy;
|
||||
kdata += copy;
|
||||
iov++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(memcpy_fromiovecend);
|
||||
|
||||
/*
|
||||
* And now for the all-in-one: copy and checksum from a user iovec
|
||||
* directly to a datagram
|
||||
|
|
Loading…
Reference in a new issue