static int test_write_lseek_blockwise(void) { void *buffer = NULL; int fd = -1; ssize_t ret = -EINVAL; //printf("Entering test_write_lseek_blockwise\n"); if (posix_memalign(&buffer, test_mem_alignment, test_length)) { fprintf(stderr, "Failed to allocate aligned buffer.\n"); goto out; } fd = open(test_file, O_RDWR | O_DIRECT); if (fd < 0) { fprintf(stderr, "Failed to open %s.\n", test_file); goto out; } ret = write_lseek_blockwise(fd, test_bsize, test_mem_alignment, buffer, test_length, test_offset); if (ret < 0) goto out; ret = (size_t) ret == test_length ? 0 : -EIO; out: if (fd >= 0) close(fd); free(buffer); return ret; }
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; }
/* Write verity superblock to disk */ int VERITY_write_sb(struct crypt_device *cd, uint64_t sb_offset, const char *uuid_string, struct crypt_params_verity *params) { struct device *device = crypt_metadata_device(cd); int bsize = device_block_size(device); struct verity_sb sb = {}; ssize_t hdr_size = sizeof(struct verity_sb); uuid_t uuid; int r, devfd = 0; log_dbg("Updating VERITY header of size %zu on device %s, offset %" PRIu64 ".", sizeof(struct verity_sb), device_path(device), sb_offset); if (!uuid_string || uuid_parse(uuid_string, uuid) == -1) { log_err(cd, _("Wrong VERITY UUID format provided on device %s. \n"), device_path(device)); return -EINVAL; } if (params->flags & CRYPT_VERITY_NO_HEADER) { log_err(cd, _("Verity device %s doesn't use on-disk header.\n"), device_path(device)); return -EINVAL; } devfd = device_open(device, O_RDWR); if(devfd == -1) { log_err(cd, _("Cannot open device %s.\n"), device_path(device)); return -EINVAL; } memcpy(&sb.signature, VERITY_SIGNATURE, sizeof(sb.signature)); sb.version = cpu_to_le32(1); sb.hash_type = cpu_to_le32(params->hash_type); sb.data_block_size = cpu_to_le32(params->data_block_size); sb.hash_block_size = cpu_to_le32(params->hash_block_size); sb.salt_size = cpu_to_le16(params->salt_size); sb.data_blocks = cpu_to_le64(params->data_size); strncpy((char *)sb.algorithm, params->hash_name, sizeof(sb.algorithm)); memcpy(sb.salt, params->salt, params->salt_size); memcpy(sb.uuid, uuid, sizeof(sb.uuid)); r = write_lseek_blockwise(devfd, bsize, (char*)&sb, hdr_size, sb_offset) < hdr_size ? -EIO : 0; if (r) log_err(cd, _("Error during update of verity header on device %s.\n"), device_path(device)); close(devfd); return r; }
int LUKS_hdr_restore( const char *backup_file, struct luks_phdr *hdr, struct crypt_device *ctx) { struct device *device = crypt_metadata_device(ctx); int fd, r = 0, devfd = -1, diff_uuid = 0; ssize_t ret, 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; } fd = open(backup_file, O_RDONLY); if (fd == -1) { log_err(ctx, _("Cannot open header backup file %s."), backup_file); r = -EINVAL; goto out; } ret = read_buffer(fd, buffer, buffer_size); close(fd); if (ret < buffer_size) { log_err(ctx, _("Cannot read header backup file %s."), backup_file); r = -EIO; goto out; } r = LUKS_read_phdr(hdr, 0, 0, ctx); if (r == 0) { log_dbg(ctx, "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(ctx, "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(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)); r = -EINVAL; goto out; } if (write_lseek_blockwise(devfd, device_block_size(ctx, device), device_alignment(device), buffer, buffer_size, 0) < buffer_size) { r = -EIO; goto out; } /* Be sure to reload new data */ r = LUKS_read_phdr(hdr, 1, 0, ctx); out: device_sync(ctx, device); 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; }