Exemplo n.º 1
0
int LUKS_write_phdr(struct luks_phdr *hdr,
		    struct crypt_device *ctx)
{
	struct device *device = crypt_metadata_device(ctx);
	ssize_t hdr_size = sizeof(struct luks_phdr);
	int devfd = 0;
	unsigned int i;
	struct luks_phdr convHdr;
	int r;

	log_dbg(ctx, "Updating LUKS header of size %zu on device %s",
		sizeof(struct luks_phdr), device_path(device));

	r = LUKS_check_device_size(ctx, hdr, 1);
	if (r)
		return r;

	devfd = device_open(ctx, device, O_RDWR);
	if (devfd < 0) {
		if (errno == EACCES)
			log_err(ctx, _("Cannot write to device %s, permission denied."),
				device_path(device));
		else
			log_err(ctx, _("Cannot open device %s."), device_path(device));
		return -EINVAL;
	}

	memcpy(&convHdr, hdr, hdr_size);
	memset(&convHdr._padding, 0, sizeof(convHdr._padding));

	/* Convert every uint16/32_t item to network byte order */
	convHdr.version            = htons(hdr->version);
	convHdr.payloadOffset      = htonl(hdr->payloadOffset);
	convHdr.keyBytes           = htonl(hdr->keyBytes);
	convHdr.mkDigestIterations = htonl(hdr->mkDigestIterations);
	for(i = 0; i < LUKS_NUMKEYS; ++i) {
		convHdr.keyblock[i].active             = htonl(hdr->keyblock[i].active);
		convHdr.keyblock[i].passwordIterations = htonl(hdr->keyblock[i].passwordIterations);
		convHdr.keyblock[i].keyMaterialOffset  = htonl(hdr->keyblock[i].keyMaterialOffset);
		convHdr.keyblock[i].stripes            = htonl(hdr->keyblock[i].stripes);
	}

	r = write_lseek_blockwise(devfd, device_block_size(ctx, device), device_alignment(device),
			    &convHdr, hdr_size, 0) < hdr_size ? -EIO : 0;
	if (r)
		log_err(ctx, _("Error during update of LUKS header on device %s."), device_path(device));

	device_sync(ctx, device);

	/* Re-read header from disk to be sure that in-memory and on-disk data are the same. */
	if (!r) {
		r = LUKS_read_phdr(hdr, 1, 0, ctx);
		if (r)
			log_err(ctx, _("Error re-reading LUKS header after update on device %s."),
				device_path(device));
	}

	return r;
}
Exemplo n.º 2
0
int LUKS_read_phdr(struct luks_phdr *hdr,
		   int require_luks_device,
		   int repair,
		   struct crypt_device *ctx)
{
	struct device *device = crypt_metadata_device(ctx);
	ssize_t hdr_size = sizeof(struct luks_phdr);
	int devfd = 0, r = 0;

	/* LUKS header starts at offset 0, first keyslot on LUKS_ALIGN_KEYSLOTS */
	assert(sizeof(struct luks_phdr) <= LUKS_ALIGN_KEYSLOTS);

	/* Stripes count cannot be changed without additional code fixes yet */
	assert(LUKS_STRIPES == 4000);

	if (repair && !require_luks_device)
		return -EINVAL;

	log_dbg("Reading LUKS header of size %zu from device %s",
		hdr_size, device_path(device));

	devfd = device_open(device, O_RDONLY);
	if (devfd < 0) {
		log_err(ctx, _("Cannot open device %s."), device_path(device));
		return -EINVAL;
	}

	if (read_blockwise(devfd, device_block_size(device), device_alignment(device),
			   hdr, hdr_size) < hdr_size)
		r = -EIO;
	else
		r = _check_and_convert_hdr(device_path(device), hdr, require_luks_device,
					   repair, ctx);

	if (!r)
		r = LUKS_check_device_size(ctx, hdr, 0);

