Function kvm_gfn_to_hva_cache_init() is exported and used to init gfn to hva cache at various places, such as called in function kvm_pv_enable_async_pf(). However, this function directly tail calls function __kvm_gfn_to_hva_cache_init(), which assigns ghc->memslot to NULL and returns 0 for cache initialization of cross pages cache. This is unsafe as 0 typically means a successful return, but it actually fails to return a valid ghc->memslot. The functions call kvm_gfn_to_hva_cache_init(), such as kvm_lapic_set_vapicz_addr() do not make future checking on the ghc->memslot if kvm_gfn_to_hva_cache_init() returns a 0. Moreover, other developers may try to initialize a cache across pages by calling this function but fail with a success return value. This patch fixes this issue by explicitly restricting function kvm_gfn_to_hva_cache_init() to only accept address ranges within one page and adding comments to the function accordingly. Signed-off-by: Kele Huang <kele@xxxxxxxxxxxxxxx> --- virt/kvm/kvm_main.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 9230ebe1753f..6efe579f6b5f 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -3476,11 +3476,22 @@ static int __kvm_gfn_to_hva_cache_init(struct kvm_memslots *slots, return 0; } +/* + * Please note that this function only supports gfn_to_hva_cache + * initialization within a single page. + */ int kvm_gfn_to_hva_cache_init(struct kvm *kvm, struct gfn_to_hva_cache *ghc, gpa_t gpa, unsigned long len) { struct kvm_memslots *slots = kvm_memslots(kvm); - return __kvm_gfn_to_hva_cache_init(slots, ghc, gpa, len); + gfn_t start_gfn = gpa >> PAGE_SHIFT; + gfn_t end_gfn = (gpa + len - 1) >> PAGE_SHIFT; + gfn_t nr_pages_needed = end_gfn - start_gfn + 1; + + if (likely(nr_pages_needed == 1)) + return __kvm_gfn_to_hva_cache_init(slots, ghc, gpa, len); + else + return -EINVAL; } EXPORT_SYMBOL_GPL(kvm_gfn_to_hva_cache_init); -- 2.44.0