Skip to content

Commit df36588

Browse files
committed
Merge tag 'for-linus-5.16-2' of git://github.com/cminyard/linux-ipmi
Pull IPMI fixes from Corey Minyard: "Some changes that went in 5.16 had issues. When working on the design a piece was redesigned and things got missed. And the message type was not being initialized when it was allocated, resulting in crashes. In addition, the IPMI driver has had a shutdown issue where it could still have an item in a system workqueue after it had been shutdown. Move to a private workqueue to avoid that problem" * tag 'for-linus-5.16-2' of git://github.com/cminyard/linux-ipmi: ipmi:ipmb: Fix unknown command response ipmi: fix IPMI_SMI_MSG_TYPE_IPMB_DIRECT response length checking ipmi: fix oob access due to uninit smi_msg type ipmi: msghandler: Make symbol 'remove_work_wq' static ipmi: Move remove_work to dedicated workqueue
2 parents 4536579 + c03a487 commit df36588

File tree

1 file changed

+33
-8
lines changed

1 file changed

+33
-8
lines changed

drivers/char/ipmi/ipmi_msghandler.c

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ struct ipmi_user {
191191
struct work_struct remove_work;
192192
};
193193

194+
static struct workqueue_struct *remove_work_wq;
195+
194196
static struct ipmi_user *acquire_ipmi_user(struct ipmi_user *user, int *index)
195197
__acquires(user->release_barrier)
196198
{
@@ -1297,7 +1299,7 @@ static void free_user(struct kref *ref)
12971299
struct ipmi_user *user = container_of(ref, struct ipmi_user, refcount);
12981300

12991301
/* SRCU cleanup must happen in task context. */
1300-
schedule_work(&user->remove_work);
1302+
queue_work(remove_work_wq, &user->remove_work);
13011303
}
13021304

13031305
static void _ipmi_destroy_user(struct ipmi_user *user)
@@ -3918,9 +3920,11 @@ static int handle_ipmb_direct_rcv_cmd(struct ipmi_smi *intf,
39183920
/* We didn't find a user, deliver an error response. */
39193921
ipmi_inc_stat(intf, unhandled_commands);
39203922

3921-
msg->data[0] = ((netfn + 1) << 2) | (msg->rsp[4] & 0x3);
3922-
msg->data[1] = msg->rsp[2];
3923-
msg->data[2] = msg->rsp[4] & ~0x3;
3923+
msg->data[0] = (netfn + 1) << 2;
3924+
msg->data[0] |= msg->rsp[2] & 0x3; /* rqLUN */
3925+
msg->data[1] = msg->rsp[1]; /* Addr */
3926+
msg->data[2] = msg->rsp[2] & ~0x3; /* rqSeq */
3927+
msg->data[2] |= msg->rsp[0] & 0x3; /* rsLUN */
39243928
msg->data[3] = cmd;
39253929
msg->data[4] = IPMI_INVALID_CMD_COMPLETION_CODE;
39263930
msg->data_size = 5;
@@ -4455,13 +4459,24 @@ static int handle_one_recv_msg(struct ipmi_smi *intf,
44554459
msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
44564460
msg->rsp_size = 3;
44574461
} else if (msg->type == IPMI_SMI_MSG_TYPE_IPMB_DIRECT) {
4458-
/* commands must have at least 3 bytes, responses 4. */
4459-
if (is_cmd && (msg->rsp_size < 3)) {
4462+
/* commands must have at least 4 bytes, responses 5. */
4463+
if (is_cmd && (msg->rsp_size < 4)) {
44604464
ipmi_inc_stat(intf, invalid_commands);
44614465
goto out;
44624466
}
4463-
if (!is_cmd && (msg->rsp_size < 4))
4464-
goto return_unspecified;
4467+
if (!is_cmd && (msg->rsp_size < 5)) {
4468+
ipmi_inc_stat(intf, invalid_ipmb_responses);
4469+
/* Construct a valid error response. */
4470+
msg->rsp[0] = msg->data[0] & 0xfc; /* NetFN */
4471+
msg->rsp[0] |= (1 << 2); /* Make it a response */
4472+
msg->rsp[0] |= msg->data[2] & 3; /* rqLUN */
4473+
msg->rsp[1] = msg->data[1]; /* Addr */
4474+
msg->rsp[2] = msg->data[2] & 0xfc; /* rqSeq */
4475+
msg->rsp[2] |= msg->data[0] & 0x3; /* rsLUN */
4476+
msg->rsp[3] = msg->data[3]; /* Cmd */
4477+
msg->rsp[4] = IPMI_ERR_UNSPECIFIED;
4478+
msg->rsp_size = 5;
4479+
}
44654480
} else if ((msg->data_size >= 2)
44664481
&& (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
44674482
&& (msg->data[1] == IPMI_SEND_MSG_CMD)
@@ -5031,6 +5046,7 @@ struct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
50315046
if (rv) {
50325047
rv->done = free_smi_msg;
50335048
rv->user_data = NULL;
5049+
rv->type = IPMI_SMI_MSG_TYPE_NORMAL;
50345050
atomic_inc(&smi_msg_inuse_count);
50355051
}
50365052
return rv;
@@ -5383,6 +5399,13 @@ static int ipmi_init_msghandler(void)
53835399

53845400
atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
53855401

5402+
remove_work_wq = create_singlethread_workqueue("ipmi-msghandler-remove-wq");
5403+
if (!remove_work_wq) {
5404+
pr_err("unable to create ipmi-msghandler-remove-wq workqueue");
5405+
rv = -ENOMEM;
5406+
goto out;
5407+
}
5408+
53865409
initialized = true;
53875410

53885411
out:
@@ -5408,6 +5431,8 @@ static void __exit cleanup_ipmi(void)
54085431
int count;
54095432

54105433
if (initialized) {
5434+
destroy_workqueue(remove_work_wq);
5435+
54115436
atomic_notifier_chain_unregister(&panic_notifier_list,
54125437
&panic_block);
54135438

0 commit comments

Comments
 (0)