.. | .. |
---|
1674 | 1674 | return name; |
---|
1675 | 1675 | } |
---|
1676 | 1676 | |
---|
| 1677 | +static char *iscsi_session_target_state_name[] = { |
---|
| 1678 | + [ISCSI_SESSION_TARGET_UNBOUND] = "UNBOUND", |
---|
| 1679 | + [ISCSI_SESSION_TARGET_ALLOCATED] = "ALLOCATED", |
---|
| 1680 | + [ISCSI_SESSION_TARGET_SCANNED] = "SCANNED", |
---|
| 1681 | + [ISCSI_SESSION_TARGET_UNBINDING] = "UNBINDING", |
---|
| 1682 | +}; |
---|
| 1683 | + |
---|
1677 | 1684 | int iscsi_session_chkready(struct iscsi_cls_session *session) |
---|
1678 | 1685 | { |
---|
1679 | 1686 | unsigned long flags; |
---|
.. | .. |
---|
1805 | 1812 | if ((scan_data->channel == SCAN_WILD_CARD || |
---|
1806 | 1813 | scan_data->channel == 0) && |
---|
1807 | 1814 | (scan_data->id == SCAN_WILD_CARD || |
---|
1808 | | - scan_data->id == id)) |
---|
| 1815 | + scan_data->id == id)) { |
---|
1809 | 1816 | scsi_scan_target(&session->dev, 0, id, |
---|
1810 | 1817 | scan_data->lun, scan_data->rescan); |
---|
| 1818 | + spin_lock_irqsave(&session->lock, flags); |
---|
| 1819 | + session->target_state = ISCSI_SESSION_TARGET_SCANNED; |
---|
| 1820 | + spin_unlock_irqrestore(&session->lock, flags); |
---|
| 1821 | + } |
---|
1811 | 1822 | } |
---|
1812 | 1823 | |
---|
1813 | 1824 | user_scan_exit: |
---|
.. | .. |
---|
1996 | 2007 | struct iscsi_cls_host *ihost = shost->shost_data; |
---|
1997 | 2008 | unsigned long flags; |
---|
1998 | 2009 | unsigned int target_id; |
---|
| 2010 | + bool remove_target = true; |
---|
1999 | 2011 | |
---|
2000 | 2012 | ISCSI_DBG_TRANS_SESSION(session, "Unbinding session\n"); |
---|
2001 | 2013 | |
---|
2002 | 2014 | /* Prevent new scans and make sure scanning is not in progress */ |
---|
2003 | 2015 | mutex_lock(&ihost->mutex); |
---|
2004 | 2016 | spin_lock_irqsave(&session->lock, flags); |
---|
2005 | | - if (session->target_id == ISCSI_MAX_TARGET) { |
---|
| 2017 | + if (session->target_state == ISCSI_SESSION_TARGET_ALLOCATED) { |
---|
| 2018 | + remove_target = false; |
---|
| 2019 | + } else if (session->target_state != ISCSI_SESSION_TARGET_SCANNED) { |
---|
2006 | 2020 | spin_unlock_irqrestore(&session->lock, flags); |
---|
2007 | 2021 | mutex_unlock(&ihost->mutex); |
---|
2008 | | - goto unbind_session_exit; |
---|
| 2022 | + ISCSI_DBG_TRANS_SESSION(session, |
---|
| 2023 | + "Skipping target unbinding: Session is unbound/unbinding.\n"); |
---|
| 2024 | + return; |
---|
2009 | 2025 | } |
---|
2010 | 2026 | |
---|
| 2027 | + session->target_state = ISCSI_SESSION_TARGET_UNBINDING; |
---|
2011 | 2028 | target_id = session->target_id; |
---|
2012 | 2029 | session->target_id = ISCSI_MAX_TARGET; |
---|
2013 | 2030 | spin_unlock_irqrestore(&session->lock, flags); |
---|
2014 | 2031 | mutex_unlock(&ihost->mutex); |
---|
2015 | 2032 | |
---|
2016 | | - scsi_remove_target(&session->dev); |
---|
| 2033 | + if (remove_target) |
---|
| 2034 | + scsi_remove_target(&session->dev); |
---|
2017 | 2035 | |
---|
2018 | 2036 | if (session->ida_used) |
---|
2019 | 2037 | ida_simple_remove(&iscsi_sess_ida, target_id); |
---|
2020 | 2038 | |
---|
2021 | | -unbind_session_exit: |
---|
2022 | 2039 | iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION); |
---|
2023 | 2040 | ISCSI_DBG_TRANS_SESSION(session, "Completed target removal\n"); |
---|
| 2041 | + |
---|
| 2042 | + spin_lock_irqsave(&session->lock, flags); |
---|
| 2043 | + session->target_state = ISCSI_SESSION_TARGET_UNBOUND; |
---|
| 2044 | + spin_unlock_irqrestore(&session->lock, flags); |
---|
2024 | 2045 | } |
---|
2025 | 2046 | |
---|
2026 | 2047 | static void __iscsi_destroy_session(struct work_struct *work) |
---|
.. | .. |
---|
2089 | 2110 | session->ida_used = true; |
---|
2090 | 2111 | } else |
---|
2091 | 2112 | session->target_id = target_id; |
---|
| 2113 | + spin_lock_irqsave(&session->lock, flags); |
---|
| 2114 | + session->target_state = ISCSI_SESSION_TARGET_ALLOCATED; |
---|
| 2115 | + spin_unlock_irqrestore(&session->lock, flags); |
---|
2092 | 2116 | |
---|
2093 | 2117 | dev_set_name(&session->dev, "session%u", session->sid); |
---|
2094 | 2118 | err = device_add(&session->dev); |
---|
.. | .. |
---|
2967 | 2991 | } |
---|
2968 | 2992 | |
---|
2969 | 2993 | static int |
---|
2970 | | -iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) |
---|
| 2994 | +iscsi_if_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev, u32 rlen) |
---|
2971 | 2995 | { |
---|
2972 | 2996 | char *data = (char*)ev + sizeof(*ev); |
---|
2973 | 2997 | struct iscsi_cls_conn *conn; |
---|
2974 | 2998 | struct iscsi_cls_session *session; |
---|
2975 | 2999 | int err = 0, value = 0, state; |
---|
2976 | 3000 | |
---|
2977 | | - if (ev->u.set_param.len > PAGE_SIZE) |
---|
| 3001 | + if (ev->u.set_param.len > rlen || |
---|
| 3002 | + ev->u.set_param.len > PAGE_SIZE) |
---|
2978 | 3003 | return -EINVAL; |
---|
2979 | 3004 | |
---|
2980 | 3005 | session = iscsi_session_lookup(ev->u.set_param.sid); |
---|
2981 | 3006 | conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid); |
---|
2982 | 3007 | if (!conn || !session) |
---|
| 3008 | + return -EINVAL; |
---|
| 3009 | + |
---|
| 3010 | + /* data will be regarded as NULL-ended string, do length check */ |
---|
| 3011 | + if (strlen(data) > ev->u.set_param.len) |
---|
2983 | 3012 | return -EINVAL; |
---|
2984 | 3013 | |
---|
2985 | 3014 | switch (ev->u.set_param.param) { |
---|
.. | .. |
---|
3071 | 3100 | |
---|
3072 | 3101 | static int |
---|
3073 | 3102 | iscsi_if_transport_ep(struct iscsi_transport *transport, |
---|
3074 | | - struct iscsi_uevent *ev, int msg_type) |
---|
| 3103 | + struct iscsi_uevent *ev, int msg_type, u32 rlen) |
---|
3075 | 3104 | { |
---|
3076 | 3105 | struct iscsi_endpoint *ep; |
---|
3077 | 3106 | int rc = 0; |
---|
.. | .. |
---|
3079 | 3108 | switch (msg_type) { |
---|
3080 | 3109 | case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST: |
---|
3081 | 3110 | case ISCSI_UEVENT_TRANSPORT_EP_CONNECT: |
---|
3082 | | - rc = iscsi_if_ep_connect(transport, ev, msg_type); |
---|
| 3111 | + if (rlen < sizeof(struct sockaddr)) |
---|
| 3112 | + rc = -EINVAL; |
---|
| 3113 | + else |
---|
| 3114 | + rc = iscsi_if_ep_connect(transport, ev, msg_type); |
---|
3083 | 3115 | break; |
---|
3084 | 3116 | case ISCSI_UEVENT_TRANSPORT_EP_POLL: |
---|
3085 | 3117 | if (!transport->ep_poll) |
---|
.. | .. |
---|
3103 | 3135 | |
---|
3104 | 3136 | static int |
---|
3105 | 3137 | iscsi_tgt_dscvr(struct iscsi_transport *transport, |
---|
3106 | | - struct iscsi_uevent *ev) |
---|
| 3138 | + struct iscsi_uevent *ev, u32 rlen) |
---|
3107 | 3139 | { |
---|
3108 | 3140 | struct Scsi_Host *shost; |
---|
3109 | 3141 | struct sockaddr *dst_addr; |
---|
3110 | 3142 | int err; |
---|
| 3143 | + |
---|
| 3144 | + if (rlen < sizeof(*dst_addr)) |
---|
| 3145 | + return -EINVAL; |
---|
3111 | 3146 | |
---|
3112 | 3147 | if (!transport->tgt_dscvr) |
---|
3113 | 3148 | return -EINVAL; |
---|
.. | .. |
---|
3129 | 3164 | |
---|
3130 | 3165 | static int |
---|
3131 | 3166 | iscsi_set_host_param(struct iscsi_transport *transport, |
---|
3132 | | - struct iscsi_uevent *ev) |
---|
| 3167 | + struct iscsi_uevent *ev, u32 rlen) |
---|
3133 | 3168 | { |
---|
3134 | 3169 | char *data = (char*)ev + sizeof(*ev); |
---|
3135 | 3170 | struct Scsi_Host *shost; |
---|
.. | .. |
---|
3138 | 3173 | if (!transport->set_host_param) |
---|
3139 | 3174 | return -ENOSYS; |
---|
3140 | 3175 | |
---|
3141 | | - if (ev->u.set_host_param.len > PAGE_SIZE) |
---|
| 3176 | + if (ev->u.set_host_param.len > rlen || |
---|
| 3177 | + ev->u.set_host_param.len > PAGE_SIZE) |
---|
3142 | 3178 | return -EINVAL; |
---|
3143 | 3179 | |
---|
3144 | 3180 | shost = scsi_host_lookup(ev->u.set_host_param.host_no); |
---|
.. | .. |
---|
3148 | 3184 | return -ENODEV; |
---|
3149 | 3185 | } |
---|
3150 | 3186 | |
---|
| 3187 | + /* see similar check in iscsi_if_set_param() */ |
---|
| 3188 | + if (strlen(data) > ev->u.set_host_param.len) |
---|
| 3189 | + return -EINVAL; |
---|
| 3190 | + |
---|
3151 | 3191 | err = transport->set_host_param(shost, ev->u.set_host_param.param, |
---|
3152 | 3192 | data, ev->u.set_host_param.len); |
---|
3153 | 3193 | scsi_host_put(shost); |
---|
.. | .. |
---|
3155 | 3195 | } |
---|
3156 | 3196 | |
---|
3157 | 3197 | static int |
---|
3158 | | -iscsi_set_path(struct iscsi_transport *transport, struct iscsi_uevent *ev) |
---|
| 3198 | +iscsi_set_path(struct iscsi_transport *transport, struct iscsi_uevent *ev, u32 rlen) |
---|
3159 | 3199 | { |
---|
3160 | 3200 | struct Scsi_Host *shost; |
---|
3161 | 3201 | struct iscsi_path *params; |
---|
3162 | 3202 | int err; |
---|
| 3203 | + |
---|
| 3204 | + if (rlen < sizeof(*params)) |
---|
| 3205 | + return -EINVAL; |
---|
3163 | 3206 | |
---|
3164 | 3207 | if (!transport->set_path) |
---|
3165 | 3208 | return -ENOSYS; |
---|
.. | .. |
---|
3220 | 3263 | } |
---|
3221 | 3264 | |
---|
3222 | 3265 | static int |
---|
3223 | | -iscsi_send_ping(struct iscsi_transport *transport, struct iscsi_uevent *ev) |
---|
| 3266 | +iscsi_send_ping(struct iscsi_transport *transport, struct iscsi_uevent *ev, u32 rlen) |
---|
3224 | 3267 | { |
---|
3225 | 3268 | struct Scsi_Host *shost; |
---|
3226 | 3269 | struct sockaddr *dst_addr; |
---|
3227 | 3270 | int err; |
---|
| 3271 | + |
---|
| 3272 | + if (rlen < sizeof(*dst_addr)) |
---|
| 3273 | + return -EINVAL; |
---|
3228 | 3274 | |
---|
3229 | 3275 | if (!transport->send_ping) |
---|
3230 | 3276 | return -ENOSYS; |
---|
.. | .. |
---|
3723 | 3769 | } |
---|
3724 | 3770 | |
---|
3725 | 3771 | static int iscsi_if_transport_conn(struct iscsi_transport *transport, |
---|
3726 | | - struct nlmsghdr *nlh) |
---|
| 3772 | + struct nlmsghdr *nlh, u32 pdu_len) |
---|
3727 | 3773 | { |
---|
3728 | 3774 | struct iscsi_uevent *ev = nlmsg_data(nlh); |
---|
3729 | 3775 | struct iscsi_cls_session *session; |
---|
3730 | 3776 | struct iscsi_cls_conn *conn = NULL; |
---|
3731 | 3777 | struct iscsi_endpoint *ep; |
---|
3732 | | - uint32_t pdu_len; |
---|
3733 | 3778 | int err = 0; |
---|
3734 | 3779 | |
---|
3735 | 3780 | switch (nlh->nlmsg_type) { |
---|
.. | .. |
---|
3809 | 3854 | |
---|
3810 | 3855 | break; |
---|
3811 | 3856 | case ISCSI_UEVENT_SEND_PDU: |
---|
3812 | | - pdu_len = nlh->nlmsg_len - sizeof(*nlh) - sizeof(*ev); |
---|
3813 | | - |
---|
3814 | 3857 | if ((ev->u.send_pdu.hdr_size > pdu_len) || |
---|
3815 | 3858 | (ev->u.send_pdu.data_size > (pdu_len - ev->u.send_pdu.hdr_size))) { |
---|
3816 | 3859 | err = -EINVAL; |
---|
.. | .. |
---|
3840 | 3883 | struct iscsi_internal *priv; |
---|
3841 | 3884 | struct iscsi_cls_session *session; |
---|
3842 | 3885 | struct iscsi_endpoint *ep = NULL; |
---|
| 3886 | + u32 rlen; |
---|
3843 | 3887 | |
---|
3844 | 3888 | if (!netlink_capable(skb, CAP_SYS_ADMIN)) |
---|
3845 | 3889 | return -EPERM; |
---|
.. | .. |
---|
3858 | 3902 | return -EINVAL; |
---|
3859 | 3903 | |
---|
3860 | 3904 | portid = NETLINK_CB(skb).portid; |
---|
| 3905 | + |
---|
| 3906 | + /* |
---|
| 3907 | + * Even though the remaining payload may not be regarded as nlattr, |
---|
| 3908 | + * (like address or something else), calculate the remaining length |
---|
| 3909 | + * here to ease following length checks. |
---|
| 3910 | + */ |
---|
| 3911 | + rlen = nlmsg_attrlen(nlh, sizeof(*ev)); |
---|
3861 | 3912 | |
---|
3862 | 3913 | switch (nlh->nlmsg_type) { |
---|
3863 | 3914 | case ISCSI_UEVENT_CREATE_SESSION: |
---|
.. | .. |
---|
3916 | 3967 | err = -EINVAL; |
---|
3917 | 3968 | break; |
---|
3918 | 3969 | case ISCSI_UEVENT_SET_PARAM: |
---|
3919 | | - err = iscsi_set_param(transport, ev); |
---|
| 3970 | + err = iscsi_if_set_param(transport, ev, rlen); |
---|
3920 | 3971 | break; |
---|
3921 | 3972 | case ISCSI_UEVENT_CREATE_CONN: |
---|
3922 | 3973 | case ISCSI_UEVENT_DESTROY_CONN: |
---|
.. | .. |
---|
3924 | 3975 | case ISCSI_UEVENT_START_CONN: |
---|
3925 | 3976 | case ISCSI_UEVENT_BIND_CONN: |
---|
3926 | 3977 | case ISCSI_UEVENT_SEND_PDU: |
---|
3927 | | - err = iscsi_if_transport_conn(transport, nlh); |
---|
| 3978 | + err = iscsi_if_transport_conn(transport, nlh, rlen); |
---|
3928 | 3979 | break; |
---|
3929 | 3980 | case ISCSI_UEVENT_GET_STATS: |
---|
3930 | 3981 | err = iscsi_if_get_stats(transport, nlh); |
---|
.. | .. |
---|
3933 | 3984 | case ISCSI_UEVENT_TRANSPORT_EP_POLL: |
---|
3934 | 3985 | case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: |
---|
3935 | 3986 | case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST: |
---|
3936 | | - err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type); |
---|
| 3987 | + err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type, rlen); |
---|
3937 | 3988 | break; |
---|
3938 | 3989 | case ISCSI_UEVENT_TGT_DSCVR: |
---|
3939 | | - err = iscsi_tgt_dscvr(transport, ev); |
---|
| 3990 | + err = iscsi_tgt_dscvr(transport, ev, rlen); |
---|
3940 | 3991 | break; |
---|
3941 | 3992 | case ISCSI_UEVENT_SET_HOST_PARAM: |
---|
3942 | | - err = iscsi_set_host_param(transport, ev); |
---|
| 3993 | + err = iscsi_set_host_param(transport, ev, rlen); |
---|
3943 | 3994 | break; |
---|
3944 | 3995 | case ISCSI_UEVENT_PATH_UPDATE: |
---|
3945 | | - err = iscsi_set_path(transport, ev); |
---|
| 3996 | + err = iscsi_set_path(transport, ev, rlen); |
---|
3946 | 3997 | break; |
---|
3947 | 3998 | case ISCSI_UEVENT_SET_IFACE_PARAMS: |
---|
3948 | | - err = iscsi_set_iface_params(transport, ev, |
---|
3949 | | - nlmsg_attrlen(nlh, sizeof(*ev))); |
---|
| 3999 | + err = iscsi_set_iface_params(transport, ev, rlen); |
---|
3950 | 4000 | break; |
---|
3951 | 4001 | case ISCSI_UEVENT_PING: |
---|
3952 | | - err = iscsi_send_ping(transport, ev); |
---|
| 4002 | + err = iscsi_send_ping(transport, ev, rlen); |
---|
3953 | 4003 | break; |
---|
3954 | 4004 | case ISCSI_UEVENT_GET_CHAP: |
---|
3955 | 4005 | err = iscsi_get_chap(transport, nlh); |
---|
.. | .. |
---|
3958 | 4008 | err = iscsi_delete_chap(transport, ev); |
---|
3959 | 4009 | break; |
---|
3960 | 4010 | case ISCSI_UEVENT_SET_FLASHNODE_PARAMS: |
---|
3961 | | - err = iscsi_set_flashnode_param(transport, ev, |
---|
3962 | | - nlmsg_attrlen(nlh, |
---|
3963 | | - sizeof(*ev))); |
---|
| 4011 | + err = iscsi_set_flashnode_param(transport, ev, rlen); |
---|
3964 | 4012 | break; |
---|
3965 | 4013 | case ISCSI_UEVENT_NEW_FLASHNODE: |
---|
3966 | | - err = iscsi_new_flashnode(transport, ev, |
---|
3967 | | - nlmsg_attrlen(nlh, sizeof(*ev))); |
---|
| 4014 | + err = iscsi_new_flashnode(transport, ev, rlen); |
---|
3968 | 4015 | break; |
---|
3969 | 4016 | case ISCSI_UEVENT_DEL_FLASHNODE: |
---|
3970 | 4017 | err = iscsi_del_flashnode(transport, ev); |
---|
.. | .. |
---|
3979 | 4026 | err = iscsi_logout_flashnode_sid(transport, ev); |
---|
3980 | 4027 | break; |
---|
3981 | 4028 | case ISCSI_UEVENT_SET_CHAP: |
---|
3982 | | - err = iscsi_set_chap(transport, ev, |
---|
3983 | | - nlmsg_attrlen(nlh, sizeof(*ev))); |
---|
| 4029 | + err = iscsi_set_chap(transport, ev, rlen); |
---|
3984 | 4030 | break; |
---|
3985 | 4031 | case ISCSI_UEVENT_GET_HOST_STATS: |
---|
3986 | 4032 | err = iscsi_get_host_stats(transport, nlh); |
---|
.. | .. |
---|
4344 | 4390 | iscsi_session_attr(discovery_parent_type, ISCSI_PARAM_DISCOVERY_PARENT_TYPE, 0); |
---|
4345 | 4391 | |
---|
4346 | 4392 | static ssize_t |
---|
| 4393 | +show_priv_session_target_state(struct device *dev, struct device_attribute *attr, |
---|
| 4394 | + char *buf) |
---|
| 4395 | +{ |
---|
| 4396 | + struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent); |
---|
| 4397 | + |
---|
| 4398 | + return sysfs_emit(buf, "%s\n", |
---|
| 4399 | + iscsi_session_target_state_name[session->target_state]); |
---|
| 4400 | +} |
---|
| 4401 | + |
---|
| 4402 | +static ISCSI_CLASS_ATTR(priv_sess, target_state, S_IRUGO, |
---|
| 4403 | + show_priv_session_target_state, NULL); |
---|
| 4404 | + |
---|
| 4405 | +static ssize_t |
---|
4347 | 4406 | show_priv_session_state(struct device *dev, struct device_attribute *attr, |
---|
4348 | 4407 | char *buf) |
---|
4349 | 4408 | { |
---|
.. | .. |
---|
4445 | 4504 | &dev_attr_sess_boot_target.attr, |
---|
4446 | 4505 | &dev_attr_priv_sess_recovery_tmo.attr, |
---|
4447 | 4506 | &dev_attr_priv_sess_state.attr, |
---|
| 4507 | + &dev_attr_priv_sess_target_state.attr, |
---|
4448 | 4508 | &dev_attr_priv_sess_creator.attr, |
---|
4449 | 4509 | &dev_attr_sess_chap_out_idx.attr, |
---|
4450 | 4510 | &dev_attr_sess_chap_in_idx.attr, |
---|
.. | .. |
---|
4558 | 4618 | return S_IRUGO | S_IWUSR; |
---|
4559 | 4619 | else if (attr == &dev_attr_priv_sess_state.attr) |
---|
4560 | 4620 | return S_IRUGO; |
---|
| 4621 | + else if (attr == &dev_attr_priv_sess_target_state.attr) |
---|
| 4622 | + return S_IRUGO; |
---|
4561 | 4623 | else if (attr == &dev_attr_priv_sess_creator.attr) |
---|
4562 | 4624 | return S_IRUGO; |
---|
4563 | 4625 | else if (attr == &dev_attr_priv_sess_target_id.attr) |
---|