	/*
	 * Cryptsetup 1.0.0 did not align keyslots to 4k (very rare version).
	 * Disable direct-io to avoid possible IO errors if underlying device
	 * has bigger sector size.
	 */
	if (!r && hdr->keyblock[0].keyMaterialOffset * SECTOR_SIZE < LUKS_ALIGN_KEYSLOTS) {
		log_dbg("Old unaligned LUKS keyslot detected, disabling direct-io.");
		device_disable_direct_io(device);
	}

	close(devfd);
	return r;
}
int LUKS2_hdr_version_unlocked(struct crypt_device *cd, const char *backup_file)
{
	struct {
		char magic[LUKS2_MAGIC_L];
		uint16_t version;
	}  __attribute__ ((packed)) hdr;
	struct device *device = NULL;
	int r = 0, devfd = -1, flags;

	if (!backup_file)
		device = crypt_metadata_device(cd);
	else if (device_alloc(&device, backup_file) < 0)
		return 0;

	if (!device)
		return 0;

	flags = O_RDONLY;
	if (device_direct_io(device))
		flags |= O_DIRECT;

	devfd = open(device_path(device), flags);
	if (devfd < 0)
		goto err;

	if ((read_lseek_blockwise(devfd, device_block_size(device),
	     device_alignment(device), &hdr, sizeof(hdr), 0) == sizeof(hdr)) &&
	    !memcmp(hdr.magic, LUKS2_MAGIC_1ST, LUKS2_MAGIC_L))
		r = (int)be16_to_cpu(hdr.version);
err:
	if (devfd != -1)
		close(devfd);

	if (backup_file)
		device_free(device);

	return r;
}
Exemplo n.º 4
0
int LUKS_hdr_restore(
	const char *backup_file,
	struct luks_phdr *hdr,
	struct crypt_device *ctx)
{
	struct device *device = crypt_metadata_device(ctx);
	int r = 0, devfd = -1, diff_uuid = 0;
	ssize_t buffer_size = 0;
	char *buffer = NULL, msg[200];
	struct luks_phdr hdr_file;

	r = LUKS_read_phdr_backup(backup_file, &hdr_file, 0, ctx);
	if (r == -ENOENT)
		return r;

	if (!r)
		buffer_size = LUKS_device_sectors(&hdr_file) << SECTOR_SHIFT;

	if (r || buffer_size < LUKS_ALIGN_KEYSLOTS) {
		log_err(ctx, _("Backup file doesn't contain valid LUKS header."));
		r = -EINVAL;
		goto out;
	}

	buffer = crypt_safe_alloc(buffer_size);
	if (!buffer) {
		r = -ENOMEM;
		goto out;
	}

	devfd = open(backup_file, O_RDONLY);
	if (devfd == -1) {
		log_err(ctx, _("Cannot open header backup file %s."), backup_file);
		r = -EINVAL;
		goto out;
	}

	if (read_buffer(devfd, buffer, buffer_size) < buffer_size) {
		log_err(ctx, _("Cannot read header backup file %s."), backup_file);
		r = -EIO;
		goto out;
	}
	close(devfd);
	devfd = -1;

	r = LUKS_read_phdr(hdr, 0, 0, ctx);
	if (r == 0) {
		log_dbg("Device %s already contains LUKS header, checking UUID and offset.", device_path(device));
		if(hdr->payloadOffset != hdr_file.payloadOffset ||
		   hdr->keyBytes != hdr_file.keyBytes) {
			log_err(ctx, _("Data offset or key size differs on device and backup, restore failed."));
			r = -EINVAL;
			goto out;
		}
		if (memcmp(hdr->uuid, hdr_file.uuid, UUID_STRING_L))
			diff_uuid = 1;
	}

	if (snprintf(msg, sizeof(msg), _("Device %s %s%s"), device_path(device),
		 r ? _("does not contain LUKS header. Replacing header can destroy data on that device.") :
		     _("already contains LUKS header. Replacing header will destroy existing keyslots."),
		     diff_uuid ? _("\nWARNING: real device header has different UUID than backup!") : "") < 0) {
		r = -ENOMEM;
		goto out;
	}

