Skip to content

Commit 02db81a

Browse files
committed
Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI fixes from James Bottomley: "Six fixes, all in drivers. The biggest are the UFS devfreq fixes which address a lock inversion and the two iscsi_tcp fixes which try to prevent a use after free from userspace still accessing an area which the kernel has released (seen by KASAN)" * tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: scsi: device_handler: alua: Remove a might_sleep() annotation scsi: iscsi_tcp: Fix UAF during login when accessing the shost ipaddress scsi: iscsi_tcp: Fix UAF during logout when accessing the shost ipaddress scsi: ufs: core: Fix devfreq deadlocks scsi: hpsa: Fix allocation size for scsi_host_alloc() scsi: target: core: Fix warning on RT kernels
2 parents fb6e71d + 0bfe63d commit 02db81a

File tree

8 files changed

+71
-31
lines changed

8 files changed

+71
-31
lines changed

drivers/scsi/device_handler/scsi_dh_alua.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,9 @@ static void alua_rtpg_work(struct work_struct *work)
981981
*
982982
* Returns true if and only if alua_rtpg_work() will be called asynchronously.
983983
* That function is responsible for calling @qdata->fn().
984+
*
985+
* Context: may be called from atomic context (alua_check()) only if the caller
986+
* holds an sdev reference.
984987
*/
985988
static bool alua_rtpg_queue(struct alua_port_group *pg,
986989
struct scsi_device *sdev,
@@ -989,8 +992,6 @@ static bool alua_rtpg_queue(struct alua_port_group *pg,
989992
int start_queue = 0;
990993
unsigned long flags;
991994

992-
might_sleep();
993-
994995
if (WARN_ON_ONCE(!pg) || scsi_device_get(sdev))
995996
return false;
996997

drivers/scsi/hpsa.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5850,7 +5850,7 @@ static int hpsa_scsi_host_alloc(struct ctlr_info *h)
58505850
{
58515851
struct Scsi_Host *sh;
58525852

5853-
sh = scsi_host_alloc(&hpsa_driver_template, sizeof(h));
5853+
sh = scsi_host_alloc(&hpsa_driver_template, sizeof(struct ctlr_info));
58545854
if (sh == NULL) {
58555855
dev_err(&h->pdev->dev, "scsi_host_alloc failed\n");
58565856
return -ENOMEM;

drivers/scsi/iscsi_tcp.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -849,7 +849,7 @@ static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost,
849849
enum iscsi_host_param param, char *buf)
850850
{
851851
struct iscsi_sw_tcp_host *tcp_sw_host = iscsi_host_priv(shost);
852-
struct iscsi_session *session = tcp_sw_host->session;
852+
struct iscsi_session *session;
853853
struct iscsi_conn *conn;
854854
struct iscsi_tcp_conn *tcp_conn;
855855
struct iscsi_sw_tcp_conn *tcp_sw_conn;
@@ -859,6 +859,7 @@ static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost,
859859

860860
switch (param) {
861861
case ISCSI_HOST_PARAM_IPADDRESS:
862+
session = tcp_sw_host->session;
862863
if (!session)
863864
return -ENOTCONN;
864865

@@ -959,11 +960,13 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
959960
if (!cls_session)
960961
goto remove_host;
961962
session = cls_session->dd_data;
962-
tcp_sw_host = iscsi_host_priv(shost);
963-
tcp_sw_host->session = session;
964963

965964
if (iscsi_tcp_r2tpool_alloc(session))
966965
goto remove_session;
966+
967+
/* We are now fully setup so expose the session to sysfs. */
968+
tcp_sw_host = iscsi_host_priv(shost);
969+
tcp_sw_host->session = session;
967970
return cls_session;
968971

969972
remove_session:
@@ -983,10 +986,17 @@ static void iscsi_sw_tcp_session_destroy(struct iscsi_cls_session *cls_session)
983986
if (WARN_ON_ONCE(session->leadconn))
984987
return;
985988

989+
iscsi_session_remove(cls_session);
990+
/*
991+
* Our get_host_param needs to access the session, so remove the
992+
* host from sysfs before freeing the session to make sure userspace
993+
* is no longer accessing the callout.
994+
*/
995+
iscsi_host_remove(shost, false);
996+
986997
iscsi_tcp_r2tpool_free(cls_session->dd_data);
987-
iscsi_session_teardown(cls_session);
988998

989-
iscsi_host_remove(shost, false);
999+
iscsi_session_free(cls_session);
9901000
iscsi_host_free(shost);
9911001
}
9921002

drivers/scsi/libiscsi.c

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3104,17 +3104,32 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
31043104
}
31053105
EXPORT_SYMBOL_GPL(iscsi_session_setup);
31063106

3107-
/**
3108-
* iscsi_session_teardown - destroy session, host, and cls_session
3109-
* @cls_session: iscsi session
3107+
/*
3108+
* issi_session_remove - Remove session from iSCSI class.
31103109
*/
3111-
void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
3110+
void iscsi_session_remove(struct iscsi_cls_session *cls_session)
31123111
{
31133112
struct iscsi_session *session = cls_session->dd_data;
3114-
struct module *owner = cls_session->transport->owner;
31153113
struct Scsi_Host *shost = session->host;
31163114

31173115
iscsi_remove_session(cls_session);
3116+
/*
3117+
* host removal only has to wait for its children to be removed from
3118+
* sysfs, and iscsi_tcp needs to do iscsi_host_remove before freeing
3119+
* the session, so drop the session count here.
3120+
*/
3121+
iscsi_host_dec_session_cnt(shost);
3122+
}
3123+
EXPORT_SYMBOL_GPL(iscsi_session_remove);
3124+
3125+
/**
3126+
* iscsi_session_free - Free iscsi session and it's resources
3127+
* @cls_session: iscsi session
3128+
*/
3129+
void iscsi_session_free(struct iscsi_cls_session *cls_session)
3130+
{
3131+
struct iscsi_session *session = cls_session->dd_data;
3132+
struct module *owner = cls_session->transport->owner;
31183133

31193134
iscsi_pool_free(&session->cmdpool);
31203135
kfree(session->password);
@@ -3132,10 +3147,19 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
31323147
kfree(session->discovery_parent_type);
31333148

31343149
iscsi_free_session(cls_session);
3135-
3136-
iscsi_host_dec_session_cnt(shost);
31373150
module_put(owner);
31383151
}
3152+
EXPORT_SYMBOL_GPL(iscsi_session_free);
3153+
3154+
/**
3155+
* iscsi_session_teardown - destroy session and cls_session
3156+
* @cls_session: iscsi session
3157+
*/
3158+
void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
3159+
{
3160+
iscsi_session_remove(cls_session);
3161+
iscsi_session_free(cls_session);
3162+
}
31393163
EXPORT_SYMBOL_GPL(iscsi_session_teardown);
31403164

31413165
/**

drivers/target/target_core_tmr.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ static bool __target_check_io_state(struct se_cmd *se_cmd,
7373
{
7474
struct se_session *sess = se_cmd->se_sess;
7575

76-
assert_spin_locked(&sess->sess_cmd_lock);
77-
WARN_ON_ONCE(!irqs_disabled());
76+
lockdep_assert_held(&sess->sess_cmd_lock);
77+
7878
/*
7979
* If command already reached CMD_T_COMPLETE state within
8080
* target_complete_cmd() or CMD_T_FABRIC_STOP due to shutdown,

drivers/ufs/core/ufshcd.c

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,12 +1234,14 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba)
12341234
* clock scaling is in progress
12351235
*/
12361236
ufshcd_scsi_block_requests(hba);
1237+
mutex_lock(&hba->wb_mutex);
12371238
down_write(&hba->clk_scaling_lock);
12381239

12391240
if (!hba->clk_scaling.is_allowed ||
12401241
ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US)) {
12411242
ret = -EBUSY;
12421243
up_write(&hba->clk_scaling_lock);
1244+
mutex_unlock(&hba->wb_mutex);
12431245
ufshcd_scsi_unblock_requests(hba);
12441246
goto out;
12451247
}
@@ -1251,12 +1253,16 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba)
12511253
return ret;
12521254
}
12531255

