diff --git a/Common/DtaDev.cpp b/Common/DtaDev.cpp index 30e4930a..7bd4493d 100644 --- a/Common/DtaDev.cpp +++ b/Common/DtaDev.cpp @@ -319,3 +319,9 @@ void DtaDev::puke() if (disk_info.Unknown) cout << "**** " << (uint16_t)disk_info.Unknown << " **** Unknown function codes IGNORED " << std::endl; } + +uint8_t DtaDev::prepareForS3Sleep(uint8_t lockingrange, char* password) +{ + LOG(E) << "S3 sleep not supported on this platform"; + return 1; +} diff --git a/Common/DtaDev.h b/Common/DtaDev.h index 9a69d884..e103633c 100644 --- a/Common/DtaDev.h +++ b/Common/DtaDev.h @@ -252,6 +252,11 @@ class DtaDev { * @param password Password of administrative authority for locking range */ virtual uint8_t eraseLockingRange(uint8_t lockingrange, char * password) = 0; + /** Optionally implemented s3 sleep support. + * On Linux, it saves the password to the kernel to use on resume. + * @param password the password to save to the kernel + */ + virtual uint8_t prepareForS3Sleep(uint8_t lockingrange, char* password); /** Dumps an object for diagnostic purposes * @param sp index into the OPALUID table for the SP the object is in * @param auth the authority ti use for the dump diff --git a/Common/DtaOptions.cpp b/Common/DtaOptions.cpp index 20fc241f..b8005dc7 100644 --- a/Common/DtaOptions.cpp +++ b/Common/DtaOptions.cpp @@ -99,6 +99,9 @@ void usage() printf("--printPasswordHash \n"); printf(" print the hash of the password \n"); printf(" as computed by sedutil. Hex-ecoded.\n"); + printf("--prepareForS3Sleep <0...n> \n"); + printf(" Automatically unlock range after S3 resume\n"); + printf(" This command will save the password to kernel memory\n"); printf("\n"); printf("Examples \n"); printf("sedutil-cli --scan \n"); @@ -522,6 +525,27 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts) OPTION_IS(password) OPTION_IS(device) END_OPTION + BEGIN_OPTION(prepareForS3Sleep, 3) + TESTARG(0, lockingrange, 0) + TESTARG(1, lockingrange, 1) + TESTARG(2, lockingrange, 2) + TESTARG(3, lockingrange, 3) + TESTARG(4, lockingrange, 4) + TESTARG(5, lockingrange, 5) + TESTARG(6, lockingrange, 6) + TESTARG(7, lockingrange, 7) + TESTARG(8, lockingrange, 8) + TESTARG(9, lockingrange, 9) + TESTARG(10, lockingrange, 10) + TESTARG(11, lockingrange, 11) + TESTARG(12, lockingrange, 12) + TESTARG(13, lockingrange, 13) + TESTARG(14, lockingrange, 14) + TESTARG(15, lockingrange, 15) + TESTFAIL("Invalid Locking Range (0-15)") + OPTION_IS(password) + OPTION_IS(device) + END_OPTION BEGIN_OPTION(rawCmd, 7) i += 6; OPTION_IS(device) END_OPTION else { LOG(E) << "Invalid command line argument " << argv[i]; diff --git a/Common/DtaOptions.h b/Common/DtaOptions.h index 715b75b8..669eef8c 100644 --- a/Common/DtaOptions.h +++ b/Common/DtaOptions.h @@ -97,6 +97,7 @@ typedef enum _sedutiloption { objDump, printDefaultPassword, printPasswordHash, + prepareForS3Sleep, rawCmd, } sedutiloption; diff --git a/Common/sedutil.cpp b/Common/sedutil.cpp index c354d78a..4427e87c 100644 --- a/Common/sedutil.cpp +++ b/Common/sedutil.cpp @@ -265,6 +265,10 @@ int main(int argc, char * argv[]) LOG(D) << "print password hash"; return d->printPasswordHash(argv[opts.password]); break; + case sedutiloption::prepareForS3Sleep: + LOG(D) << "Preparing for S3 sleep " << (uint16_t) opts.lockingrange; + return d->prepareForS3Sleep(opts.lockingrange, argv[opts.password]); + break; case sedutiloption::rawCmd: LOG(D) << "Performing cmdDump "; return d->rawCmd(argv[argc - 7], argv[argc - 6], argv[argc - 5], argv[argc - 4], argv[argc - 3], argv[argc - 2]); diff --git a/Makefile.am b/Makefile.am index f32e4f1d..56ed21eb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -25,7 +25,8 @@ sedutil_cli_SOURCES = linux/Version.h Common/sedutil.cpp Common/DtaOptions.cpp C linux/DtaDevLinuxNvme.cpp linux/DtaDevLinuxNvme.h \ linux/DtaDevLinuxSata.cpp linux/DtaDevLinuxSata.h \ linux/DtaDevOS.cpp linux/DtaDevOS.h \ - linux/DtaDevLinuxDrive.h linux/os.h \ + linux/DtaDevLinuxDrive.cpp linux/DtaDevLinuxDrive.h \ + linux/os.h \ $(SEDUTIL_COMMON_CODE) CLEANFILES = linux/Version.h BUILT_SOURCES = linux/Version.h @@ -36,7 +37,8 @@ linuxpba_SOURCES = LinuxPBA/LinuxPBA.cpp LinuxPBA/GetPassPhrase.cpp LinuxPBA/Unl linux/DtaDevLinuxNvme.cpp linux/DtaDevLinuxNvme.h \ linux/DtaDevLinuxSata.cpp linux/DtaDevLinuxSata.h \ linux/DtaDevOS.cpp linux/DtaDevOS.h \ - linux/DtaDevLinuxDrive.h linux/os.h \ + linux/DtaDevLinuxDrive.cpp linux/DtaDevLinuxDrive.h \ + linux/os.h \ \ $(SEDUTIL_COMMON_CODE) EXTRA_DIST = linux/GitVersion.sh linux/PSIDRevert_LINUX.txt linux/TestSuite.sh README.md docs/sedutil-cli.8 diff --git a/linux/DtaDevLinuxDrive.cpp b/linux/DtaDevLinuxDrive.cpp new file mode 100755 index 00000000..d04606a9 --- /dev/null +++ b/linux/DtaDevLinuxDrive.cpp @@ -0,0 +1,46 @@ +/* C:B************************************************************************** +Copyright 2017, Alex Badics + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ +#include "os.h" +#include +#include +#include "DtaDevLinuxDrive.h" + +using namespace std; + +uint8_t DtaDevLinuxDrive::prepareForS3Sleep(uint8_t lockingrange, const vector &password_hash) +{ + LOG(D1) << "Entering DtaDevLinuxDrive::prepareForS3Sleep"; + + opal_lock_unlock opal_ioctl_data={}; + opal_ioctl_data.l_state = OPAL_RW; + opal_ioctl_data.session.who = OPAL_ADMIN1; + opal_ioctl_data.session.opal_key.lr = 0; + + size_t hash_len=min(password_hash.size(), sizeof(opal_ioctl_data.session.opal_key.key)); + LOG(D2) << "Setting a hash of length" << hash_len; + + memcpy(opal_ioctl_data.session.opal_key.key, &password_hash[0], hash_len); + opal_ioctl_data.session.opal_key.key_len = hash_len; + + int err = ioctl(fd, IOC_OPAL_SAVE, &opal_ioctl_data); + if (err < 0) + return errno; + return 0; +} diff --git a/linux/DtaDevLinuxDrive.h b/linux/DtaDevLinuxDrive.h index d2022a16..39d1951f 100755 --- a/linux/DtaDevLinuxDrive.h +++ b/linux/DtaDevLinuxDrive.h @@ -18,8 +18,10 @@ along with sedutil. If not, see . * C:E********************************************************************** */ #pragma once +#include #include "DtaStructures.h" +using namespace std; /** virtual implementation for a disk interface-generic disk drive */ class DtaDevLinuxDrive { @@ -45,4 +47,7 @@ class DtaDevLinuxDrive { void * buffer, uint32_t bufferlen) = 0; /** Routine to send an identify to the device */ virtual void identify(OPAL_DiskInfo& disk_info) = 0; + /** Save the password hash to the kernel for S3 sleep wakeup */ + uint8_t prepareForS3Sleep(uint8_t lockingrange, const vector &password_hash); + int fd; /**< Linux handle for the device */ }; diff --git a/linux/DtaDevLinuxNvme.h b/linux/DtaDevLinuxNvme.h index 3ea6874d..b305a88f 100755 --- a/linux/DtaDevLinuxNvme.h +++ b/linux/DtaDevLinuxNvme.h @@ -59,5 +59,4 @@ class DtaDevLinuxNvme: public DtaDevLinuxDrive{ void * buffer, uint32_t bufferlen); /** NVMe specific routine to send an identify to the device */ void identify(OPAL_DiskInfo& disk_info); - int fd; /**< Linux handle for the device */ }; diff --git a/linux/DtaDevLinuxSata.h b/linux/DtaDevLinuxSata.h index 14b7e12a..6e19b44d 100755 --- a/linux/DtaDevLinuxSata.h +++ b/linux/DtaDevLinuxSata.h @@ -55,6 +55,5 @@ class DtaDevLinuxSata: public DtaDevLinuxDrive { void * buffer, uint32_t bufferlen); /** Linux specific routine to send an ATA identify to the device */ void identify_SAS(OPAL_DiskInfo *disk_info); - int fd; /**< Linux handle for the device */ int isSAS; /* The device is sas */ }; diff --git a/linux/DtaDevOS.cpp b/linux/DtaDevOS.cpp index 5261e736..342d63f3 100644 --- a/linux/DtaDevOS.cpp +++ b/linux/DtaDevOS.cpp @@ -38,6 +38,9 @@ along with sedutil. If not, see . #include "DtaDevLinuxSata.h" #include "DtaDevLinuxNvme.h" #include "DtaDevGeneric.h" +#include "DtaHashPwd.h" +#include "DtaSession.h" +#include "DtaDevOpal.h" using namespace std; @@ -165,6 +168,36 @@ int DtaDevOS::diskScan() return 0; } +uint8_t DtaDevOS::prepareForS3Sleep(uint8_t lockingrange, char* password) +{ + LOG(D1) << "Entering DtaDevOS::prepareForS3Sleep "; + LOG(D2) << "Starting testing of password "; + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + int err; + if ((err = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { + delete session; + LOG(E) << "Unable to authenticate with the given password"; + return err; + } + delete session; + LOG(D2) << "Test successful, saving it to kernel "; + vector hash; + DtaHashPwd(hash, password, this); + hash.erase(hash.begin(), hash.begin()+2); + + err = drive->prepareForS3Sleep(0, hash); + if (err) + { + LOG(E) << "Error saving the password to the kernel errno = " << errno; + return errno; + } + return 0; +} + /** Close the device reference so this object can be delete. */ DtaDevOS::~DtaDevOS() { diff --git a/linux/DtaDevOS.h b/linux/DtaDevOS.h index beeacb38..fc3705fc 100644 --- a/linux/DtaDevOS.h +++ b/linux/DtaDevOS.h @@ -49,6 +49,8 @@ class DtaDevOS : public DtaDev { void * buffer, uint32_t bufferlen); /** A static class to scan for supported drives */ static int diskScan(); + /** Save device key to kernel for S3 sleep resume */ + uint8_t prepareForS3Sleep(uint8_t lockingrange, char* password); protected: /** OS specific command to Wait for specified number of milliseconds * @param ms number of milliseconds to wait