Skip to content

Commit

Permalink
Add S3 sleep support for Linux
Browse files Browse the repository at this point in the history
The new command is --prepareForS3Sleep, and it should be called every
new boot, as it stores the drive key (password hash) in kernel memory.
  • Loading branch information
Alex committed Nov 19, 2017
1 parent 69a2a4d commit ecfd482
Show file tree
Hide file tree
Showing 12 changed files with 130 additions and 4 deletions.
6 changes: 6 additions & 0 deletions Common/DtaDev.cpp
Expand Up @@ -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;
}
5 changes: 5 additions & 0 deletions Common/DtaDev.h
Expand Up @@ -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
Expand Down
24 changes: 24 additions & 0 deletions Common/DtaOptions.cpp
Expand Up @@ -99,6 +99,9 @@ void usage()
printf("--printPasswordHash <password> <device>\n");
printf(" print the hash of the password \n");
printf(" as computed by sedutil. Hex-ecoded.\n");
printf("--prepareForS3Sleep <0...n> <Admin1password> <device>\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");
Expand Down Expand Up @@ -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];
Expand Down
1 change: 1 addition & 0 deletions Common/DtaOptions.h
Expand Up @@ -97,6 +97,7 @@ typedef enum _sedutiloption {
objDump,
printDefaultPassword,
printPasswordHash,
prepareForS3Sleep,
rawCmd,

} sedutiloption;
Expand Down
4 changes: 4 additions & 0 deletions Common/sedutil.cpp
Expand Up @@ -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]);
Expand Down
6 changes: 4 additions & 2 deletions Makefile.am
Expand Up @@ -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
Expand All @@ -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
Expand Down
46 changes: 46 additions & 0 deletions 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 <http://www.gnu.org/licenses/>.
* C:E********************************************************************** */
#include "os.h"
#include <sys/ioctl.h>
#include <linux/sed-opal.h>
#include "DtaDevLinuxDrive.h"

using namespace std;

uint8_t DtaDevLinuxDrive::prepareForS3Sleep(uint8_t lockingrange, const vector<uint8_t> &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;
}
5 changes: 5 additions & 0 deletions linux/DtaDevLinuxDrive.h
Expand Up @@ -18,8 +18,10 @@ along with sedutil. If not, see <http://www.gnu.org/licenses/>.
* C:E********************************************************************** */
#pragma once
#include <vector>
#include "DtaStructures.h"

using namespace std;
/** virtual implementation for a disk interface-generic disk drive
*/
class DtaDevLinuxDrive {
Expand All @@ -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<uint8_t> &password_hash);
int fd; /**< Linux handle for the device */
};
1 change: 0 additions & 1 deletion linux/DtaDevLinuxNvme.h
Expand Up @@ -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 */
};
1 change: 0 additions & 1 deletion linux/DtaDevLinuxSata.h
Expand Up @@ -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 */
};
33 changes: 33 additions & 0 deletions linux/DtaDevOS.cpp
Expand Up @@ -38,6 +38,9 @@ along with sedutil. If not, see <http://www.gnu.org/licenses/>.
#include "DtaDevLinuxSata.h"
#include "DtaDevLinuxNvme.h"
#include "DtaDevGeneric.h"
#include "DtaHashPwd.h"
#include "DtaSession.h"
#include "DtaDevOpal.h"

using namespace std;

Expand Down Expand Up @@ -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<uint8_t> 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()
{
Expand Down
2 changes: 2 additions & 0 deletions linux/DtaDevOS.h
Expand Up @@ -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
Expand Down

0 comments on commit ecfd482

Please sign in to comment.