From 03439e7d0a7ab3d77a74523b9ba64736c0fc28de Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 4 Dec 2013 14:29:11 +0100 Subject: s390/3270: fix use after free of tty3270_screen structure The deactivation and freeing of the tty view of the 3270 device can race with a tty3270_update invocation via the update timer. To fix this move the del_timer_sync call for the update timer from tty3270_free_view to tty3270_free prior to the tty3270_free_screen call. Signed-off-by: Martin Schwidefsky --- drivers/s390/char/tty3270.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/s390/char') diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 3f4ca4e09a4c..07cf182c18f9 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -125,10 +125,7 @@ static void tty3270_resize_work(struct work_struct *work); */ static void tty3270_set_timer(struct tty3270 *tp, int expires) { - if (expires == 0) - del_timer(&tp->timer); - else - mod_timer(&tp->timer, jiffies + expires); + mod_timer(&tp->timer, jiffies + expires); } /* @@ -744,7 +741,6 @@ tty3270_free_view(struct tty3270 *tp) { int pages; - del_timer_sync(&tp->timer); kbd_free(tp->kbd); raw3270_request_free(tp->kreset); raw3270_request_free(tp->read); @@ -877,6 +873,7 @@ tty3270_free(struct raw3270_view *view) { struct tty3270 *tp = container_of(view, struct tty3270, view); + del_timer_sync(&tp->timer); tty3270_free_screen(tp->screen, tp->view.rows); tty3270_free_view(tp); } -- cgit v1.2.3 From 333cce91f384409fb6a3e656dc11e21e872c5ea2 Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Thu, 5 Dec 2013 18:46:51 +0100 Subject: s390/sclp_early: Get rid of sclp_early_read_info_sccb_valid The early sclp detect functions gather the available SCLP facility information. The sclp_early_read_info_sccb_valid indicates whether the early sclp request was valid. However, one external reference to it checks for particular sclp facility bits and this should be sufficient. Another occurance is in the sclp_get_ipl_info() function that is called later. Because all information are available at the early stage, save the ipl information when detecting the sclp facilities. Hence, no more checks for sclp_early_read_info_sccb_valid are required. Signed-off-by: Hendrik Brueckner Reviewed-by: Michael Holzheu Reviewed-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp.h | 1 - drivers/s390/char/sclp_cmd.c | 2 -- drivers/s390/char/sclp_early.c | 36 ++++++++++++++++-------------------- 3 files changed, 16 insertions(+), 23 deletions(-) (limited to 'drivers/s390/char') diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 6fbe09686d18..fea76aed9eea 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -183,7 +183,6 @@ extern unsigned long sclp_console_full; extern u8 sclp_fac84; extern unsigned long long sclp_rzm; extern unsigned long long sclp_rnmax; -extern __initdata int sclp_early_read_info_sccb_valid; /* useful inlines */ diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index eaa21d542c5c..cb3c4e05a385 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -455,8 +455,6 @@ static int __init sclp_detect_standby_memory(void) if (OLDMEM_BASE) /* No standby memory in kdump mode */ return 0; - if (!sclp_early_read_info_sccb_valid) - return 0; if ((sclp_facilities & 0xe00000000000ULL) != 0xe00000000000ULL) return 0; rc = -ENOMEM; diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index 1465e9563101..e4e5b32c52f2 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -38,8 +38,8 @@ struct read_info_sccb { static __initdata struct read_info_sccb early_read_info_sccb; static __initdata char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE); static unsigned long sclp_hsa_size; +static struct sclp_ipl_info sclp_ipl_info; -__initdata int sclp_early_read_info_sccb_valid; u64 sclp_facilities; u8 sclp_fac84; unsigned long long sclp_rzm; @@ -63,10 +63,9 @@ out: return rc; } -static void __init sclp_read_info_early(void) +static int __init sclp_read_info_early(void) { - int rc; - int i; + int rc, i; struct read_info_sccb *sccb; sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED, SCLP_CMDW_READ_SCP_INFO}; @@ -83,21 +82,19 @@ static void __init sclp_read_info_early(void) if (rc) break; - if (sccb->header.response_code == 0x10) { - sclp_early_read_info_sccb_valid = 1; - break; - } + if (sccb->header.response_code == 0x10) + return 0; if (sccb->header.response_code != 0x1f0) break; } + return -EIO; } static void __init sclp_facilities_detect(void) { struct read_info_sccb *sccb; - sclp_read_info_early(); - if (!sclp_early_read_info_sccb_valid) + if (sclp_read_info_early()) return; sccb = &early_read_info_sccb; @@ -108,6 +105,12 @@ static void __init sclp_facilities_detect(void) sclp_rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2; sclp_rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2; sclp_rzm <<= 20; + + /* Save IPL information */ + sclp_ipl_info.is_valid = 1; + if (sccb->flags & 0x2) + sclp_ipl_info.has_dump = 1; + memcpy(&sclp_ipl_info.loadparm, &sccb->loadparm, LOADPARM_LEN); } bool __init sclp_has_linemode(void) @@ -146,19 +149,12 @@ unsigned long long sclp_get_rzm(void) /* * This function will be called after sclp_facilities_detect(), which gets - * called from early.c code. Therefore the sccb should have valid contents. + * called from early.c code. The sclp_facilities_detect() function retrieves + * and saves the IPL information. */ void __init sclp_get_ipl_info(struct sclp_ipl_info *info) { - struct read_info_sccb *sccb; - - if (!sclp_early_read_info_sccb_valid) - return; - sccb = &early_read_info_sccb; - info->is_valid = 1; - if (sccb->flags & 0x2) - info->has_dump = 1; - memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN); + *info = sclp_ipl_info; } static int __init sclp_cmd_early(sclp_cmdw_t cmd, void *sccb) -- cgit v1.2.3 From 56e57a84a7856130f45009ce1713dc8ec8e59887 Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Thu, 5 Dec 2013 19:03:50 +0100 Subject: s390/sclp_early: Replace early_read_info_sccb with sccb_early Replace early_read_info_sccb and use sccb_early instead. Also saves some memory. Signed-off-by: Hendrik Brueckner Reviewed-by: Michael Holzheu Reviewed-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp_early.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/s390/char') diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index e4e5b32c52f2..dc4ed04cbf50 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -35,8 +35,7 @@ struct read_info_sccb { u8 _reserved5[4096 - 112]; /* 112-4095 */ } __packed __aligned(PAGE_SIZE); -static __initdata struct read_info_sccb early_read_info_sccb; -static __initdata char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE); +static char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE) __initdata; static unsigned long sclp_hsa_size; static struct sclp_ipl_info sclp_ipl_info; @@ -63,14 +62,12 @@ out: return rc; } -static int __init sclp_read_info_early(void) +static int __init sclp_read_info_early(struct read_info_sccb *sccb) { int rc, i; - struct read_info_sccb *sccb; sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED, SCLP_CMDW_READ_SCP_INFO}; - sccb = &early_read_info_sccb; for (i = 0; i < ARRAY_SIZE(commands); i++) { do { memset(sccb, 0, sizeof(*sccb)); @@ -92,12 +89,11 @@ static int __init sclp_read_info_early(void) static void __init sclp_facilities_detect(void) { - struct read_info_sccb *sccb; + struct read_info_sccb *sccb = (void *) &sccb_early; - if (sclp_read_info_early()) + if (sclp_read_info_early(sccb)) return; - sccb = &early_read_info_sccb; sclp_facilities = sccb->facilities; sclp_fac84 = sccb->fac84; if (sccb->fac85 & 0x02) -- cgit v1.2.3 From 5d5de1a068efffb0dcc03235e6fa258201096f02 Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Thu, 5 Dec 2013 19:13:36 +0100 Subject: s390/sclp_early: Pass sccb pointer to every *_detect() function Add a sccb pointer parameter to *_detect() functions instead of accessing the global sccb_early variable directly. Signed-off-by: Hendrik Brueckner Reviewed-by: Michael Holzheu Reviewed-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp_early.c | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) (limited to 'drivers/s390/char') diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index dc4ed04cbf50..1af3555c096d 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -87,10 +87,8 @@ static int __init sclp_read_info_early(struct read_info_sccb *sccb) return -EIO; } -static void __init sclp_facilities_detect(void) +static void __init sclp_facilities_detect(struct read_info_sccb *sccb) { - struct read_info_sccb *sccb = (void *) &sccb_early; - if (sclp_read_info_early(sccb)) return; @@ -181,11 +179,10 @@ static void __init sccb_init_eq_size(struct sdias_sccb *sccb) sccb->evbuf.dbs = 1; } -static int __init sclp_set_event_mask(unsigned long receive_mask, +static int __init sclp_set_event_mask(struct init_sccb *sccb, + unsigned long receive_mask, unsigned long send_mask) { - struct init_sccb *sccb = (void *) &sccb_early; - memset(sccb, 0, sizeof(*sccb)); sccb->header.length = sizeof(*sccb); sccb->mask_length = sizeof(sccb_mask_t); @@ -194,10 +191,8 @@ static int __init sclp_set_event_mask(unsigned long receive_mask, return sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_MASK, sccb); } -static long __init sclp_hsa_size_init(void) +static long __init sclp_hsa_size_init(struct sdias_sccb *sccb) { - struct sdias_sccb *sccb = (void *) &sccb_early; - sccb_init_eq_size(sccb); if (sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_DATA, sccb)) return -EIO; @@ -206,10 +201,8 @@ static long __init sclp_hsa_size_init(void) return 0; } -static long __init sclp_hsa_copy_wait(void) +static long __init sclp_hsa_copy_wait(struct sccb_header *sccb) { - struct sccb_header *sccb = (void *) &sccb_early; - memset(sccb, 0, PAGE_SIZE); sccb->length = PAGE_SIZE; if (sclp_cmd_early(SCLP_CMDW_READ_EVENT_DATA, sccb)) @@ -222,25 +215,25 @@ unsigned long sclp_get_hsa_size(void) return sclp_hsa_size; } -static void __init sclp_hsa_size_detect(void) +static void __init sclp_hsa_size_detect(void *sccb) { long size; /* First try synchronous interface (LPAR) */ - if (sclp_set_event_mask(0, 0x40000010)) + if (sclp_set_event_mask(sccb, 0, 0x40000010)) return; - size = sclp_hsa_size_init(); + size = sclp_hsa_size_init(sccb); if (size < 0) return; if (size != 0) goto out; /* Then try asynchronous interface (z/VM) */ - if (sclp_set_event_mask(0x00000010, 0x40000010)) + if (sclp_set_event_mask(sccb, 0x00000010, 0x40000010)) return; - size = sclp_hsa_size_init(); + size = sclp_hsa_size_init(sccb); if (size < 0) return; - size = sclp_hsa_copy_wait(); + size = sclp_hsa_copy_wait(sccb); if (size < 0) return; out: @@ -249,7 +242,9 @@ out: void __init sclp_early_detect(void) { - sclp_facilities_detect(); - sclp_hsa_size_detect(); - sclp_set_event_mask(0, 0); + void *sccb = &sccb_early; + + sclp_facilities_detect(sccb); + sclp_hsa_size_detect(sccb); + sclp_set_event_mask(sccb, 0, 0); } -- cgit v1.2.3 From 52733e0152dad719ed6374b56fd1c33e784e44b3 Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Thu, 5 Dec 2013 19:28:39 +0100 Subject: s390/sclp_early: Add function to detect sclp console capabilities Add SCLP console detect functions to encapsulate detection of SCLP console capabilities, for example, VT220 support. Reuse the sclp_send/receive masks that were stored by the most recent sclp_set_event_mask() call to prevent unnecessary SCLP calls. Signed-off-by: Hendrik Brueckner Reviewed-by: Michael Holzheu Reviewed-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/sclp.h | 4 ++-- drivers/s390/char/sclp_early.c | 46 +++++++++++++++++++++++++++--------------- 2 files changed, 32 insertions(+), 18 deletions(-) (limited to 'drivers/s390/char') diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h index 2f390956c7c1..220e171413f8 100644 --- a/arch/s390/include/asm/sclp.h +++ b/arch/s390/include/asm/sclp.h @@ -52,8 +52,8 @@ int sclp_chp_configure(struct chp_id chpid); int sclp_chp_deconfigure(struct chp_id chpid); int sclp_chp_read_info(struct sclp_chp_info *info); void sclp_get_ipl_info(struct sclp_ipl_info *info); -bool sclp_has_linemode(void); -bool sclp_has_vt220(void); +bool __init sclp_has_linemode(void); +bool __init sclp_has_vt220(void); int sclp_pci_configure(u32 fid); int sclp_pci_deconfigure(u32 fid); int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode); diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index 1af3555c096d..82f2c389b4d1 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -36,6 +36,8 @@ struct read_info_sccb { } __packed __aligned(PAGE_SIZE); static char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE) __initdata; +static unsigned int sclp_con_has_vt220 __initdata; +static unsigned int sclp_con_has_linemode __initdata; static unsigned long sclp_hsa_size; static struct sclp_ipl_info sclp_ipl_info; @@ -109,26 +111,12 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb) bool __init sclp_has_linemode(void) { - struct init_sccb *sccb = (void *) &sccb_early; - - if (sccb->header.response_code != 0x20) - return 0; - if (!(sccb->sclp_send_mask & (EVTYP_OPCMD_MASK | EVTYP_PMSGCMD_MASK))) - return 0; - if (!(sccb->sclp_receive_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK))) - return 0; - return 1; + return !!sclp_con_has_linemode; } bool __init sclp_has_vt220(void) { - struct init_sccb *sccb = (void *) &sccb_early; - - if (sccb->header.response_code != 0x20) - return 0; - if (sccb->sclp_send_mask & EVTYP_VT220MSG_MASK) - return 1; - return 0; + return !!sclp_con_has_vt220; } unsigned long long sclp_get_rnmax(void) @@ -240,11 +228,37 @@ out: sclp_hsa_size = size; } +static unsigned int __init sclp_con_check_linemode(struct init_sccb *sccb) +{ + if (!(sccb->sclp_send_mask & (EVTYP_OPCMD_MASK | EVTYP_PMSGCMD_MASK))) + return 0; + if (!(sccb->sclp_receive_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK))) + return 0; + return 1; +} + +static void __init sclp_console_detect(struct init_sccb *sccb) +{ + if (sccb->header.response_code != 0x20) + return; + + if (sccb->sclp_send_mask & EVTYP_VT220MSG_MASK) + sclp_con_has_vt220 = 1; + + if (sclp_con_check_linemode(sccb)) + sclp_con_has_linemode = 1; +} + void __init sclp_early_detect(void) { void *sccb = &sccb_early; sclp_facilities_detect(sccb); sclp_hsa_size_detect(sccb); + + /* Turn off SCLP event notifications. Also save remote masks in the + * sccb. These are sufficient to detect sclp console capabilities. + */ sclp_set_event_mask(sccb, 0, 0); + sclp_console_detect(sccb); } -- cgit v1.2.3