diff options
Diffstat (limited to 'fs/partitions/ldm.c')
-rw-r--r-- | fs/partitions/ldm.c | 137 |
1 files changed, 92 insertions, 45 deletions
diff --git a/fs/partitions/ldm.c b/fs/partitions/ldm.c index 99873a2b4cbc..e7dd1d4e3473 100644 --- a/fs/partitions/ldm.c +++ b/fs/partitions/ldm.c | |||
@@ -677,15 +677,24 @@ static bool ldm_create_data_partitions (struct parsed_partitions *pp, | |||
677 | * Return: -1 Error, the calculated offset exceeded the size of the buffer | 677 | * Return: -1 Error, the calculated offset exceeded the size of the buffer |
678 | * n OK, a range-checked offset into buffer | 678 | * n OK, a range-checked offset into buffer |
679 | */ | 679 | */ |
680 | static int ldm_relative (const u8 *buffer, int buflen, int base, int offset) | 680 | static int ldm_relative(const u8 *buffer, int buflen, int base, int offset) |
681 | { | 681 | { |
682 | 682 | ||
683 | base += offset; | 683 | base += offset; |
684 | if ((!buffer) || (offset < 0) || (base > buflen)) | 684 | if (!buffer || offset < 0 || base > buflen) { |
685 | if (!buffer) | ||
686 | ldm_error("!buffer"); | ||
687 | if (offset < 0) | ||
688 | ldm_error("offset (%d) < 0", offset); | ||
689 | if (base > buflen) | ||
690 | ldm_error("base (%d) > buflen (%d)", base, buflen); | ||
685 | return -1; | 691 | return -1; |
686 | if ((base + buffer[base]) >= buflen) | 692 | } |
693 | if (base + buffer[base] >= buflen) { | ||
694 | ldm_error("base (%d) + buffer[base] (%d) >= buflen (%d)", base, | ||
695 | buffer[base], buflen); | ||
687 | return -1; | 696 | return -1; |
688 | 697 | } | |
689 | return buffer[base] + offset + 1; | 698 | return buffer[base] + offset + 1; |
690 | } | 699 | } |
691 | 700 | ||
@@ -1054,60 +1063,98 @@ static bool ldm_parse_prt3(const u8 *buffer, int buflen, struct vblk *vb) | |||
1054 | * Return: 'true' @vb contains a Volume VBLK | 1063 | * Return: 'true' @vb contains a Volume VBLK |
1055 | * 'false' @vb contents are not defined | 1064 | * 'false' @vb contents are not defined |
1056 | */ | 1065 | */ |
1057 | static bool ldm_parse_vol5 (const u8 *buffer, int buflen, struct vblk *vb) | 1066 | static bool ldm_parse_vol5(const u8 *buffer, int buflen, struct vblk *vb) |
1058 | { | 1067 | { |
1059 | int r_objid, r_name, r_vtype, r_child, r_size, r_id1, r_id2, r_size2; | 1068 | int r_objid, r_name, r_vtype, r_disable_drive_letter, r_child, r_size; |
1060 | int r_drive, len; | 1069 | int r_id1, r_id2, r_size2, r_drive, len; |
1061 | struct vblk_volu *volu; | 1070 | struct vblk_volu *volu; |
1062 | 1071 | ||
1063 | BUG_ON (!buffer || !vb); | 1072 | BUG_ON(!buffer || !vb); |
1064 | 1073 | r_objid = ldm_relative(buffer, buflen, 0x18, 0); | |
1065 | r_objid = ldm_relative (buffer, buflen, 0x18, 0); | 1074 | if (r_objid < 0) { |
1066 | r_name = ldm_relative (buffer, buflen, 0x18, r_objid); | 1075 | ldm_error("r_objid %d < 0", r_objid); |
1067 | r_vtype = ldm_relative (buffer, buflen, 0x18, r_name); | 1076 | return false; |
1068 | r_child = ldm_relative (buffer, buflen, 0x2E, r_vtype); | 1077 | } |
1069 | r_size = ldm_relative (buffer, buflen, 0x3E, r_child); | 1078 | r_name = ldm_relative(buffer, buflen, 0x18, r_objid); |
1070 | 1079 | if (r_name < 0) { | |
1071 | if (buffer[0x12] & VBLK_FLAG_VOLU_ID1) | 1080 | ldm_error("r_name %d < 0", r_name); |
1072 | r_id1 = ldm_relative (buffer, buflen, 0x53, r_size); | 1081 | return false; |
1073 | else | 1082 | } |
1083 | r_vtype = ldm_relative(buffer, buflen, 0x18, r_name); | ||
1084 | if (r_vtype < 0) { | ||
1085 | ldm_error("r_vtype %d < 0", r_vtype); | ||
1086 | return false; | ||
1087 | } | ||
1088 | r_disable_drive_letter = ldm_relative(buffer, buflen, 0x18, r_vtype); | ||
1089 | if (r_disable_drive_letter < 0) { | ||
1090 | ldm_error("r_disable_drive_letter %d < 0", | ||
1091 | r_disable_drive_letter); | ||
1092 | return false; | ||
1093 | } | ||
1094 | r_child = ldm_relative(buffer, buflen, 0x2D, r_disable_drive_letter); | ||
1095 | if (r_child < 0) { | ||
1096 | ldm_error("r_child %d < 0", r_child); | ||
1097 | return false; | ||
1098 | } | ||
1099 | r_size = ldm_relative(buffer, buflen, 0x3D, r_child); | ||
1100 | if (r_size < 0) { | ||
1101 | ldm_error("r_size %d < 0", r_size); | ||
1102 | return false; | ||
1103 | } | ||
1104 | if (buffer[0x12] & VBLK_FLAG_VOLU_ID1) { | ||
1105 | r_id1 = ldm_relative(buffer, buflen, 0x52, r_size); | ||
1106 | if (r_id1 < 0) { | ||
1107 | ldm_error("r_id1 %d < 0", r_id1); | ||
1108 | return false; | ||
1109 | } | ||
1110 | } else | ||
1074 | r_id1 = r_size; | 1111 | r_id1 = r_size; |
1075 | 1112 | if (buffer[0x12] & VBLK_FLAG_VOLU_ID2) { | |
1076 | if (buffer[0x12] & VBLK_FLAG_VOLU_ID2) | 1113 | r_id2 = ldm_relative(buffer, buflen, 0x52, r_id1); |
1077 | r_id2 = ldm_relative (buffer, buflen, 0x53, r_id1); | 1114 | if (r_id2 < 0) { |
1078 | else | 1115 | ldm_error("r_id2 %d < 0", r_id2); |
1116 | return false; | ||
1117 | } | ||
1118 | } else | ||
1079 | r_id2 = r_id1; | 1119 | r_id2 = r_id1; |
1080 | 1120 | if (buffer[0x12] & VBLK_FLAG_VOLU_SIZE) { | |
1081 | if (buffer[0x12] & VBLK_FLAG_VOLU_SIZE) | 1121 | r_size2 = ldm_relative(buffer, buflen, 0x52, r_id2); |
1082 | r_size2 = ldm_relative (buffer, buflen, 0x53, r_id2); | 1122 | if (r_size2 < 0) { |
1083 | else | 1123 | ldm_error("r_size2 %d < 0", r_size2); |
1124 | return false; | ||
1125 | } | ||
1126 | } else | ||
1084 | r_size2 = r_id2; | 1127 | r_size2 = r_id2; |
1085 | 1128 | if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) { | |
1086 | if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) | 1129 | r_drive = ldm_relative(buffer, buflen, 0x52, r_size2); |
1087 | r_drive = ldm_relative (buffer, buflen, 0x53, r_size2); | 1130 | if (r_drive < 0) { |
1088 | else | 1131 | ldm_error("r_drive %d < 0", r_drive); |
1132 | return false; | ||
1133 | } | ||
1134 | } else | ||
1089 | r_drive = r_size2; | 1135 | r_drive = r_size2; |
1090 | |||
1091 | len = r_drive; | 1136 | len = r_drive; |
1092 | if (len < 0) | 1137 | if (len < 0) { |
1138 | ldm_error("len %d < 0", len); | ||
1093 | return false; | 1139 | return false; |
1094 | 1140 | } | |
1095 | len += VBLK_SIZE_VOL5; | 1141 | len += VBLK_SIZE_VOL5; |
1096 | if (len != BE32 (buffer + 0x14)) | 1142 | if (len > BE32(buffer + 0x14)) { |
1143 | ldm_error("len %d > BE32(buffer + 0x14) %d", len, | ||
1144 | BE32(buffer + 0x14)); | ||
1097 | return false; | 1145 | return false; |
1098 | 1146 | } | |
1099 | volu = &vb->vblk.volu; | 1147 | volu = &vb->vblk.volu; |
1100 | 1148 | ldm_get_vstr(buffer + 0x18 + r_name, volu->volume_type, | |
1101 | ldm_get_vstr (buffer + 0x18 + r_name, volu->volume_type, | 1149 | sizeof(volu->volume_type)); |
1102 | sizeof (volu->volume_type)); | 1150 | memcpy(volu->volume_state, buffer + 0x18 + r_disable_drive_letter, |
1103 | memcpy (volu->volume_state, buffer + 0x19 + r_vtype, | 1151 | sizeof(volu->volume_state)); |
1104 | sizeof (volu->volume_state)); | 1152 | volu->size = ldm_get_vnum(buffer + 0x3D + r_child); |
1105 | volu->size = ldm_get_vnum (buffer + 0x3E + r_child); | 1153 | volu->partition_type = buffer[0x41 + r_size]; |
1106 | volu->partition_type = buffer[0x42 + r_size]; | 1154 | memcpy(volu->guid, buffer + 0x42 + r_size, sizeof(volu->guid)); |
1107 | memcpy (volu->guid, buffer + 0x43 + r_size, sizeof (volu->guid)); | ||
1108 | if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) { | 1155 | if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) { |
1109 | ldm_get_vstr (buffer + 0x53 + r_size, volu->drive_hint, | 1156 | ldm_get_vstr(buffer + 0x52 + r_size, volu->drive_hint, |
1110 | sizeof (volu->drive_hint)); | 1157 | sizeof(volu->drive_hint)); |
1111 | } | 1158 | } |
1112 | return true; | 1159 | return true; |
1113 | } | 1160 | } |