/* the bootdata_preserved fields come from ones in arch/s390/boot/uv.c */ int __bootdata_preserved(prot_virt_guest);
EXPORT_SYMBOL(prot_virt_guest);
/* * uv_info contains both host and guest information but it's currently only * expected to be used within modules if it's the KVM module or for * any PV guest module. * * The kernel itself will write these values once in uv_query_info() * and then make some of them readable via a sysfs interface.
*/ struct uv_info __bootdata_preserved(uv_info);
EXPORT_SYMBOL(uv_info);
int __bootdata_preserved(prot_virt_host);
EXPORT_SYMBOL(prot_virt_host);
if (uv_call(0, (uint64_t)&uvcb)) {
pr_err("Ultravisor init failed with rc: 0x%x rrc: 0%x\n",
uvcb.header.rc, uvcb.header.rrc); return -1;
} return 0;
}
void __init setup_uv(void)
{ void *uv_stor_base;
if (!is_prot_virt_host()) return;
uv_stor_base = memblock_alloc_try_nid(
uv_info.uv_base_stor_len, SZ_1M, SZ_2G,
MEMBLOCK_ALLOC_ACCESSIBLE, NUMA_NO_NODE); if (!uv_stor_base) {
pr_warn("Failed to reserve %lu bytes for ultravisor base storage\n",
uv_info.uv_base_stor_len); goto fail;
}
if (uv_init(__pa(uv_stor_base), uv_info.uv_base_stor_len)) {
memblock_free(uv_stor_base, uv_info.uv_base_stor_len); goto fail;
}
pr_info("Reserving %luMB as ultravisor base storage\n",
uv_info.uv_base_stor_len >> 20); return;
fail:
pr_info("Disabling support for protected virtualization");
prot_virt_host = 0;
}
/* * Requests the Ultravisor to pin the page in the shared state. This will * cause an intercept when the guest attempts to unshare the pinned page.
*/ int uv_pin_shared(unsignedlong paddr)
{ struct uv_cb_cfs uvcb = {
.header.cmd = UVC_CMD_PIN_PAGE_SHARED,
.header.len = sizeof(uvcb),
.paddr = paddr,
};
if (uv_call(0, (u64)&uvcb)) return -EINVAL; return 0;
}
EXPORT_SYMBOL_GPL(uv_pin_shared);
/* * Requests the Ultravisor to destroy a guest page and make it * accessible to the host. The destroy clears the page instead of * exporting. * * @paddr: Absolute host address of page to be destroyed
*/ staticint uv_destroy(unsignedlong paddr)
{ struct uv_cb_cfs uvcb = {
.header.cmd = UVC_CMD_DESTR_SEC_STOR,
.header.len = sizeof(uvcb),
.paddr = paddr
};
if (uv_call(0, (u64)&uvcb)) { /* * Older firmware uses 107/d as an indication of a non secure * page. Let us emulate the newer variant (no-op).
*/ if (uvcb.header.rc == 0x107 && uvcb.header.rrc == 0xd) return 0; return -EINVAL;
} return 0;
}
/* * The caller must already hold a reference to the folio
*/ int uv_destroy_folio(struct folio *folio)
{ int rc;
/* Large folios cannot be secure */ if (unlikely(folio_test_large(folio))) return 0;
/* * The present PTE still indirectly holds a folio reference through the mapping.
*/ int uv_destroy_pte(pte_t pte)
{
VM_WARN_ON(!pte_present(pte)); return uv_destroy_folio(pfn_folio(pte_pfn(pte)));
}
/* * Requests the Ultravisor to encrypt a guest page and make it * accessible to the host for paging (export). * * @paddr: Absolute host address of page to be exported
*/ int uv_convert_from_secure(unsignedlong paddr)
{ struct uv_cb_cfs uvcb = {
.header.cmd = UVC_CMD_CONV_FROM_SEC_STOR,
.header.len = sizeof(uvcb),
.paddr = paddr
};
if (uv_call(0, (u64)&uvcb)) return -EINVAL; return 0;
}
EXPORT_SYMBOL_GPL(uv_convert_from_secure);
/* * The caller must already hold a reference to the folio.
*/ int uv_convert_from_secure_folio(struct folio *folio)
{ int rc;
/* Large folios cannot be secure */ if (unlikely(folio_test_large(folio))) return 0;
/* * The present PTE still indirectly holds a folio reference through the mapping.
*/ int uv_convert_from_secure_pte(pte_t pte)
{
VM_WARN_ON(!pte_present(pte)); return uv_convert_from_secure_folio(pfn_folio(pte_pfn(pte)));
}
/** * should_export_before_import - Determine whether an export is needed * before an import-like operation * @uvcb: the Ultravisor control block of the UVC to be performed * @mm: the mm of the process * * Returns whether an export is needed before every import-like operation. * This is needed for shared pages, which don't trigger a secure storage * exception when accessed from a different guest. * * Although considered as one, the Unpin Page UVC is not an actual import, * so it is not affected. * * No export is needed also when there is only one protected VM, because the * page cannot belong to the wrong VM in that case (there is no "other VM" * it can belong to). * * Return: true if an export is needed before every import, otherwise false.
*/ staticbool should_export_before_import(struct uv_cb_header *uvcb, struct mm_struct *mm)
{ /* * The misc feature indicates, among other things, that importing a * shared page from a different protected VM will automatically also * transfer its ownership.
*/ if (uv_has_feature(BIT_UV_FEAT_MISC)) returnfalse; if (uvcb->cmd == UVC_CMD_UNPIN_PAGE_SHARED) returnfalse; return atomic_read(&mm->context.protected_count) > 1;
}
/* * Calculate the expected ref_count for a folio that would otherwise have no * further pins. This was cribbed from similar functions in other places in * the kernel, but with some slight modifications. We know that a secure * folio can not be a large folio, for example.
*/ staticint expected_folio_refs(struct folio *folio)
{ int res;
res = folio_mapcount(folio); if (folio_test_swapcache(folio)) {
res++;
} elseif (folio_mapping(folio)) {
res++; if (folio->private)
res++;
} return res;
}
/** * __make_folio_secure() - make a folio secure * @folio: the folio to make secure * @uvcb: the uvcb that describes the UVC to be used * * The folio @folio will be made secure if possible, @uvcb will be passed * as-is to the UVC. * * Return: 0 on success; * -EBUSY if the folio is in writeback or has too many references; * -EAGAIN if the UVC needs to be attempted again; * -ENXIO if the address is not mapped; * -EINVAL if the UVC failed for other reasons. * * Context: The caller must hold exactly one extra reference on the folio * (it's the same logic as split_folio()), and the folio must be * locked.
*/ staticint __make_folio_secure(struct folio *folio, struct uv_cb_header *uvcb)
{ int expected, cc = 0;
if (folio_test_writeback(folio)) return -EBUSY;
expected = expected_folio_refs(folio) + 1; if (!folio_ref_freeze(folio, expected)) return -EBUSY;
set_bit(PG_arch_1, &folio->flags); /* * If the UVC does not succeed or fail immediately, we don't want to * loop for long, or we might get stall notifications. * On the other hand, this is a complex scenario and we are holding a lot of * locks, so we can't easily sleep and reschedule. We try only once, * and if the UVC returned busy or partial completion, we return * -EAGAIN and we let the callers deal with it.
*/
cc = __uv_call(0, (u64)uvcb);
folio_ref_unfreeze(folio, expected); /* * Return -ENXIO if the folio was not mapped, -EINVAL for other errors. * If busy or partially completed, return -EAGAIN.
*/ if (cc == UVC_CC_OK) return 0; elseif (cc == UVC_CC_BUSY || cc == UVC_CC_PARTIAL) return -EAGAIN; return uvcb->rc == 0x10a ? -ENXIO : -EINVAL;
}
if (!folio_trylock(folio)) return -EAGAIN; if (should_export_before_import(uvcb, mm))
uv_convert_from_secure(folio_to_phys(folio));
rc = __make_folio_secure(folio, uvcb);
folio_unlock(folio);
return rc;
}
/** * s390_wiggle_split_folio() - try to drain extra references to a folio and * split the folio if it is large. * @mm: the mm containing the folio to work on * @folio: the folio * * Context: Must be called while holding an extra reference to the folio; * the mm lock should not be held. * Return: 0 if the operation was successful; * -EAGAIN if splitting the large folio was not successful, * but another attempt can be made; * -EINVAL in case of other folio splitting errors. See split_folio().
*/ staticint s390_wiggle_split_folio(struct mm_struct *mm, struct folio *folio)
{ int rc, tried_splits;
/* * Splitting with -EBUSY can fail for various reasons, but we * have to handle one case explicitly for now: some mappings * don't allow for splitting dirty folios; writeback will * mark them clean again, including marking all page table * entries mapping the folio read-only, to catch future write * attempts. * * While the system should be writing back dirty folios in the * background, we obtained this folio by looking up a writable * page table entry. On these problematic mappings, writable * page table entries imply dirty folios, preventing the * split in the first place. * * To prevent a livelock when trigger writeback manually and * letting the caller look up the folio again in the page * table (turning it dirty), immediately try to split again. * * This is only a problem for some mappings (e.g., XFS); * mappings that do not support writeback (e.g., shmem) do not * apply.
*/ if (!folio_test_dirty(folio) || folio_test_anon(folio) ||
!folio->mapping || !mapping_can_writeback(folio->mapping)) {
folio_unlock(folio); break;
}
/* * Ideally, we'd only trigger writeback on this exact folio. But * there is no easy way to do that, so we'll stabilize the * mapping while we still hold the folio lock, so we can drop * the folio lock to trigger writeback on the range currently * covered by the folio instead.
*/
mapping = folio->mapping;
lstart = folio_pos(folio);
lend = lstart + folio_size(folio) - 1;
inode = igrab(mapping->host);
folio_unlock(folio);
folio_get(folio); /* * Secure pages cannot be huge and userspace should not combine both. * In case userspace does it anyway this will result in an -EFAULT for * the unpack. The guest is thus never reaching secure mode. * If userspace plays dirty tricks and decides to map huge pages at a * later point in time, it will receive a segmentation fault or * KVM_RUN will return -EFAULT.
*/ if (folio_test_hugetlb(folio))
rc = -EFAULT; elseif (folio_test_large(folio))
rc = -E2BIG; elseif (!pte_write(fw.pte) || (pte_val(fw.pte) & _PAGE_INVALID))
rc = -ENXIO; else
rc = make_folio_secure(mm, folio, uvcb);
folio_walk_end(&fw, vma);
mmap_read_unlock(mm);
if (rc == -E2BIG || rc == -EBUSY) {
rc = s390_wiggle_split_folio(mm, folio); if (!rc)
rc = -EAGAIN;
}
folio_put(folio);
return rc;
}
EXPORT_SYMBOL_GPL(make_hva_secure);
/* * To be called with the folio locked or with an extra reference! This will * prevent kvm_s390_pv_make_secure() from touching the folio concurrently. * Having 2 parallel arch_make_folio_accessible is fine, as the UV calls will * become a no-op if the folio is already exported.
*/ int arch_make_folio_accessible(struct folio *folio)
{ int rc = 0;
/* Large folios cannot be secure */ if (unlikely(folio_test_large(folio))) return 0;
/* * PG_arch_1 is used in 2 places: * 1. for storage keys of hugetlb folios and KVM * 2. As an indication that this small folio might be secure. This can * overindicate, e.g. we set the bit before calling * convert_to_secure. * As secure pages are never large folios, both variants can co-exists.
*/ if (!test_bit(PG_arch_1, &folio->flags)) return 0;
rc = sysfs_create_group(&kset->kobj, grp); if (rc)
kset_unregister(kset); return rc;
}
staticint __init uv_sysfs_init(void)
{ int rc = -ENOMEM;
if (!test_facility(158)) return 0;
uv_kobj = kobject_create_and_add("uv", firmware_kobj); if (!uv_kobj) return -ENOMEM;
rc = sysfs_create_files(uv_kobj, uv_prot_virt_attrs); if (rc) goto out_kobj;
rc = uv_sysfs_dir_init(&uv_query_attr_group, &uv_query_kset, "query"); if (rc) goto out_ind_files;
/* Get installed key hashes if available, ignore any errors */ if (test_bit_inv(BIT_UVC_CMD_QUERY_KEYS, uv_info.inst_calls_list))
uv_sysfs_dir_init(&uv_keys_attr_group, &uv_keys_kset, "keys");
/* * Locate a secret in the list by its id. * @secret_id: search pattern. * @list: ephemeral buffer space * @secret: output data, containing the secret's metadata. * * Search for a secret with the given secret_id in the Ultravisor secret store. * * Context: might sleep.
*/ staticint find_secret_in_page(const u8 secret_id[UV_SECRET_ID_LEN], conststruct uv_secret_list *list, struct uv_secret_list_item_hdr *secret)
{
u16 i;
for (i = 0; i < list->total_num_secrets; i++) { if (memcmp(secret_id, list->secrets[i].id, UV_SECRET_ID_LEN) == 0) {
*secret = list->secrets[i].hdr; return 0;
}
} return -ENOENT;
}
/* * Do the actual search for `uv_get_secret_metadata`. * @secret_id: search pattern. * @list: ephemeral buffer space * @secret: output data, containing the secret's metadata. * * Context: might sleep.
*/ int uv_find_secret(const u8 secret_id[UV_SECRET_ID_LEN], struct uv_secret_list *list, struct uv_secret_list_item_hdr *secret)
{
u16 start_idx = 0;
u16 list_rc; int ret;
do {
uv_list_secrets(list, start_idx, &list_rc, NULL); if (list_rc != UVC_RC_EXECUTED && list_rc != UVC_RC_MORE_DATA) { if (list_rc == UVC_RC_INV_CMD) return -ENODEV; else return -EIO;
}
ret = find_secret_in_page(secret_id, list, secret); if (ret == 0) return ret;
start_idx = list->next_secret_idx;
} while (list_rc == UVC_RC_MORE_DATA && start_idx < list->next_secret_idx);
/** * uv_retrieve_secret() - get the secret value for the secret index. * @secret_idx: Secret index for which the secret should be retrieved. * @buf: Buffer to store retrieved secret. * @buf_size: Size of the buffer. The correct buffer size is reported as part of * the result from `uv_get_secret_metadata`. * * Calls the Retrieve Secret UVC and translates the UV return code into an errno. * * Context: might sleep. * * Return: * * %0 - Entry found; buffer contains a valid secret. * * %ENOENT: - No entry found or secret at the index is non-retrievable. * * %ENODEV: - Not supported: UV not available or command not available. * * %EINVAL: - Buffer too small for content. * * %EIO: - Other unexpected UV error.
*/ int uv_retrieve_secret(u16 secret_idx, u8 *buf, size_t buf_size)
{ struct uv_cb_retr_secr uvcb = {
.header.len = sizeof(uvcb),
.header.cmd = UVC_CMD_RETR_SECRET,
.secret_idx = secret_idx,
.buf_addr = (u64)buf,
.buf_size = buf_size,
};
uv_call_sched(0, (u64)&uvcb);
switch (uvcb.header.rc) { case UVC_RC_EXECUTED: return 0; case UVC_RC_INV_CMD: return -ENODEV; case UVC_RC_RETR_SECR_STORE_EMPTY: case UVC_RC_RETR_SECR_INV_SECRET: case UVC_RC_RETR_SECR_INV_IDX: return -ENOENT; case UVC_RC_RETR_SECR_BUF_SMALL: return -EINVAL; default: return -EIO;
}
}
EXPORT_SYMBOL_GPL(uv_retrieve_secret);
Messung V0.5
¤ Dauer der Verarbeitung: 0.41 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.