Commit eb477e03 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 3e7b256c 81a9c5e7
...@@ -1309,7 +1309,7 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf, ...@@ -1309,7 +1309,7 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,
if (cmd->data_direction != DMA_TO_DEVICE) { if (cmd->data_direction != DMA_TO_DEVICE) {
pr_err("Command ITT: 0x%08x received DataOUT for a" pr_err("Command ITT: 0x%08x received DataOUT for a"
" NON-WRITE command.\n", cmd->init_task_tag); " 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; se_cmd = &cmd->se_cmd;
iscsit_mod_dataout_timer(cmd); iscsit_mod_dataout_timer(cmd);
......
...@@ -174,7 +174,6 @@ static int chap_server_compute_md5( ...@@ -174,7 +174,6 @@ static int chap_server_compute_md5(
char *nr_out_ptr, char *nr_out_ptr,
unsigned int *nr_out_len) unsigned int *nr_out_len)
{ {
char *endptr;
unsigned long id; unsigned long id;
unsigned char id_as_uchar; unsigned char id_as_uchar;
unsigned char digest[MD5_SIGNATURE_SIZE]; unsigned char digest[MD5_SIGNATURE_SIZE];
...@@ -320,9 +319,14 @@ static int chap_server_compute_md5( ...@@ -320,9 +319,14 @@ static int chap_server_compute_md5(
} }
if (type == HEX) if (type == HEX)
id = simple_strtoul(&identifier[2], &endptr, 0); ret = kstrtoul(&identifier[2], 0, &id);
else 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) { if (id > 255) {
pr_err("chap identifier: %lu greater than 255\n", id); pr_err("chap identifier: %lu greater than 255\n", id);
goto out; goto out;
...@@ -351,6 +355,10 @@ static int chap_server_compute_md5( ...@@ -351,6 +355,10 @@ static int chap_server_compute_md5(
pr_err("Unable to convert incoming challenge\n"); pr_err("Unable to convert incoming challenge\n");
goto out; 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 * During mutual authentication, the CHAP_C generated by the
* initiator must not match the original CHAP_C generated by * initiator must not match the original CHAP_C generated by
......
...@@ -1216,7 +1216,7 @@ void iscsi_target_login_sess_out(struct iscsi_conn *conn, ...@@ -1216,7 +1216,7 @@ void iscsi_target_login_sess_out(struct iscsi_conn *conn,
static int __iscsi_target_login_thread(struct iscsi_np *np) static int __iscsi_target_login_thread(struct iscsi_np *np)
{ {
u8 *buffer, zero_tsih = 0; u8 *buffer, zero_tsih = 0;
int ret = 0, rc, stop; int ret = 0, rc;
struct iscsi_conn *conn = NULL; struct iscsi_conn *conn = NULL;
struct iscsi_login *login; struct iscsi_login *login;
struct iscsi_portal_group *tpg = NULL; struct iscsi_portal_group *tpg = NULL;
...@@ -1230,6 +1230,9 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) ...@@ -1230,6 +1230,9 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
if (np->np_thread_state == ISCSI_NP_THREAD_RESET) { if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
np->np_thread_state = ISCSI_NP_THREAD_ACTIVE; np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
complete(&np->np_restart_comp); 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 { } else {
np->np_thread_state = ISCSI_NP_THREAD_ACTIVE; np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
} }
...@@ -1422,10 +1425,8 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) ...@@ -1422,10 +1425,8 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
} }
out: out:
stop = kthread_should_stop(); return 1;
/* Wait for another socket.. */
if (!stop)
return 1;
exit: exit:
iscsi_stop_login_thread_timer(np); iscsi_stop_login_thread_timer(np);
spin_lock_bh(&np->np_thread_lock); spin_lock_bh(&np->np_thread_lock);
...@@ -1442,7 +1443,7 @@ int iscsi_target_login_thread(void *arg) ...@@ -1442,7 +1443,7 @@ int iscsi_target_login_thread(void *arg)
allow_signal(SIGINT); allow_signal(SIGINT);
while (!kthread_should_stop()) { while (1) {
ret = __iscsi_target_login_thread(np); ret = __iscsi_target_login_thread(np);
/* /*
* We break and exit here unless another sock_accept() call * 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 ...@@ -1295,6 +1295,8 @@ int iscsit_tx_login_rsp(struct iscsi_conn *conn, u8 status_class, u8 status_deta
login->login_failed = 1; login->login_failed = 1;
iscsit_collect_login_stats(conn, status_class, status_detail); 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 = (struct iscsi_login_rsp *)&login->rsp[0];
hdr->opcode = ISCSI_OP_LOGIN_RSP; hdr->opcode = ISCSI_OP_LOGIN_RSP;
hdr->status_class = status_class; hdr->status_class = status_class;
......
...@@ -239,6 +239,7 @@ static void tcm_loop_submission_work(struct work_struct *work) ...@@ -239,6 +239,7 @@ static void tcm_loop_submission_work(struct work_struct *work)
return; return;
out_done: out_done:
kmem_cache_free(tcm_loop_cmd_cache, tl_cmd);
sc->scsi_done(sc); sc->scsi_done(sc);
return; return;
} }
......
...@@ -616,6 +616,7 @@ void core_dev_unexport( ...@@ -616,6 +616,7 @@ void core_dev_unexport(
dev->export_count--; dev->export_count--;
spin_unlock(&hba->device_lock); spin_unlock(&hba->device_lock);
lun->lun_sep = NULL;
lun->lun_se_dev = NULL; lun->lun_se_dev = NULL;
} }
......
...@@ -305,8 +305,6 @@ struct ucred { ...@@ -305,8 +305,6 @@ struct ucred {
/* IPX options */ /* IPX options */
#define IPX_TYPE 1 #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, extern int csum_partial_copy_fromiovecend(unsigned char *kdata,
struct iovec *iov, struct iovec *iov,
int offset, int offset,
...@@ -315,8 +313,6 @@ extern unsigned long iov_pages(const struct iovec *iov, int offset, ...@@ -315,8 +313,6 @@ extern unsigned long iov_pages(const struct iovec *iov, int offset,
unsigned long nr_segs); unsigned long nr_segs);
extern int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *address, int mode); 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 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); 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) ...@@ -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_fromiovec(unsigned char *kdata, struct iovec *iov, int len);
int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, 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 #endif
...@@ -51,3 +51,58 @@ int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len) ...@@ -51,3 +51,58 @@ int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len)
return 0; return 0;
} }
EXPORT_SYMBOL(memcpy_toiovec); 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 ...@@ -74,61 +74,6 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *a
return err; 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 * And now for the all-in-one: copy and checksum from a user iovec
* directly to a datagram * directly to a datagram
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment