@@ -194,12 +194,19 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type)
194194 record_header = (void * )subtable_header + offset ;
195195 offset += record_header -> length ;
196196
197+ if (!record_header -> length ) {
198+ pr_err (FW_BUG "Zero-length record found in FPTD.\n" );
199+ result = - EINVAL ;
200+ goto err ;
201+ }
202+
197203 switch (record_header -> type ) {
198204 case RECORD_S3_RESUME :
199205 if (subtable_type != SUBTABLE_S3PT ) {
200206 pr_err (FW_BUG "Invalid record %d for subtable %s\n" ,
201207 record_header -> type , signature );
202- return - EINVAL ;
208+ result = - EINVAL ;
209+ goto err ;
203210 }
204211 if (record_resume ) {
205212 pr_err ("Duplicate resume performance record found.\n" );
@@ -208,7 +215,7 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type)
208215 record_resume = (struct resume_performance_record * )record_header ;
209216 result = sysfs_create_group (fpdt_kobj , & resume_attr_group );
210217 if (result )
211- return result ;
218+ goto err ;
212219 break ;
213220 case RECORD_S3_SUSPEND :
214221 if (subtable_type != SUBTABLE_S3PT ) {
@@ -223,13 +230,14 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type)
223230 record_suspend = (struct suspend_performance_record * )record_header ;
224231 result = sysfs_create_group (fpdt_kobj , & suspend_attr_group );
225232 if (result )
226- return result ;
233+ goto err ;
227234 break ;
228235 case RECORD_BOOT :
229236 if (subtable_type != SUBTABLE_FBPT ) {
230237 pr_err (FW_BUG "Invalid %d for subtable %s\n" ,
231238 record_header -> type , signature );
232- return - EINVAL ;
239+ result = - EINVAL ;
240+ goto err ;
233241 }
234242 if (record_boot ) {
235243 pr_err ("Duplicate boot performance record found.\n" );
@@ -238,7 +246,7 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type)
238246 record_boot = (struct boot_performance_record * )record_header ;
239247 result = sysfs_create_group (fpdt_kobj , & boot_attr_group );
240248 if (result )
241- return result ;
249+ goto err ;
242250 break ;
243251
244252 default :
@@ -247,6 +255,18 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type)
247255 }
248256 }
249257 return 0 ;
258+
259+ err :
260+ if (record_boot )
261+ sysfs_remove_group (fpdt_kobj , & boot_attr_group );
262+
263+ if (record_suspend )
264+ sysfs_remove_group (fpdt_kobj , & suspend_attr_group );
265+
266+ if (record_resume )
267+ sysfs_remove_group (fpdt_kobj , & resume_attr_group );
268+
269+ return result ;
250270}
251271
252272static int __init acpi_init_fpdt (void )
@@ -255,6 +275,7 @@ static int __init acpi_init_fpdt(void)
255275 struct acpi_table_header * header ;
256276 struct fpdt_subtable_entry * subtable ;
257277 u32 offset = sizeof (* header );
278+ int result ;
258279
259280 status = acpi_get_table (ACPI_SIG_FPDT , 0 , & header );
260281
@@ -263,17 +284,19 @@ static int __init acpi_init_fpdt(void)
263284
264285 fpdt_kobj = kobject_create_and_add ("fpdt" , acpi_kobj );
265286 if (!fpdt_kobj ) {
266- acpi_put_table ( header ) ;
267- return - ENOMEM ;
287+ result = - ENOMEM ;
288+ goto err_nomem ;
268289 }
269290
270291 while (offset < header -> length ) {
271292 subtable = (void * )header + offset ;
272293 switch (subtable -> type ) {
273294 case SUBTABLE_FBPT :
274295 case SUBTABLE_S3PT :
275- fpdt_process_subtable (subtable -> address ,
296+ result = fpdt_process_subtable (subtable -> address ,
276297 subtable -> type );
298+ if (result )
299+ goto err_subtable ;
277300 break ;
278301 default :
279302 /* Other types are reserved in ACPI 6.4 spec. */
@@ -282,6 +305,12 @@ static int __init acpi_init_fpdt(void)
282305 offset += sizeof (* subtable );
283306 }
284307 return 0 ;
308+ err_subtable :
309+ kobject_put (fpdt_kobj );
310+
311+ err_nomem :
312+ acpi_put_table (header );
313+ return result ;
285314}
286315
287316fs_initcall (acpi_init_fpdt );
0 commit comments