Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vfio-ccw: make it safe to access channel programs

When we get a solicited interrupt, the start function may have
been cleared by a csch, but we still have a channel program
structure allocated. Make it safe to call the cp accessors in
any case, so we can call them unconditionally.

While at it, also make sure that functions called from other parts
of the code return gracefully if the channel program structure
has not been initialized (even though that is a bug in the caller).

Reviewed-by: Eric Farman <farman@linux.ibm.com>
Reviewed-by: Farhan Ali <alifm@linux.ibm.com>
Signed-off-by: Cornelia Huck <cohuck@redhat.com>

+27 -1
+20 -1
drivers/s390/cio/vfio_ccw_cp.c
··· 362 362 struct ccwchain *chain, *temp; 363 363 int i; 364 364 365 + cp->initialized = false; 365 366 list_for_each_entry_safe(chain, temp, &cp->ccwchain_list, next) { 366 367 for (i = 0; i < chain->ch_len; i++) { 367 368 pfn_array_table_unpin_free(chain->ch_pat + i, ··· 733 732 */ 734 733 cp->orb.cmd.c64 = 1; 735 734 735 + if (!ret) 736 + cp->initialized = true; 737 + 736 738 return ret; 737 739 } 738 740 ··· 750 746 */ 751 747 void cp_free(struct channel_program *cp) 752 748 { 753 - cp_unpin_free(cp); 749 + if (cp->initialized) 750 + cp_unpin_free(cp); 754 751 } 755 752 756 753 /** ··· 796 791 struct ccwchain *chain; 797 792 int len, idx, ret; 798 793 794 + /* this is an error in the caller */ 795 + if (!cp->initialized) 796 + return -EINVAL; 797 + 799 798 list_for_each_entry(chain, &cp->ccwchain_list, next) { 800 799 len = chain->ch_len; 801 800 for (idx = 0; idx < len; idx++) { ··· 834 825 union orb *orb; 835 826 struct ccwchain *chain; 836 827 struct ccw1 *cpa; 828 + 829 + /* this is an error in the caller */ 830 + if (!cp->initialized) 831 + return NULL; 837 832 838 833 orb = &cp->orb; 839 834 ··· 875 862 u32 cpa = scsw->cmd.cpa; 876 863 u32 ccw_head; 877 864 865 + if (!cp->initialized) 866 + return; 867 + 878 868 /* 879 869 * LATER: 880 870 * For now, only update the cmd.cpa part. We may need to deal with ··· 913 897 { 914 898 struct ccwchain *chain; 915 899 int i; 900 + 901 + if (!cp->initialized) 902 + return false; 916 903 917 904 list_for_each_entry(chain, &cp->ccwchain_list, next) { 918 905 for (i = 0; i < chain->ch_len; i++)
+2
drivers/s390/cio/vfio_ccw_cp.h
··· 21 21 * @ccwchain_list: list head of ccwchains 22 22 * @orb: orb for the currently processed ssch request 23 23 * @mdev: the mediated device to perform page pinning/unpinning 24 + * @initialized: whether this instance is actually initialized 24 25 * 25 26 * @ccwchain_list is the head of a ccwchain list, that contents the 26 27 * translated result of the guest channel program that pointed out by ··· 31 30 struct list_head ccwchain_list; 32 31 union orb orb; 33 32 struct device *mdev; 33 + bool initialized; 34 34 }; 35 35 36 36 extern int cp_init(struct channel_program *cp, struct device *mdev,
+5
drivers/s390/cio/vfio_ccw_fsm.c
··· 31 31 private->state = VFIO_CCW_STATE_BUSY; 32 32 33 33 orb = cp_get_orb(&private->cp, (u32)(addr_t)sch, sch->lpm); 34 + if (!orb) { 35 + ret = -EIO; 36 + goto out; 37 + } 34 38 35 39 /* Issue "Start Subchannel" */ 36 40 ccode = ssch(sch->schid, orb); ··· 68 64 default: 69 65 ret = ccode; 70 66 } 67 + out: 71 68 spin_unlock_irqrestore(sch->lock, flags); 72 69 return ret; 73 70 }