	if (!crypt_confirm(ctx, msg)) {
		r = -EINVAL;
		goto out;
	}

	log_dbg("Storing backup of header (%zu bytes) and keyslot area (%zu bytes) to device %s.",
		sizeof(*hdr), buffer_size - LUKS_ALIGN_KEYSLOTS, device_path(device));

	devfd = device_open(device, O_RDWR);
	if (devfd < 0) {
		if (errno == EACCES)
			log_err(ctx, _("Cannot write to device %s, permission denied."),
				device_path(device));
		else
			log_err(ctx, _("Cannot open device %s."), device_path(device));
		r = -EINVAL;
		goto out;
	}

	if (write_blockwise(devfd, device_block_size(device), device_alignment(device),
			    buffer, buffer_size) < buffer_size) {
		r = -EIO;
		goto out;
	}
	close(devfd);
	devfd = -1;

	/* Be sure to reload new data */
	r = LUKS_read_phdr(hdr, 1, 0, ctx);
out:
	if (devfd >= 0)
		close(devfd);
	crypt_safe_free(buffer);
	return r;
}
Exemplo n.º 5
0
int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
{
	struct device *device = crypt_metadata_device(ctx);
	struct luks_phdr hdr;
	int r = 0, devfd = -1;
	size_t hdr_size;
	size_t buffer_size;
	char *buffer = NULL;

	r = LUKS_read_phdr(&hdr, 1, 0, ctx);
	if (r)
		return r;

	hdr_size = LUKS_device_sectors(&hdr) << SECTOR_SHIFT;
	buffer_size = size_round_up(hdr_size, crypt_getpagesize());

	buffer = crypt_safe_alloc(buffer_size);
	if (!buffer || hdr_size < LUKS_ALIGN_KEYSLOTS || hdr_size > buffer_size) {
		r = -ENOMEM;
		goto out;
	}

	log_dbg("Storing backup of header (%zu bytes) and keyslot area (%zu bytes).",
		sizeof(hdr), hdr_size - LUKS_ALIGN_KEYSLOTS);

	log_dbg("Output backup file size: %zu bytes.", buffer_size);

	devfd = device_open(device, O_RDONLY);
	if (devfd < 0) {
		log_err(ctx, _("Device %s is not a valid LUKS device."), device_path(device));
		r = -EINVAL;
		goto out;
	}

	if (read_blockwise(devfd, device_block_size(device), device_alignment(device),
			   buffer, hdr_size) < (ssize_t)hdr_size) {
		r = -EIO;
		goto out;
	}
	close(devfd);

	/* Wipe unused area, so backup cannot contain old signatures */
	if (hdr.keyblock[0].keyMaterialOffset * SECTOR_SIZE == LUKS_ALIGN_KEYSLOTS)
		memset(buffer + sizeof(hdr), 0, LUKS_ALIGN_KEYSLOTS - sizeof(hdr));

	devfd = open(backup_file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
	if (devfd == -1) {
		if (errno == EEXIST)
			log_err(ctx, _("Requested header backup file %s already exists."), backup_file);
		else
			log_err(ctx, _("Cannot create header backup file %s."), backup_file);
		r = -EINVAL;
		goto out;
	}
	if (write_buffer(devfd, buffer, buffer_size) < (ssize_t)buffer_size) {
		log_err(ctx, _("Cannot write header backup file %s."), backup_file);
		r = -EIO;
		goto out;
	}

	r = 0;
out:
	if (devfd >= 0)
		close(devfd);
	crypt_memzero(&hdr, sizeof(hdr));
	crypt_safe_free(buffer);
	return r;
}
/*
 * Write LUKS2 header to disk at specific offset.
 */
static int hdr_write_disk(struct device *device, struct luks2_hdr *hdr,
		   const char *json_area, int secondary)
{
	struct luks2_hdr_disk hdr_disk;
	uint64_t offset = secondary ? hdr->hdr_size : 0;
	size_t hdr_json_len;
	int devfd = -1, r;

	log_dbg("Trying to write LUKS2 header (%zu bytes) at offset %" PRIu64 ".",
		hdr->hdr_size, offset);

	/* FIXME: read-only device silent fail? */

	devfd = device_open_locked(device, O_RDWR);
	if (devfd < 0)
		return devfd == -1 ? -EINVAL : devfd;

	hdr_json_len = hdr->hdr_size - LUKS2_HDR_BIN_LEN;

	hdr_to_disk(hdr, &hdr_disk, secondary, offset);

	/*
	 * Write header without checksum but with proper seqid.
	 */
	if (write_lseek_blockwise(devfd, device_block_size(device),
				  device_alignment(device), (char *)&hdr_disk,
				  LUKS2_HDR_BIN_LEN, offset) < (ssize_t)LUKS2_HDR_BIN_LEN) {
		close(devfd);
		return -EIO;
	}

	/*
	 * Write json area.
	 */
	if (write_lseek_blockwise(devfd, device_block_size(device),
				  device_alignment(device),
				  CONST_CAST(char*)json_area, hdr_json_len,
				  LUKS2_HDR_BIN_LEN + offset) < (ssize_t)hdr_json_len) {
		close(devfd);
		return -EIO;
	}

	/*
	 * Calculate checksum and write header with checksum.
	 */
	r = hdr_checksum_calculate(hdr_disk.checksum_alg, &hdr_disk,
				   json_area, hdr_json_len);
	if (r < 0) {
		close(devfd);
		return r;
	}
	log_dbg_checksum(hdr_disk.csum, hdr_disk.checksum_alg, "in-memory");

	if (write_lseek_blockwise(devfd, device_block_size(device),
				  device_alignment(device), (char *)&hdr_disk,
				  LUKS2_HDR_BIN_LEN, offset) < (ssize_t)LUKS2_HDR_BIN_LEN)
		r = -EIO;

	close(devfd);
	return r;
}
/*
 * Read LUKS2 header from disk at specific offset.
 */
static int hdr_read_disk(struct device *device, struct luks2_hdr_disk *hdr_disk,
			 char **json_area, uint64_t offset, int secondary)
{
	size_t hdr_json_size = 0;
	int devfd = -1, r;

	log_dbg("Trying to read %s LUKS2 header at offset %" PRIu64 ".",
		secondary ? "secondary" : "primary", offset);

	devfd = device_open_locked(device, O_RDONLY);
	if (devfd < 0)
		return devfd == -1 ? -EIO : devfd;

	/*
	 * Read binary header and run sanity check before reading
	 * JSON area and validating checksum.
	 */
	if (read_lseek_blockwise(devfd, device_block_size(device),
				 device_alignment(device), hdr_disk,
				 LUKS2_HDR_BIN_LEN, offset) != LUKS2_HDR_BIN_LEN) {
		close(devfd);
		return -EIO;
	}

	r = hdr_disk_sanity_check_pre(hdr_disk, &hdr_json_size, secondary, offset);
	if (r < 0) {
		close(devfd);
		return r;
	}

	/*
	 * Allocate and read JSON area. Always the whole area must be read.
	 */
	*json_area = malloc(hdr_json_size);
	if (!*json_area) {
		close(devfd);
		return -ENOMEM;
	}

	if (read_lseek_blockwise(devfd, device_block_size(device),
				 device_alignment(device), *json_area, hdr_json_size,
				 offset + LUKS2_HDR_BIN_LEN) != (ssize_t)hdr_json_size) {
		close(devfd);
		free(*json_area);
		*json_area = NULL;
		return -EIO;
	}

	close(devfd);

	/*
	 * Calculate and validate checksum and zero it afterwards.
	 */
	if (hdr_checksum_check(hdr_disk->checksum_alg, hdr_disk,
				*json_area, hdr_json_size)) {
		log_dbg("LUKS2 header checksum error (offset %" PRIu64 ").", offset);
		r = -EINVAL;
	}
	memset(hdr_disk->csum, 0, LUKS2_CHECKSUM_L);

	return r;
}