From ccaf6553963bc6304d5820962a08a4397d0a2dc2 Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Fri, 13 Nov 2009 15:43:51 +0100 Subject: [PATCH 1/4] [S390] monreader: fix use after free bug with suspend/resume The monreader device driver doesn't set dev->driver_data to NULL after freeing the corresponding data structure. This leads to a use after free bug in the freeze/thaw suspend/resume functions after the device has been opened and closed once. Fix this by clearing dev->driver_data in the close() function. Signed-off-by: Gerald Schaefer Signed-off-by: Martin Schwidefsky --- drivers/s390/char/monreader.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index 89ece1c235aa..66e21dd23154 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -357,6 +357,7 @@ static int mon_close(struct inode *inode, struct file *filp) atomic_set(&monpriv->msglim_count, 0); monpriv->write_index = 0; monpriv->read_index = 0; + dev_set_drvdata(monreader_device, NULL); for (i = 0; i < MON_MSGLIM; i++) kfree(monpriv->msg_array[i]); From b89031e087a47819be48028e62cebade5f9fb75b Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 13 Nov 2009 15:43:52 +0100 Subject: [PATCH 2/4] [S390] reset cputime accounting after IPL from NSS After an IPL from NSS the uptime of the system is incorrect. The reason is that the startup code in head.S is not executed in case of an IPL from NSS. Due to that sched_clock_base_cc which is used to initialze wall_to_monotonic contains the time stamp when the NSS has been created instead of the time stamp of the system start. Reinitialize the cputime accounting values in create_kernel_nss after the SAVESYS CP command that created the NSS segment. Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/early.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index bf8b4ae7ff2d..e49e9e0c69fd 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -55,6 +55,7 @@ static void __init reset_tod_clock(void) disabled_wait(0); sched_clock_base_cc = TOD_UNIX_EPOCH; + S390_lowcore.last_update_clock = sched_clock_base_cc; } #ifdef CONFIG_SHARED_KERNEL @@ -167,6 +168,14 @@ static noinline __init void create_kernel_nss(void) return; } + /* re-initialize cputime accounting. */ + sched_clock_base_cc = get_clock(); + S390_lowcore.last_update_clock = sched_clock_base_cc; + S390_lowcore.last_update_timer = 0x7fffffffffffffffULL; + S390_lowcore.user_timer = 0; + S390_lowcore.system_timer = 0; + asm volatile("SPT 0(%0)" : : "a" (&S390_lowcore.last_update_timer)); + /* re-setup boot command line with new ipl vm parms */ ipl_update_parameters(); setup_boot_command_line(); From 8b94c1ed4d8232a452aa9db0f5ac9141d942590f Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 13 Nov 2009 15:43:53 +0100 Subject: [PATCH 3/4] [S390] sclp: undo quiesce handler override on resume In a system where the ctrl-alt-del init action initiated by signal quiesce suspends the machine the quiesce handler override for _machine_restart, _machine_halt and _machine_power_off needs to be undone, otherwise the override is still present in the resumed system. The next shutdown would then load the quiesce state psw instead of performing the correct shutdown action. Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp_quiesce.c | 48 +++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/drivers/s390/char/sclp_quiesce.c b/drivers/s390/char/sclp_quiesce.c index 84c191c1cd62..05909a7df8b3 100644 --- a/drivers/s390/char/sclp_quiesce.c +++ b/drivers/s390/char/sclp_quiesce.c @@ -20,9 +20,12 @@ #include "sclp.h" +static void (*old_machine_restart)(char *); +static void (*old_machine_halt)(void); +static void (*old_machine_power_off)(void); + /* Shutdown handler. Signal completion of shutdown by loading special PSW. */ -static void -do_machine_quiesce(void) +static void do_machine_quiesce(void) { psw_t quiesce_psw; @@ -33,23 +36,48 @@ do_machine_quiesce(void) } /* Handler for quiesce event. Start shutdown procedure. */ -static void -sclp_quiesce_handler(struct evbuf_header *evbuf) +static void sclp_quiesce_handler(struct evbuf_header *evbuf) { - _machine_restart = (void *) do_machine_quiesce; - _machine_halt = do_machine_quiesce; - _machine_power_off = do_machine_quiesce; + if (_machine_restart != (void *) do_machine_quiesce) { + old_machine_restart = _machine_restart; + old_machine_halt = _machine_halt; + old_machine_power_off = _machine_power_off; + _machine_restart = (void *) do_machine_quiesce; + _machine_halt = do_machine_quiesce; + _machine_power_off = do_machine_quiesce; + } ctrl_alt_del(); } +/* Undo machine restart/halt/power_off modification on resume */ +static void sclp_quiesce_pm_event(struct sclp_register *reg, + enum sclp_pm_event sclp_pm_event) +{ + switch (sclp_pm_event) { + case SCLP_PM_EVENT_RESTORE: + if (old_machine_restart) { + _machine_restart = old_machine_restart; + _machine_halt = old_machine_halt; + _machine_power_off = old_machine_power_off; + old_machine_restart = NULL; + old_machine_halt = NULL; + old_machine_power_off = NULL; + } + break; + case SCLP_PM_EVENT_FREEZE: + case SCLP_PM_EVENT_THAW: + break; + } +} + static struct sclp_register sclp_quiesce_event = { .receive_mask = EVTYP_SIGQUIESCE_MASK, - .receiver_fn = sclp_quiesce_handler + .receiver_fn = sclp_quiesce_handler, + .pm_event_fn = sclp_quiesce_pm_event }; /* Initialize quiesce driver. */ -static int __init -sclp_quiesce_init(void) +static int __init sclp_quiesce_init(void) { return sclp_register(&sclp_quiesce_event); } From bcc6525fb23d2cec7ffdf908d98826a66823bcb2 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 13 Nov 2009 15:43:54 +0100 Subject: [PATCH 4/4] [S390] s390: fix single stepping on svc0 On s390 there are two ways of specifying the system call number for the svc instruction. The standard way is to use the immediate field in the instruction (or to use EXecute for values unknown during assemble time). This can encode 256 system calls. The kernel ABI also allows to put the system call number in r1 and then execute svc 0 to enable system call numbers > 255. It turns out that single stepping svc 0 is broken, since the PER program check handler uses r1. We have to use a different register. Signed-off-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/entry.S | 8 ++++---- arch/s390/kernel/entry64.S | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index f43d2ee54464..48215d15762b 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -565,10 +565,10 @@ pgm_svcper: lh %r7,0x8a # get svc number from lowcore l %r9,__LC_THREAD_INFO # load pointer to thread_info struct TRACE_IRQS_OFF - l %r1,__TI_task(%r9) - mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID - mvc __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS - mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID + l %r8,__TI_task(%r9) + mvc __THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID + mvc __THREAD_per+__PER_address(4,%r8),__LC_PER_ADDRESS + mvc __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP TRACE_IRQS_ON stosm __SF_EMPTY(%r15),0x03 # reenable interrupts diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index a6f7b20df616..9aff1d449b6e 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -543,10 +543,10 @@ pgm_svcper: mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct - lg %r1,__TI_task(%r9) - mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID - mvc __THREAD_per+__PER_address(8,%r1),__LC_PER_ADDRESS - mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID + lg %r8,__TI_task(%r9) + mvc __THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID + mvc __THREAD_per+__PER_address(8,%r8),__LC_PER_ADDRESS + mvc __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID oi __TI_flags+7(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP TRACE_IRQS_ON stosm __SF_EMPTY(%r15),0x03 # reenable interrupts