diff options
-rw-r--r-- | arch/s390/boot/uv.c | 1 | ||||
-rw-r--r-- | arch/s390/include/asm/uv.h | 8 | ||||
-rw-r--r-- | arch/s390/kernel/uv.c | 10 | ||||
-rw-r--r-- | arch/s390/mm/fault.c | 26 |
4 files changed, 44 insertions, 1 deletions
diff --git a/arch/s390/boot/uv.c b/arch/s390/boot/uv.c index 82b99b916243..f6b0c4f43c99 100644 --- a/arch/s390/boot/uv.c +++ b/arch/s390/boot/uv.c @@ -36,6 +36,7 @@ void uv_query_info(void) uv_info.max_sec_stor_addr = ALIGN(uvcb.max_guest_stor_addr, PAGE_SIZE); uv_info.max_num_sec_conf = uvcb.max_num_sec_conf; uv_info.max_guest_cpu_id = uvcb.max_guest_cpu_id; + uv_info.uv_feature_indications = uvcb.uv_feature_indications; } #ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST diff --git a/arch/s390/include/asm/uv.h b/arch/s390/include/asm/uv.h index 7b98d4caee77..12c5f006c136 100644 --- a/arch/s390/include/asm/uv.h +++ b/arch/s390/include/asm/uv.h @@ -73,6 +73,10 @@ enum uv_cmds_inst { BIT_UVC_CMD_UNPIN_PAGE_SHARED = 22, }; +enum uv_feat_ind { + BIT_UV_FEAT_MISC = 0, +}; + struct uv_cb_header { u16 len; u16 cmd; /* Command Code */ @@ -97,7 +101,8 @@ struct uv_cb_qui { u64 max_guest_stor_addr; u8 reserved88[158 - 136]; u16 max_guest_cpu_id; - u8 reserveda0[200 - 160]; + u64 uv_feature_indications; + u8 reserveda0[200 - 168]; } __packed __aligned(8); /* Initialize Ultravisor */ @@ -274,6 +279,7 @@ struct uv_info { unsigned long max_sec_stor_addr; unsigned int max_num_sec_conf; unsigned short max_guest_cpu_id; + unsigned long uv_feature_indications; }; extern struct uv_info uv_info; diff --git a/arch/s390/kernel/uv.c b/arch/s390/kernel/uv.c index 6be2167943bb..aeb0a15bcbb7 100644 --- a/arch/s390/kernel/uv.c +++ b/arch/s390/kernel/uv.c @@ -358,6 +358,15 @@ static ssize_t uv_query_facilities(struct kobject *kobj, static struct kobj_attribute uv_query_facilities_attr = __ATTR(facilities, 0444, uv_query_facilities, NULL); +static ssize_t uv_query_feature_indications(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%lx\n", uv_info.uv_feature_indications); +} + +static struct kobj_attribute uv_query_feature_indications_attr = + __ATTR(feature_indications, 0444, uv_query_feature_indications, NULL); + static ssize_t uv_query_max_guest_cpus(struct kobject *kobj, struct kobj_attribute *attr, char *page) { @@ -390,6 +399,7 @@ static struct kobj_attribute uv_query_max_guest_addr_attr = static struct attribute *uv_query_attrs[] = { &uv_query_facilities_attr.attr, + &uv_query_feature_indications_attr.attr, &uv_query_max_guest_cpus_attr.attr, &uv_query_max_guest_vms_attr.attr, &uv_query_max_guest_addr_attr.attr, diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 8ae3dc5783fd..18b6212bd449 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -792,6 +792,32 @@ void do_secure_storage_access(struct pt_regs *regs) struct page *page; int rc; + /* + * bit 61 tells us if the address is valid, if it's not we + * have a major problem and should stop the kernel or send a + * SIGSEGV to the process. Unfortunately bit 61 is not + * reliable without the misc UV feature so we need to check + * for that as well. + */ + if (test_bit_inv(BIT_UV_FEAT_MISC, &uv_info.uv_feature_indications) && + !test_bit_inv(61, ®s->int_parm_long)) { + /* + * When this happens, userspace did something that it + * was not supposed to do, e.g. branching into secure + * memory. Trigger a segmentation fault. + */ + if (user_mode(regs)) { + send_sig(SIGSEGV, current, 0); + return; + } + + /* + * The kernel should never run into this case and we + * have no way out of this situation. + */ + panic("Unexpected PGM 0x3d with TEID bit 61=0"); + } + switch (get_fault_type(regs)) { case USER_FAULT: mm = current->mm; |