From 4b6399a93ff592d99648d6a55059d8304c951ee1 Mon Sep 17 00:00:00 2001 From: PartialVolume <22084881+PartialVolume@users.noreply.github.com> Date: Wed, 8 Mar 2023 00:20:22 +0000 Subject: [PATCH] HPA_DCO_004 - Add HPA/DCO Capability 1. In the GUI I switched the HPA/DCO status position from overlaying the [drive size][temp] and instead positioning the HPA/DCO status over the drive model and serial number. HPA/DCO information and drive details alternating every couple of seconds. This allowed me to extend the length of the HPA message and make it more meaningful to somebody that doesn't know the HPA/DCO terminology. Therefore "HPA Enabled" is replaced with "HPA/DCO Warning, hidden area detected" 2. Started adding bad/missing sense data detection .. more code to follow .. --- src/gui.c | 43 +++++++++++++------------- src/hpa_dco.c | 86 ++++++++++++++++++++++++++++++++------------------- src/hpa_dco.h | 9 ++++++ 3 files changed, 85 insertions(+), 53 deletions(-) diff --git a/src/gui.c b/src/gui.c index 3539ed3..d95bdbc 100644 --- a/src/gui.c +++ b/src/gui.c @@ -795,47 +795,51 @@ void nwipe_gui_select( int count, nwipe_context_t** c ) } /* switch select */ - /* Toggle the [size][temp C] with [HDA Status] + wprintw( main_window, "[%s] ", c[i + offset]->device_size_text ); + + /* Read the drive temperature values */ + nwipe_update_temperature( c[i + offset] ); + + /* print the temperature */ + wprintw_temperature( c[i + offset] ); + + /* Toggle the drive/serial with [HDA/DCO Status] */ switch( c[i + offset]->HPA_display_toggle_state ) { case 0: - wprintw( main_window, "[%s] ", c[i + offset]->device_size_text ); - - /* Read the drive temperature values */ - nwipe_update_temperature( c[i + offset] ); - - /* print the temperature */ - wprintw_temperature( c[i + offset] ); + /* print the drive model and serial number */ + wprintw( main_window, " %s/%s", c[i + offset]->device_model, c[i + offset]->device_serial_no ); break; case 1: switch( c[i + offset]->HPA_status ) { case HPA_ENABLED: + wprintw( main_window, " " ); wattron( main_window, COLOR_PAIR( 9 ) ); - wprintw( main_window, "[HPA ENABLED!]" ); + wprintw( main_window, " HPA/DCO Warning, hidden area detected " ); wattroff( main_window, COLOR_PAIR( 9 ) ); break; case HPA_DISABLED: - wprintw( main_window, "[HPA disabled]" ); + wprintw( main_window, " " ); + wprintw( main_window, " HPA/DCO GOOD, no hidden areas " ); break; case HPA_UNKNOWN: + wprintw( main_window, " " ); wattron( main_window, COLOR_PAIR( 9 ) ); - wprintw( main_window, "[HPA unknown ]" ); + wprintw( main_window, " HPA/DCO hidden area indeterminate " ); wattroff( main_window, COLOR_PAIR( 9 ) ); break; case HPA_NOT_APPLICABLE: - wprintw( main_window, "[%s] ", c[i + offset]->device_size_text ); - - /* Read the drive temperature values */ - nwipe_update_temperature( c[i + offset] ); - - /* print the temperature */ - wprintw_temperature( c[i + offset] ); + /* print the drive model and serial number */ + wprintw( main_window, + " %s/%s", + c[i + offset]->device_model, + c[i + offset]->device_serial_no ); break; default: @@ -858,9 +862,6 @@ void nwipe_gui_select( int count, nwipe_context_t** c ) } c[i + offset]->HPA_toggle_time = time( NULL ); } - - /* print the drive model and serial number */ - wprintw( main_window, " %s/%s", c[i + offset]->device_model, c[i + offset]->device_serial_no ); } else { diff --git a/src/hpa_dco.c b/src/hpa_dco.c index f68a9d8..8670600 100644 --- a/src/hpa_dco.c +++ b/src/hpa_dco.c @@ -44,7 +44,8 @@ * rather than reinvent the wheel. However, I don't like doing it like this as a change in formatted * output of hdparm could potentially break HPA/DCO detection requiring a fix. Anybody that wants to * re-write this function for a purer nwipe without the use of hdparm then by all means please go - * ahead and submit a pull request to https://github.com/martijnvanbrummelen/nwipe + * ahead and submit a pull request to https://github.com/martijnvanbrummelen/nwipe, however, hopefully + * time permitting I will end up doing this myself. */ int hpa_dco_status( nwipe_context_t* ptr ) @@ -59,13 +60,13 @@ int hpa_dco_status( nwipe_context_t* ptr ) int dco_line_found; FILE* fp; - char path_hdparm_cmd1_get_hpa[] = "hdparm -N"; - char path_hdparm_cmd2_get_hpa[] = "/sbin/hdparm -N"; - char path_hdparm_cmd3_get_hpa[] = "/usr/bin/hdparm -N"; + char path_hdparm_cmd1_get_hpa[] = "hdparm --verbose -N"; + char path_hdparm_cmd2_get_hpa[] = "/sbin/hdparm --verbose -N"; + char path_hdparm_cmd3_get_hpa[] = "/usr/bin/hdparm --verbose -N"; - char path_hdparm_cmd4_get_dco[] = "hdparm --dco-identify"; - char path_hdparm_cmd5_get_dco[] = "/sbin/hdparm --dco-identify"; - char path_hdparm_cmd6_get_dco[] = "/usr/bin/hdparm --dco-identify"; + char path_hdparm_cmd4_get_dco[] = "hdparm --verbose --dco-identify"; + char path_hdparm_cmd5_get_dco[] = "/sbin/hdparm --verbose --dco-identify"; + char path_hdparm_cmd6_get_dco[] = "/usr/bin/hdparm --verbose --dco-identify"; char result[512]; @@ -162,36 +163,41 @@ int hpa_dco_status( nwipe_context_t* ptr ) /* Scan the hdparm results for HPA is disabled */ - if( strstr( result, "hpa is disabled" ) != 0 ) + if( strstr( result, "SG_IO: bad/missing sense data" ) != 0 ) { - c->HPA_status = HPA_DISABLED; - - nwipe_log( NWIPE_LOG_INFO, "[GOOD] The host protected area is disabled on %s", c->device_name ); - hpa_line_found = 1; + c->HPA_status = HPA_UNKNOWN; + nwipe_log( NWIPE_LOG_INFO, "[ERROR] SG_IO bad/missing sense data %s", hdparm_cmd_get_hpa ); break; } else { - if( strstr( result, "hpa is enabled" ) != 0 ) + if( strstr( result, "hpa is disabled" ) != 0 ) { - c->HPA_status = HPA_ENABLED; - nwipe_log( - NWIPE_LOG_WARNING, "[BAD] The host protected area is enabled on %s", c->device_name ); + c->HPA_status = HPA_DISABLED; + + nwipe_log( NWIPE_LOG_INFO, "[GOOD] The host protected area is disabled on %s", c->device_name ); hpa_line_found = 1; - break; } else { - if( strstr( result, "invalid" ) != 0 ) + if( strstr( result, "hpa is enabled" ) != 0 ) { c->HPA_status = HPA_ENABLED; - nwipe_log( NWIPE_LOG_WARNING, - "[UNSURE] hdparm reports invalid output, buggy drive firmware on %s?", - c->device_name ); - // We'll assume the HPA values are in the string as we may be able to extract something - // meaningful + nwipe_log( NWIPE_LOG_WARNING, "The host protected area is enabled on %s", c->device_name ); hpa_line_found = 1; - break; + } + else + { + if( strstr( result, "invalid" ) != 0 ) + { + c->HPA_status = HPA_ENABLED; + nwipe_log( NWIPE_LOG_WARNING, + "[UNSURE] hdparm reports invalid output, buggy drive firmware on %s?", + c->device_name ); + // We'll assume the HPA values are in the string as we may be able to extract something + // meaningful + hpa_line_found = 1; + } } } } @@ -361,6 +367,21 @@ int hpa_dco_status( nwipe_context_t* ptr ) * * If 'HPA set' and 'HPA real' are different then it * can be considered that HPA is enabled) + * + * However we also need to consider that more recent drives + * no longer support HPA/DCO such as the Seagate ST10000NM0016, + * ST4000NM0033 and ST1000DM003. If you try to issue those drives + * with the ATA command code 0xB1 (device configuration overlay) + * you will get a generic illegal request in the returned sense data. + * + * One other thing to note, we use HPA enabled/disabled to mean + * hidden area detected or not detected, this could be caused by + * either the dco-setmax being issued or Np, either way an area + * of the disc can be hidden. From the user interface we just call + * it a HPA/DCO hidden area detected (or not) which is more + * meaningful than just saying HDA enabled or disabled and a user + * not familiar with the term HPA or DCO not understanding why a + * HDA being detected could be significant. */ /* Determine, based on the values of 'HPA set', 'HPA real, @@ -370,9 +391,9 @@ int hpa_dco_status( nwipe_context_t* ptr ) * the certificate and is used to determine whether * to reset the HPA. */ - /* If all three values match then there is no hidden disc area. HPA is disabled. */ + /* If all three values match and none are zero then there is NO hidden disc area. HPA is disabled. */ if( c->HPA_reported_set == c->HPA_reported_real && c->DCO_reported_real_max_sectors == c->HPA_reported_set - && c->HPA_reported_set != 0 ) + && c->HPA_reported_set != 0 && c->HPA_reported_real != 0 && c->DCO_reported_real_max_sectors != 0 ) { c->HPA_status = HPA_DISABLED; } @@ -401,20 +422,19 @@ int hpa_dco_status( nwipe_context_t* ptr ) if( c->HPA_status == HPA_DISABLED ) { - nwipe_log( NWIPE_LOG_INFO, "[GOOD] HPA is disabled on %s", c->device_name ); + nwipe_log( NWIPE_LOG_INFO, "No hidden areas on %s", c->device_name ); } else { if( c->HPA_status == HPA_ENABLED ) { - nwipe_log( NWIPE_LOG_WARNING, "[BAD] HPA is enabled on %s", c->device_name ); + nwipe_log( NWIPE_LOG_WARNING, "HIDDEN AREA DETECTED! on %s", c->device_name ); } else { if( c->HPA_status == HPA_UNKNOWN ) { - nwipe_log( - NWIPE_LOG_WARNING, "[UNKNOWN] We can't seem to determine the HPA status on %s", c->device_name ); + nwipe_log( NWIPE_LOG_WARNING, "HIDDEN AREA INDETERMINATE! on %s", c->device_name ); } } } @@ -447,9 +467,11 @@ int hpa_dco_status( nwipe_context_t* ptr ) int ascii2binary_array( char* input, unsigned char* output_bin, int bin_size ) { - /* Scans a character string that contains hexadecimal ascii data, ignores spaces + /* Converts ascii sense data output by hdparm to binary. + * Scans a character string that contains hexadecimal ascii data, ignores spaces * and extracts and converts the hexadecimal ascii data to binary and places in a array. - * Typically for dco_identify sense data the bin size will be 512 bytes. + * Typically for dco_identify sense data the bin size will be 512 bytes but for error + * sense data this would be 32 bytes. */ int idx_in; // Index into ascii input string int idx_out; // Index into the binary output array diff --git a/src/hpa_dco.h b/src/hpa_dco.h index 2346359..e76ac29 100644 --- a/src/hpa_dco.h +++ b/src/hpa_dco.h @@ -29,4 +29,13 @@ int hpa_dco_status( nwipe_context_t* ); +typedef struct nwipe_sense_dco_identify_t_t_ +{ + /* This struct contains some of the decoded fields from the sense data after a + * ATA 0xB1 device configuration overlay command has been issued. We mainly + * use it to decode the real max sectors + */ + u64 dco_real_max_sectors; +} nwipe_sense_dco_identify_t_t_; + #endif /* HPA_DCO_H_ */