1254-
static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, bool writelock)
1256+
static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, int err, bool scale_up)
12551257
{
1256-
if (writelock)
1257-
up_write(&hba->clk_scaling_lock);
1258-
else
1259-
up_read(&hba->clk_scaling_lock);
1258+
up_write(&hba->clk_scaling_lock);
1259+
1260+
/* Enable Write Booster if we have scaled up else disable it */
1261+
if (ufshcd_enable_wb_if_scaling_up(hba) && !err)
1262+
ufshcd_wb_toggle(hba, scale_up);
1263+
1264+
mutex_unlock(&hba->wb_mutex);
1265+
12601266
ufshcd_scsi_unblock_requests(hba);
12611267
ufshcd_release(hba);
12621268
}
@@ -1273,7 +1279,6 @@ static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, bool writelock)
12731279
static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up)
12741280
{
12751281
int ret = 0;
1276-
bool is_writelock = true;
12771282

12781283
ret = ufshcd_clock_scaling_prepare(hba);
12791284
if (ret)
@@ -1302,15 +1307,8 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up)
13021307
}
13031308
}
13041309

1305-
/* Enable Write Booster if we have scaled up else disable it */
1306-
if (ufshcd_enable_wb_if_scaling_up(hba)) {
1307-
downgrade_write(&hba->clk_scaling_lock);
1308-
is_writelock = false;
1309-
ufshcd_wb_toggle(hba, scale_up);
1310-
}
1311-
13121310
out_unprepare:
1313-
ufshcd_clock_scaling_unprepare(hba, is_writelock);
1311+
ufshcd_clock_scaling_unprepare(hba, ret, scale_up);
13141312
return ret;
13151313
}
13161314

