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

of: overlay: rework overlay apply and remove kfree()s

Fix various kfree() issues related to of_overlay_apply().
- Double kfree() of fdt and tree when init_overlay_changeset()
returns an error.
- free_overlay_changeset() free the root of the unflattened
overlay (variable tree) instead of the memory that contains
the unflattened overlay.
- For the case of a failure during applying an overlay, move kfree()
of new_fdt and overlay_mem into free_overlay_changeset(), which
is called by the function that allocated them.
- For the case of removing an overlay, the kfree() of new_fdt and
overlay_mem remains in free_overlay_changeset().
- Check return value of of_fdt_unflatten_tree() for error instead
of checking the returned value of overlay_root.
- When storing pointers to allocated objects in ovcs, do so as
near to the allocation as possible instead of in deeply layered
function.

More clearly document policy related to lifetime of pointers into
overlay memory.

Double kfree()
Reported-by: Slawomir Stepien <slawomir.stepien@nokia.com>

Signed-off-by: Frank Rowand <frank.rowand@sony.com>
Signed-off-by: Rob Herring <robh@kernel.org>
Link: https://lore.kernel.org/r/20220420222505.928492-3-frowand.list@gmail.com

authored by

Frank Rowand and committed by
Rob Herring
067c0987 1e408966

+153 -143
+26 -4
Documentation/devicetree/overlay-notes.rst
··· 119 119 of_overlay_remove_all() which will remove every single one in the correct 120 120 order. 121 121 122 - In addition, there is the option to register notifiers that get called on 122 + There is the option to register notifiers that get called on 123 123 overlay operations. See of_overlay_notifier_register/unregister and 124 124 enum of_overlay_notify_action for details. 125 125 126 - Note that a notifier callback is not supposed to store pointers to a device 127 - tree node or its content beyond OF_OVERLAY_POST_REMOVE corresponding to the 128 - respective node it received. 126 + A notifier callback for OF_OVERLAY_PRE_APPLY, OF_OVERLAY_POST_APPLY, or 127 + OF_OVERLAY_PRE_REMOVE may store pointers to a device tree node in the overlay 128 + or its content but these pointers must not persist past the notifier callback 129 + for OF_OVERLAY_POST_REMOVE. The memory containing the overlay will be 130 + kfree()ed after OF_OVERLAY_POST_REMOVE notifiers are called. Note that the 131 + memory will be kfree()ed even if the notifier for OF_OVERLAY_POST_REMOVE 132 + returns an error. 133 + 134 + The changeset notifiers in drivers/of/dynamic.c are a second type of notifier 135 + that could be triggered by applying or removing an overlay. These notifiers 136 + are not allowed to store pointers to a device tree node in the overlay 137 + or its content. The overlay code does not protect against such pointers 138 + remaining active when the memory containing the overlay is freed as a result 139 + of removing the overlay. 140 + 141 + Any other code that retains a pointer to the overlay nodes or data is 142 + considered to be a bug because after removing the overlay the pointer 143 + will refer to freed memory. 144 + 145 + Users of overlays must be especially aware of the overall operations that 146 + occur on the system to ensure that other kernel code does not retain any 147 + pointers to the overlay nodes or data. Any example of an inadvertent use 148 + of such pointers is if a driver or subsystem module is loaded after an 149 + overlay has been applied, and the driver or subsystem scans the entire 150 + devicetree or a large portion of it, including the overlay nodes.
+125 -138
drivers/of/overlay.c
··· 58 58 * @id: changeset identifier 59 59 * @ovcs_list: list on which we are located 60 60 * @new_fdt: Memory allocated to hold unflattened aligned FDT 61 + * @overlay_mem: the memory chunk that contains @overlay_root 61 62 * @overlay_root: expanded device tree that contains the fragment nodes 63 + * @notify_state: most recent notify action used on overlay 62 64 * @count: count of fragment structures 63 65 * @fragments: fragment nodes in the overlay expanded device tree 64 66 * @symbols_fragment: last element of @fragments[] is the __symbols__ node ··· 70 68 int id; 71 69 struct list_head ovcs_list; 72 70 const void *new_fdt; 71 + const void *overlay_mem; 73 72 struct device_node *overlay_root; 73 + enum of_overlay_notify_action notify_state; 74 74 int count; 75 75 struct fragment *fragments; 76 76 bool symbols_fragment; ··· 119 115 mutex_unlock(&of_overlay_phandle_mutex); 120 116 } 121 117 122 - 123 118 static LIST_HEAD(ovcs_list); 124 119 static DEFINE_IDR(ovcs_idr); 125 120 ··· 164 161 { 165 162 struct of_overlay_notify_data nd; 166 163 int i, ret; 164 + 165 + ovcs->notify_state = action; 167 166 168 167 for (i = 0; i < ovcs->count; i++) { 169 168 struct fragment *fragment = &ovcs->fragments[i]; ··· 722 717 /** 723 718 * init_overlay_changeset() - initialize overlay changeset from overlay tree 724 719 * @ovcs: Overlay changeset to build 725 - * @new_fdt: Memory allocated to hold unflattened aligned FDT 726 - * @overlay_root: Contains the overlay fragments and overlay fixup nodes 727 720 * 728 721 * Initialize @ovcs. Populate @ovcs->fragments with node information from 729 722 * the top level of @overlay_root. The relevant top level nodes are the 730 723 * fragment nodes and the __symbols__ node. Any other top level node will 731 - * be ignored. 724 + * be ignored. Populate other @ovcs fields. 732 725 * 733 726 * Return: 0 on success, -ENOMEM if memory allocation failure, -EINVAL if error 734 - * detected in @overlay_root, or -ENOSPC if idr_alloc() error. 727 + * detected in @overlay_root. On error return, the caller of 728 + * init_overlay_changeset() must call free_overlay_changeset(). 735 729 */ 736 - static int init_overlay_changeset(struct overlay_changeset *ovcs, 737 - const void *new_fdt, struct device_node *overlay_root) 730 + static int init_overlay_changeset(struct overlay_changeset *ovcs) 738 731 { 739 732 struct device_node *node, *overlay_node; 740 733 struct fragment *fragment; 741 734 struct fragment *fragments; 742 - int cnt, id, ret; 735 + int cnt, ret; 736 + 737 + /* 738 + * None of the resources allocated by this function will be freed in 739 + * the error paths. Instead the caller of this function is required 740 + * to call free_overlay_changeset() (which will free the resources) 741 + * if error return. 742 + */ 743 743 744 744 /* 745 745 * Warn for some issues. Can not return -EINVAL for these until 746 746 * of_unittest_apply_overlay() is fixed to pass these checks. 747 747 */ 748 - if (!of_node_check_flag(overlay_root, OF_DYNAMIC)) 749 - pr_debug("%s() overlay_root is not dynamic\n", __func__); 748 + if (!of_node_check_flag(ovcs->overlay_root, OF_DYNAMIC)) 749 + pr_debug("%s() ovcs->overlay_root is not dynamic\n", __func__); 750 750 751 - if (!of_node_check_flag(overlay_root, OF_DETACHED)) 752 - pr_debug("%s() overlay_root is not detached\n", __func__); 751 + if (!of_node_check_flag(ovcs->overlay_root, OF_DETACHED)) 752 + pr_debug("%s() ovcs->overlay_root is not detached\n", __func__); 753 753 754 - if (!of_node_is_root(overlay_root)) 755 - pr_debug("%s() overlay_root is not root\n", __func__); 756 - 757 - ovcs->overlay_root = overlay_root; 758 - ovcs->new_fdt = new_fdt; 759 - 760 - INIT_LIST_HEAD(&ovcs->ovcs_list); 754 + if (!of_node_is_root(ovcs->overlay_root)) 755 + pr_debug("%s() ovcs->overlay_root is not root\n", __func__); 761 756 762 757 of_changeset_init(&ovcs->cset); 763 - 764 - id = idr_alloc(&ovcs_idr, ovcs, 1, 0, GFP_KERNEL); 765 - if (id <= 0) 766 - return id; 767 758 768 759 cnt = 0; 769 760 770 761 /* fragment nodes */ 771 - for_each_child_of_node(overlay_root, node) { 762 + for_each_child_of_node(ovcs->overlay_root, node) { 772 763 overlay_node = of_get_child_by_name(node, "__overlay__"); 773 764 if (overlay_node) { 774 765 cnt++; ··· 772 771 } 773 772 } 774 773 775 - node = of_get_child_by_name(overlay_root, "__symbols__"); 774 + node = of_get_child_by_name(ovcs->overlay_root, "__symbols__"); 776 775 if (node) { 777 776 cnt++; 778 777 of_node_put(node); ··· 781 780 fragments = kcalloc(cnt, sizeof(*fragments), GFP_KERNEL); 782 781 if (!fragments) { 783 782 ret = -ENOMEM; 784 - goto err_free_idr; 783 + goto err_out; 785 784 } 785 + ovcs->fragments = fragments; 786 786 787 787 cnt = 0; 788 - for_each_child_of_node(overlay_root, node) { 788 + for_each_child_of_node(ovcs->overlay_root, node) { 789 789 overlay_node = of_get_child_by_name(node, "__overlay__"); 790 790 if (!overlay_node) 791 791 continue; ··· 798 796 of_node_put(fragment->overlay); 799 797 ret = -EINVAL; 800 798 of_node_put(node); 801 - goto err_free_fragments; 799 + goto err_out; 802 800 } 803 801 804 802 cnt++; ··· 808 806 * if there is a symbols fragment in ovcs->fragments[i] it is 809 807 * the final element in the array 810 808 */ 811 - node = of_get_child_by_name(overlay_root, "__symbols__"); 809 + node = of_get_child_by_name(ovcs->overlay_root, "__symbols__"); 812 810 if (node) { 813 811 ovcs->symbols_fragment = 1; 814 812 fragment = &fragments[cnt]; ··· 818 816 if (!fragment->target) { 819 817 pr_err("symbols in overlay, but not in live tree\n"); 820 818 ret = -EINVAL; 821 - goto err_free_fragments; 819 + goto err_out; 822 820 } 823 821 824 822 cnt++; ··· 827 825 if (!cnt) { 828 826 pr_err("no fragments or symbols in overlay\n"); 829 827 ret = -EINVAL; 830 - goto err_free_fragments; 828 + goto err_out; 831 829 } 832 830 833 - ovcs->id = id; 834 831 ovcs->count = cnt; 835 - ovcs->fragments = fragments; 836 832 837 833 return 0; 838 834 839 - err_free_fragments: 840 - kfree(fragments); 841 - err_free_idr: 842 - idr_remove(&ovcs_idr, id); 843 - 835 + err_out: 844 836 pr_err("%s() failed, ret = %d\n", __func__, ret); 845 837 846 838 return ret; ··· 847 851 if (ovcs->cset.entries.next) 848 852 of_changeset_destroy(&ovcs->cset); 849 853 850 - if (ovcs->id) 854 + if (ovcs->id) { 851 855 idr_remove(&ovcs_idr, ovcs->id); 856 + list_del(&ovcs->ovcs_list); 857 + ovcs->id = 0; 858 + } 859 + 852 860 853 861 for (i = 0; i < ovcs->count; i++) { 854 862 of_node_put(ovcs->fragments[i].target); 855 863 of_node_put(ovcs->fragments[i].overlay); 856 864 } 857 865 kfree(ovcs->fragments); 866 + 858 867 /* 859 - * There should be no live pointers into ovcs->overlay_root and 868 + * There should be no live pointers into ovcs->overlay_mem and 860 869 * ovcs->new_fdt due to the policy that overlay notifiers are not 861 - * allowed to retain pointers into the overlay devicetree. 870 + * allowed to retain pointers into the overlay devicetree other 871 + * than during the window from OF_OVERLAY_PRE_APPLY overlay 872 + * notifiers until the OF_OVERLAY_POST_REMOVE overlay notifiers. 873 + * 874 + * A memory leak will occur here if within the window. 862 875 */ 863 - kfree(ovcs->overlay_root); 864 - kfree(ovcs->new_fdt); 876 + 877 + if (ovcs->notify_state == OF_OVERLAY_INIT || 878 + ovcs->notify_state == OF_OVERLAY_POST_REMOVE) { 879 + kfree(ovcs->overlay_mem); 880 + kfree(ovcs->new_fdt); 881 + } 865 882 kfree(ovcs); 866 883 } 867 884 ··· 882 873 * internal documentation 883 874 * 884 875 * of_overlay_apply() - Create and apply an overlay changeset 885 - * @new_fdt: Memory allocated to hold the aligned FDT 886 - * @overlay_root: Expanded overlay device tree 887 - * @ovcs_id: Pointer to overlay changeset id 876 + * @ovcs: overlay changeset 888 877 * 889 878 * Creates and applies an overlay changeset. 890 879 * 891 - * If an error occurs in a pre-apply notifier, then no changes are made 892 - * to the device tree. 893 - * 894 - * A non-zero return value will not have created the changeset if error is from: 895 - * - parameter checks 896 - * - building the changeset 897 - * - overlay changeset pre-apply notifier 898 - * 899 880 * If an error is returned by an overlay changeset pre-apply notifier 900 881 * then no further overlay changeset pre-apply notifier will be called. 901 - * 902 - * A non-zero return value will have created the changeset if error is from: 903 - * - overlay changeset entry notifier 904 - * - overlay changeset post-apply notifier 905 882 * 906 883 * If an error is returned by an overlay changeset post-apply notifier 907 884 * then no further overlay changeset post-apply notifier will be called. ··· 902 907 * following attempt to apply or remove an overlay changeset will be 903 908 * refused. 904 909 * 905 - * Returns 0 on success, or a negative error number. Overlay changeset 906 - * id is returned to *ovcs_id. 910 + * Returns 0 on success, or a negative error number. On error return, 911 + * the caller of of_overlay_apply() must call free_overlay_changeset(). 907 912 */ 908 913 909 - static int of_overlay_apply(const void *new_fdt, 910 - struct device_node *overlay_root, int *ovcs_id) 914 + static int of_overlay_apply(struct overlay_changeset *ovcs) 911 915 { 912 - struct overlay_changeset *ovcs; 913 916 int ret = 0, ret_revert, ret_tmp; 914 - 915 - /* 916 - * As of this point, fdt and tree belong to the overlay changeset. 917 - * overlay changeset code is responsible for freeing them. 918 - */ 919 917 920 918 if (devicetree_corrupt()) { 921 919 pr_err("devicetree state suspect, refuse to apply overlay\n"); 922 - kfree(new_fdt); 923 - kfree(overlay_root); 924 920 ret = -EBUSY; 925 921 goto out; 926 922 } 927 923 928 - ovcs = kzalloc(sizeof(*ovcs), GFP_KERNEL); 929 - if (!ovcs) { 930 - kfree(new_fdt); 931 - kfree(overlay_root); 932 - ret = -ENOMEM; 924 + ret = of_resolve_phandles(ovcs->overlay_root); 925 + if (ret) 933 926 goto out; 934 - } 935 927 936 - of_overlay_mutex_lock(); 937 - mutex_lock(&of_mutex); 938 - 939 - ret = of_resolve_phandles(overlay_root); 928 + ret = init_overlay_changeset(ovcs); 940 929 if (ret) 941 - goto err_free_tree; 930 + goto out; 942 931 943 - ret = init_overlay_changeset(ovcs, new_fdt, overlay_root); 944 - if (ret) 945 - goto err_free_tree; 946 - 947 - /* 948 - * After overlay_notify(), ovcs->overlay_root related pointers may have 949 - * leaked to drivers, so can not kfree() tree, aka ovcs->overlay_tree; 950 - * and can not free memory containing aligned fdt. The aligned fdt 951 - * is contained within the memory at ovcs->new_fdt, possibly at an 952 - * offset from ovcs->new_fdt. 953 - */ 954 932 ret = overlay_notify(ovcs, OF_OVERLAY_PRE_APPLY); 955 933 if (ret) { 956 934 pr_err("overlay changeset pre-apply notify error %d\n", ret); 957 - goto err_free_overlay_changeset; 935 + goto out; 958 936 } 959 937 960 938 ret = build_changeset(ovcs); 961 939 if (ret) 962 - goto err_free_overlay_changeset; 940 + goto out; 963 941 964 942 ret_revert = 0; 965 943 ret = __of_changeset_apply_entries(&ovcs->cset, &ret_revert); ··· 942 974 ret_revert); 943 975 devicetree_state_flags |= DTSF_APPLY_FAIL; 944 976 } 945 - goto err_free_overlay_changeset; 977 + goto out; 946 978 } 947 979 948 980 ret = __of_changeset_apply_notify(&ovcs->cset); 949 981 if (ret) 950 982 pr_err("overlay apply changeset entry notify error %d\n", ret); 951 983 /* notify failure is not fatal, continue */ 952 - 953 - list_add_tail(&ovcs->ovcs_list, &ovcs_list); 954 - *ovcs_id = ovcs->id; 955 984 956 985 ret_tmp = overlay_notify(ovcs, OF_OVERLAY_POST_APPLY); 957 986 if (ret_tmp) { ··· 958 993 ret = ret_tmp; 959 994 } 960 995 961 - goto out_unlock; 962 - 963 - err_free_tree: 964 - kfree(new_fdt); 965 - kfree(overlay_root); 966 - 967 - err_free_overlay_changeset: 968 - free_overlay_changeset(ovcs); 969 - 970 - out_unlock: 971 - mutex_unlock(&of_mutex); 972 - of_overlay_mutex_unlock(); 973 - 974 996 out: 975 997 pr_debug("%s() err=%d\n", __func__, ret); 976 998 ··· 965 1013 } 966 1014 967 1015 int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size, 968 - int *ovcs_id) 1016 + int *ret_ovcs_id) 969 1017 { 970 1018 void *new_fdt; 971 1019 void *new_fdt_align; 1020 + void *overlay_mem; 972 1021 int ret; 973 1022 u32 size; 974 - struct device_node *overlay_root = NULL; 1023 + struct overlay_changeset *ovcs; 975 1024 976 - *ovcs_id = 0; 1025 + *ret_ovcs_id = 0; 977 1026 978 1027 if (overlay_fdt_size < sizeof(struct fdt_header) || 979 1028 fdt_check_header(overlay_fdt)) { ··· 986 1033 if (overlay_fdt_size < size) 987 1034 return -EINVAL; 988 1035 1036 + ovcs = kzalloc(sizeof(*ovcs), GFP_KERNEL); 1037 + if (!ovcs) 1038 + return -ENOMEM; 1039 + 1040 + of_overlay_mutex_lock(); 1041 + mutex_lock(&of_mutex); 1042 + 1043 + /* 1044 + * ovcs->notify_state must be set to OF_OVERLAY_INIT before allocating 1045 + * ovcs resources, implicitly set by kzalloc() of ovcs 1046 + */ 1047 + 1048 + ovcs->id = idr_alloc(&ovcs_idr, ovcs, 1, 0, GFP_KERNEL); 1049 + if (ovcs->id <= 0) { 1050 + ret = ovcs->id; 1051 + goto err_free_ovcs; 1052 + } 1053 + 1054 + INIT_LIST_HEAD(&ovcs->ovcs_list); 1055 + list_add_tail(&ovcs->ovcs_list, &ovcs_list); 1056 + 989 1057 /* 990 1058 * Must create permanent copy of FDT because of_fdt_unflatten_tree() 991 1059 * will create pointers to the passed in FDT in the unflattened tree. 992 1060 */ 993 1061 new_fdt = kmalloc(size + FDT_ALIGN_SIZE, GFP_KERNEL); 994 - if (!new_fdt) 995 - return -ENOMEM; 1062 + if (!new_fdt) { 1063 + ret = -ENOMEM; 1064 + goto err_free_ovcs; 1065 + } 1066 + ovcs->new_fdt = new_fdt; 996 1067 997 1068 new_fdt_align = PTR_ALIGN(new_fdt, FDT_ALIGN_SIZE); 998 1069 memcpy(new_fdt_align, overlay_fdt, size); 999 1070 1000 - of_fdt_unflatten_tree(new_fdt_align, NULL, &overlay_root); 1001 - if (!overlay_root) { 1071 + overlay_mem = of_fdt_unflatten_tree(new_fdt_align, NULL, 1072 + &ovcs->overlay_root); 1073 + if (!overlay_mem) { 1002 1074 pr_err("unable to unflatten overlay_fdt\n"); 1003 1075 ret = -EINVAL; 1004 - goto out_free_new_fdt; 1076 + goto err_free_ovcs; 1005 1077 } 1078 + ovcs->overlay_mem = overlay_mem; 1006 1079 1007 - ret = of_overlay_apply(new_fdt, overlay_root, ovcs_id); 1008 - if (ret < 0) { 1009 - /* 1010 - * new_fdt and overlay_root now belong to the overlay 1011 - * changeset. 1012 - * overlay changeset code is responsible for freeing them. 1013 - */ 1014 - goto out; 1015 - } 1080 + ret = of_overlay_apply(ovcs); 1081 + if (ret < 0) 1082 + goto err_free_ovcs; 1083 + 1084 + mutex_unlock(&of_mutex); 1085 + of_overlay_mutex_unlock(); 1086 + 1087 + *ret_ovcs_id = ovcs->id; 1016 1088 1017 1089 return 0; 1018 1090 1091 + err_free_ovcs: 1092 + free_overlay_changeset(ovcs); 1019 1093 1020 - out_free_new_fdt: 1021 - kfree(new_fdt); 1094 + mutex_unlock(&of_mutex); 1095 + of_overlay_mutex_unlock(); 1022 1096 1023 - out: 1024 1097 return ret; 1025 1098 } 1026 1099 EXPORT_SYMBOL_GPL(of_overlay_fdt_apply); ··· 1183 1204 if (!ovcs) { 1184 1205 ret = -ENODEV; 1185 1206 pr_err("remove: Could not find overlay #%d\n", *ovcs_id); 1186 - goto out_unlock; 1207 + goto err_unlock; 1187 1208 } 1188 1209 1189 1210 if (!overlay_removal_is_ok(ovcs)) { 1190 1211 ret = -EBUSY; 1191 - goto out_unlock; 1212 + goto err_unlock; 1192 1213 } 1193 1214 1194 1215 ret = overlay_notify(ovcs, OF_OVERLAY_PRE_REMOVE); 1195 1216 if (ret) { 1196 1217 pr_err("overlay changeset pre-remove notify error %d\n", ret); 1197 - goto out_unlock; 1218 + goto err_unlock; 1198 1219 } 1199 - 1200 - list_del(&ovcs->ovcs_list); 1201 1220 1202 1221 ret_apply = 0; 1203 1222 ret = __of_changeset_revert_entries(&ovcs->cset, &ret_apply); 1204 1223 if (ret) { 1205 1224 if (ret_apply) 1206 1225 devicetree_state_flags |= DTSF_REVERT_FAIL; 1207 - goto out_unlock; 1226 + goto err_unlock; 1208 1227 } 1209 1228 1210 1229 ret = __of_changeset_revert_notify(&ovcs->cset); ··· 1212 1235 1213 1236 *ovcs_id = 0; 1214 1237 1238 + /* 1239 + * Note that the overlay memory will be kfree()ed by 1240 + * free_overlay_changeset() even if the notifier for 1241 + * OF_OVERLAY_POST_REMOVE returns an error. 1242 + */ 1215 1243 ret_tmp = overlay_notify(ovcs, OF_OVERLAY_POST_REMOVE); 1216 1244 if (ret_tmp) { 1217 1245 pr_err("overlay changeset post-remove notify error %d\n", ··· 1227 1245 1228 1246 free_overlay_changeset(ovcs); 1229 1247 1230 - out_unlock: 1248 + err_unlock: 1249 + /* 1250 + * If jumped over free_overlay_changeset(), then did not kfree() 1251 + * overlay related memory. This is a memory leak unless a subsequent 1252 + * of_overlay_remove() of this overlay is successful. 1253 + */ 1231 1254 mutex_unlock(&of_mutex); 1232 1255 1233 1256 out:
+2 -1
include/linux/of.h
··· 1543 1543 */ 1544 1544 1545 1545 enum of_overlay_notify_action { 1546 - OF_OVERLAY_PRE_APPLY = 0, 1546 + OF_OVERLAY_INIT = 0, /* kzalloc() of ovcs sets this value */ 1547 + OF_OVERLAY_PRE_APPLY, 1547 1548 OF_OVERLAY_POST_APPLY, 1548 1549 OF_OVERLAY_PRE_REMOVE, 1549 1550 OF_OVERLAY_POST_REMOVE,