From ce1ce2f31224c18e84d859ccd5675cbb2728f57a Mon Sep 17 00:00:00 2001 From: Ingo Tuchscherer Date: Tue, 18 Mar 2014 16:30:21 +0100 Subject: s390/zcrypt: add length check for aligned data to avoid overflow in msg-type 6 Signed-off-by: Ingo Tuchscherer Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/zcrypt_api.c | 4 ++-- drivers/s390/crypto/zcrypt_msgtype6.c | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 4b824b1..5222ebe 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -626,8 +626,8 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) return -ENOMEM; if (copy_from_user(ep11_dev_list.targets, - (struct ep11_target_dev *)xcrb->targets, - xcrb->targets_num * + (struct ep11_target_dev __force __user *) + xcrb->targets, xcrb->targets_num * sizeof(struct ep11_target_dev))) return -EFAULT; } diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index 0bc91e4..46b324c 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -315,6 +315,10 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, char *req_data = ap_msg->message + sizeof(struct type6_hdr) + rcblen; char *function_code; + if (CEIL4(xcRB->request_control_blk_length) < + xcRB->request_control_blk_length) + return -EINVAL; /* overflow after alignment*/ + /* length checks */ ap_msg->length = sizeof(struct type6_hdr) + CEIL4(xcRB->request_control_blk_length) + @@ -333,6 +337,10 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, return -EINVAL; } + if (CEIL4(xcRB->reply_control_blk_length) < + xcRB->reply_control_blk_length) + return -EINVAL; /* overflow after alignment*/ + replylen = sizeof(struct type86_fmt2_msg) + CEIL4(xcRB->reply_control_blk_length) + xcRB->reply_data_length; @@ -415,12 +423,18 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev, unsigned int dom_val; /* domain id */ } __packed * payload_hdr; + if (CEIL4(xcRB->req_len) < xcRB->req_len) + return -EINVAL; /* overflow after alignment*/ + /* length checks */ ap_msg->length = sizeof(struct type6_hdr) + xcRB->req_len; if (CEIL4(xcRB->req_len) > MSGTYPE06_MAX_MSG_SIZE - (sizeof(struct type6_hdr))) return -EINVAL; + if (CEIL4(xcRB->resp_len) < xcRB->resp_len) + return -EINVAL; /* overflow after alignment*/ + if (CEIL4(xcRB->resp_len) > MSGTYPE06_MAX_MSG_SIZE - (sizeof(struct type86_fmt2_msg))) return -EINVAL; @@ -432,7 +446,7 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev, /* Import CPRB data from the ioctl input parameter */ if (copy_from_user(&(msg->cprbx.cprb_len), - (char *)xcRB->req, xcRB->req_len)) { + (char __force __user *)xcRB->req, xcRB->req_len)) { return -EFAULT; } @@ -645,7 +659,7 @@ static int convert_type86_ep11_xcrb(struct zcrypt_device *zdev, return -EINVAL; /* Copy response CPRB to user */ - if (copy_to_user((char *)xcRB->resp, + if (copy_to_user((char __force __user *)xcRB->resp, data + msg->fmt2.offset1, msg->fmt2.count1)) return -EFAULT; xcRB->resp_len = msg->fmt2.count1; -- cgit v1.1 From bd1cb5de140d844f63389bf21b336c194a8c83a1 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 21 Mar 2014 15:24:27 +0100 Subject: s390/3270: fix crash with multiple reset device requests If the 3270 device is detached the initial reset device request will stays pending until the device is operational. A second reset device call will reuse the same request structure which will cause an oops. Add a check to see if the reset device request is already pending and do nothing in this case. Signed-off-by: Martin Schwidefsky --- drivers/s390/char/raw3270.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 9f849df..15b3459 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -632,6 +632,8 @@ raw3270_reset_device_cb(struct raw3270_request *rq, void *data) raw3270_size_device_done(rp); } else raw3270_writesf_readpart(rp); + memset(&rp->init_reset, 0, sizeof(rp->init_reset)); + memset(&rp->init_data, 0, sizeof(rp->init_data)); } static int @@ -639,9 +641,10 @@ __raw3270_reset_device(struct raw3270 *rp) { int rc; + /* Check if reset is already pending */ + if (rp->init_reset.view) + return -EBUSY; /* Store reset data stream to init_data/init_reset */ - memset(&rp->init_reset, 0, sizeof(rp->init_reset)); - memset(&rp->init_data, 0, sizeof(rp->init_data)); rp->init_data[0] = TW_KR; rp->init_reset.ccw.cmd_code = TC_EWRITEA; rp->init_reset.ccw.flags = CCW_FLAG_SLI; @@ -850,7 +853,7 @@ raw3270_create_device(struct ccw_device *cdev) char *ascebc; int rc; - rp = kmalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA); + rp = kzalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA); if (!rp) return ERR_PTR(-ENOMEM); ascebc = kmalloc(256, GFP_KERNEL); -- cgit v1.1 From 02ba8d211d16f3b385147dd50d7198744e9af59c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 23 Mar 2014 15:09:24 +0000 Subject: s390/tape: Use del_timer_sync() del_timer() does not wait for a possible running callback to complete. So the call side might free request and the associated objects while on another cpu the timer handler runs. Signed-off-by: Thomas Gleixner Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/tape_std.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c index 981a99f..cf577a2 100644 --- a/drivers/s390/char/tape_std.c +++ b/drivers/s390/char/tape_std.c @@ -78,7 +78,7 @@ tape_std_assign(struct tape_device *device) rc = tape_do_io_interruptible(device, request); - del_timer(&timeout); + del_timer_sync(&timeout); if (rc != 0) { DBF_EVENT(3, "%08x: assign failed - device might be busy\n", -- cgit v1.1 From 50f0e3bc93d86d0df6805eb55c58302d27a5cfca Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 23 Mar 2014 15:09:25 +0000 Subject: s390/tape: Add missing destroy_timer_on_stack() Otherwise we leak a tracking object when DEBUG_OBJECTS is enabled. Signed-off-by: Thomas Gleixner Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/tape_std.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/s390') diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c index cf577a2..3478e19 100644 --- a/drivers/s390/char/tape_std.c +++ b/drivers/s390/char/tape_std.c @@ -79,6 +79,7 @@ tape_std_assign(struct tape_device *device) rc = tape_do_io_interruptible(device, request); del_timer_sync(&timeout); + destroy_timer_on_stack(&timeout); if (rc != 0) { DBF_EVENT(3, "%08x: assign failed - device might be busy\n", -- cgit v1.1 From 12797e8e9da93dca9040f8a1a018e27635f29f04 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 23 Mar 2014 15:09:25 +0000 Subject: lcs: Add missing destroy_timer_on_stack() Otherwise we leak a tracking object when DEBUG_OBJECTS is enabled. Signed-off-by: Thomas Gleixner Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/net/lcs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/s390') diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index f404f55..c461f2a 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -899,6 +899,7 @@ lcs_send_lancmd(struct lcs_card *card, struct lcs_buffer *buffer, add_timer(&timer); wait_event(reply->wait_q, reply->received); del_timer_sync(&timer); + destroy_timer_on_stack(&timer); LCS_DBF_TEXT_(4, trace, "rc:%d",reply->rc); rc = reply->rc; lcs_put_reply(reply); -- cgit v1.1 From 9f0128f9e7bf7b2929540d395daf8d823dc30c9f Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Mon, 31 Mar 2014 16:18:29 +0200 Subject: s390/sclp: add timeout for queued requests This patch adds a timeout option for queued requests and introduces sclp_sync_request_timeout() to use this timer. With this, blocking the system too long, e.g. during an SE reboot, can be avoided in critical situations like CPU and memory hotplug. Since there is no way to cancel a running request, this timeout only applies to queued requests that have not yet been started. Reviewed-by: Peter Oberparleiter Signed-off-by: Gerald Schaefer Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp.c | 82 ++++++++++++++++++++++++++++++++++++++++++++ drivers/s390/char/sclp.h | 9 +++++ drivers/s390/char/sclp_cmd.c | 17 ++++++--- 3 files changed, 104 insertions(+), 4 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 1fe2643..e9ede59 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -91,6 +91,9 @@ static struct sclp_req sclp_suspend_req; /* Timer for request retries. */ static struct timer_list sclp_request_timer; +/* Timer for queued requests. */ +static struct timer_list sclp_queue_timer; + /* Internal state: is the driver initialized? */ static volatile enum sclp_init_state_t { sclp_init_state_uninitialized, @@ -215,6 +218,76 @@ sclp_request_timeout(unsigned long data) sclp_process_queue(); } +/* + * Returns the expire value in jiffies of the next pending request timeout, + * if any. Needs to be called with sclp_lock. + */ +static unsigned long __sclp_req_queue_find_next_timeout(void) +{ + unsigned long expires_next = 0; + struct sclp_req *req; + + list_for_each_entry(req, &sclp_req_queue, list) { + if (!req->queue_expires) + continue; + if (!expires_next || + (time_before(req->queue_expires, expires_next))) + expires_next = req->queue_expires; + } + return expires_next; +} + +/* + * Returns expired request, if any, and removes it from the list. + */ +static struct sclp_req *__sclp_req_queue_remove_expired_req(void) +{ + unsigned long flags, now; + struct sclp_req *req; + + spin_lock_irqsave(&sclp_lock, flags); + now = jiffies; + /* Don't need list_for_each_safe because we break out after list_del */ + list_for_each_entry(req, &sclp_req_queue, list) { + if (!req->queue_expires) + continue; + if (time_before_eq(req->queue_expires, now)) { + if (req->status == SCLP_REQ_QUEUED) { + req->status = SCLP_REQ_QUEUED_TIMEOUT; + list_del(&req->list); + goto out; + } + } + } + req = NULL; +out: + spin_unlock_irqrestore(&sclp_lock, flags); + return req; +} + +/* + * Timeout handler for queued requests. Removes request from list and + * invokes callback. This timer can be set per request in situations where + * waiting too long would be harmful to the system, e.g. during SE reboot. + */ +static void sclp_req_queue_timeout(unsigned long data) +{ + unsigned long flags, expires_next; + struct sclp_req *req; + + do { + req = __sclp_req_queue_remove_expired_req(); + if (req && req->callback) + req->callback(req, req->callback_data); + } while (req); + + spin_lock_irqsave(&sclp_lock, flags); + expires_next = __sclp_req_queue_find_next_timeout(); + if (expires_next) + mod_timer(&sclp_queue_timer, expires_next); + spin_unlock_irqrestore(&sclp_lock, flags); +} + /* Try to start a request. Return zero if the request was successfully * started or if it will be started at a later time. Return non-zero otherwise. * Called while sclp_lock is locked. */ @@ -317,6 +390,13 @@ sclp_add_request(struct sclp_req *req) req->start_count = 0; list_add_tail(&req->list, &sclp_req_queue); rc = 0; + if (req->queue_timeout) { + req->queue_expires = jiffies + req->queue_timeout * HZ; + if (!timer_pending(&sclp_queue_timer) || + time_after(sclp_queue_timer.expires, req->queue_expires)) + mod_timer(&sclp_queue_timer, req->queue_expires); + } else + req->queue_expires = 0; /* Start if request is first in list */ if (sclp_running_state == sclp_running_state_idle && req->list.prev == &sclp_req_queue) { @@ -1113,6 +1193,8 @@ sclp_init(void) INIT_LIST_HEAD(&sclp_reg_list); list_add(&sclp_state_change_event.list, &sclp_reg_list); init_timer(&sclp_request_timer); + init_timer(&sclp_queue_timer); + sclp_queue_timer.function = sclp_req_queue_timeout; /* Check interface */ spin_unlock_irqrestore(&sclp_lock, flags); rc = sclp_check_interface(); diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index fea76ae..a68b5ec 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -133,6 +133,11 @@ struct sclp_req { /* Callback that is called after reaching final status. */ void (*callback)(struct sclp_req *, void *data); void *callback_data; + int queue_timeout; /* request queue timeout (sec), set by + caller of sclp_add_request(), if + needed */ + /* Internal fields */ + unsigned long queue_expires; /* request queue timeout (jiffies) */ }; #define SCLP_REQ_FILLED 0x00 /* request is ready to be processed */ @@ -140,6 +145,9 @@ struct sclp_req { #define SCLP_REQ_RUNNING 0x02 /* request is currently running */ #define SCLP_REQ_DONE 0x03 /* request is completed successfully */ #define SCLP_REQ_FAILED 0x05 /* request is finally failed */ +#define SCLP_REQ_QUEUED_TIMEOUT 0x06 /* request on queue timed out */ + +#define SCLP_QUEUE_INTERVAL 5 /* timeout interval for request queue */ /* function pointers that a high level driver has to use for registration */ /* of some routines it wants to be called from the low level driver */ @@ -173,6 +181,7 @@ int sclp_deactivate(void); int sclp_reactivate(void); int sclp_service_call(sclp_cmdw_t command, void *sccb); int sclp_sync_request(sclp_cmdw_t command, void *sccb); +int sclp_sync_request_timeout(sclp_cmdw_t command, void *sccb, int timeout); int sclp_sdias_init(void); void sclp_sdias_exit(void); diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index 49af8ee..6e8f90f 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -37,6 +37,11 @@ static void sclp_sync_callback(struct sclp_req *req, void *data) int sclp_sync_request(sclp_cmdw_t cmd, void *sccb) { + return sclp_sync_request_timeout(cmd, sccb, 0); +} + +int sclp_sync_request_timeout(sclp_cmdw_t cmd, void *sccb, int timeout) +{ struct completion completion; struct sclp_req *request; int rc; @@ -44,6 +49,8 @@ int sclp_sync_request(sclp_cmdw_t cmd, void *sccb) request = kzalloc(sizeof(*request), GFP_KERNEL); if (!request) return -ENOMEM; + if (timeout) + request->queue_timeout = timeout; request->command = cmd; request->sccb = sccb; request->status = SCLP_REQ_FILLED; @@ -110,7 +117,8 @@ int sclp_get_cpu_info(struct sclp_cpu_info *info) if (!sccb) return -ENOMEM; sccb->header.length = sizeof(*sccb); - rc = sclp_sync_request(SCLP_CMDW_READ_CPU_INFO, sccb); + rc = sclp_sync_request_timeout(SCLP_CMDW_READ_CPU_INFO, sccb, + SCLP_QUEUE_INTERVAL); if (rc) goto out; if (sccb->header.response_code != 0x0010) { @@ -144,7 +152,7 @@ static int do_cpu_configure(sclp_cmdw_t cmd) if (!sccb) return -ENOMEM; sccb->header.length = sizeof(*sccb); - rc = sclp_sync_request(cmd, sccb); + rc = sclp_sync_request_timeout(cmd, sccb, SCLP_QUEUE_INTERVAL); if (rc) goto out; switch (sccb->header.response_code) { @@ -214,7 +222,7 @@ static int do_assign_storage(sclp_cmdw_t cmd, u16 rn) return -ENOMEM; sccb->header.length = PAGE_SIZE; sccb->rn = rn; - rc = sclp_sync_request(cmd, sccb); + rc = sclp_sync_request_timeout(cmd, sccb, SCLP_QUEUE_INTERVAL); if (rc) goto out; switch (sccb->header.response_code) { @@ -269,7 +277,8 @@ static int sclp_attach_storage(u8 id) if (!sccb) return -ENOMEM; sccb->header.length = PAGE_SIZE; - rc = sclp_sync_request(0x00080001 | id << 8, sccb); + rc = sclp_sync_request_timeout(0x00080001 | id << 8, sccb, + SCLP_QUEUE_INTERVAL); if (rc) goto out; switch (sccb->header.response_code) { -- cgit v1.1 From 1dad093b66fdd4fd5d7d2692169dc1bafd794628 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 31 Mar 2014 15:24:08 +0200 Subject: s390/irq: Use defines for external interruption codes Use the new defines for external interruption codes to get rid of "magic" numbers in the s390 source code. And while we're at it, also rename the (un-)register_external_interrupt function to something shorter so that this patch does not exceed the 80 columns all over the place. Signed-off-by: Thomas Huth Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_diag.c | 4 ++-- drivers/s390/char/sclp.c | 6 +++--- drivers/s390/kvm/kvm_virtio.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 9cbc567..c062f16 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -646,7 +646,7 @@ dasd_diag_init(void) ASCEBC(dasd_diag_discipline.ebcname, 4); irq_subclass_register(IRQ_SUBCLASS_SERVICE_SIGNAL); - register_external_interrupt(0x2603, dasd_ext_handler); + register_external_irq(EXT_IRQ_CP_SERVICE, dasd_ext_handler); dasd_diag_discipline_pointer = &dasd_diag_discipline; return 0; } @@ -654,7 +654,7 @@ dasd_diag_init(void) static void __exit dasd_diag_cleanup(void) { - unregister_external_interrupt(0x2603, dasd_ext_handler); + unregister_external_irq(EXT_IRQ_CP_SERVICE, dasd_ext_handler); irq_subclass_unregister(IRQ_SUBCLASS_SERVICE_SIGNAL); dasd_diag_discipline_pointer = NULL; } diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index e9ede59..1990285 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -972,7 +972,7 @@ sclp_check_interface(void) spin_lock_irqsave(&sclp_lock, flags); /* Prepare init mask command */ - rc = register_external_interrupt(0x2401, sclp_check_handler); + rc = register_external_irq(EXT_IRQ_SERVICE_SIG, sclp_check_handler); if (rc) { spin_unlock_irqrestore(&sclp_lock, flags); return rc; @@ -1005,7 +1005,7 @@ sclp_check_interface(void) } else rc = -EBUSY; } - unregister_external_interrupt(0x2401, sclp_check_handler); + unregister_external_irq(EXT_IRQ_SERVICE_SIG, sclp_check_handler); spin_unlock_irqrestore(&sclp_lock, flags); return rc; } @@ -1206,7 +1206,7 @@ sclp_init(void) if (rc) goto fail_init_state_uninitialized; /* Register interrupt handler */ - rc = register_external_interrupt(0x2401, sclp_interrupt_handler); + rc = register_external_irq(EXT_IRQ_SERVICE_SIG, sclp_interrupt_handler); if (rc) goto fail_unregister_reboot_notifier; sclp_init_state = sclp_init_state_initialized; diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index 1abd0db..a134965 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c @@ -477,7 +477,7 @@ static int __init kvm_devices_init(void) INIT_WORK(&hotplug_work, hotplug_devices); irq_subclass_register(IRQ_SUBCLASS_SERVICE_SIGNAL); - register_external_interrupt(0x2603, kvm_extint_handler); + register_external_irq(EXT_IRQ_CP_SERVICE, kvm_extint_handler); scan_devices(); return 0; -- cgit v1.1