@@ -6066,9 +6064,11 @@ static void ufshcd_force_error_recovery(struct ufs_hba *hba)
60666064

60676065
static void ufshcd_clk_scaling_allow(struct ufs_hba *hba, bool allow)
60686066
{
6067+
mutex_lock(&hba->wb_mutex);
60696068
down_write(&hba->clk_scaling_lock);
60706069
hba->clk_scaling.is_allowed = allow;
60716070
up_write(&hba->clk_scaling_lock);
6071+
mutex_unlock(&hba->wb_mutex);
60726072
}
60736073

60746074
static void ufshcd_clk_scaling_suspend(struct ufs_hba *hba, bool suspend)
@@ -9793,6 +9793,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
97939793
/* Initialize mutex for exception event control */
97949794
mutex_init(&hba->ee_ctrl_mutex);
97959795

9796+
mutex_init(&hba->wb_mutex);
97969797
init_rwsem(&hba->clk_scaling_lock);
97979798

97989799
ufshcd_init_clk_gating(hba);

include/scsi/libiscsi.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,8 @@ extern int iscsi_host_get_max_scsi_cmds(struct Scsi_Host *shost,
422422
extern struct iscsi_cls_session *
423423
iscsi_session_setup(struct iscsi_transport *, struct Scsi_Host *shost,
424424
uint16_t, int, int, uint32_t, unsigned int);
425+
void iscsi_session_remove(struct iscsi_cls_session *cls_session);
426+
void iscsi_session_free(struct iscsi_cls_session *cls_session);
425427
extern void iscsi_session_teardown(struct iscsi_cls_session *);
426428
extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *);
427429
extern int iscsi_set_param(struct iscsi_cls_conn *cls_conn,

include/ufs/ufshcd.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,7 @@ struct ufs_hba_monitor {
808808
* @urgent_bkops_lvl: keeps track of urgent bkops level for device
809809
* @is_urgent_bkops_lvl_checked: keeps track if the urgent bkops level for
810810
* device is known or not.
811+
* @wb_mutex: used to serialize devfreq and sysfs write booster toggling
811812
* @clk_scaling_lock: used to serialize device commands and clock scaling
812813
* @desc_size: descriptor sizes reported by device
813814
* @scsi_block_reqs_cnt: reference counting for scsi block requests
@@ -951,6 +952,7 @@ struct ufs_hba {
951952
enum bkops_status urgent_bkops_lvl;
952953
bool is_urgent_bkops_lvl_checked;
953954

955+
struct mutex wb_mutex;
954956
struct rw_semaphore clk_scaling_lock;
955957
unsigned char desc_size[QUERY_DESC_IDN_MAX];
956958
atomic_t scsi_block_reqs_cnt;

0 commit comments

Comments
 (0)