Bug Summary

File:.build-ci/../plugins/rpmb/rpmb.c
Warning:line 938, column 9
Potential leak of memory pointed to by 'msg_buf'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -O3 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name rpmb.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -fcoverage-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -resource-dir /usr/bin/../lib/clang/22 -include /__w/nvme-cli/nvme-cli/.build-ci/nvme-config.h -I nvme.p -I . -I .. -I src -I ../src -I ccan -I ../ccan -I libnvme/src -I ../libnvme/src -I /usr/include/json-c -D _FILE_OFFSET_BITS=64 -D _GNU_SOURCE -U NDEBUG -internal-isystem /usr/bin/../lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=gnu11 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /__w/nvme-cli/nvme-cli/.build-ci/scan-results/2026-09-23-073103-589-1 -x c ../plugins/rpmb/rpmb.c
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2020 Micron Technology Inc. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16 * rpmb.c - Implementation of NVMe RPMB support commands
17 */
18#include <errno(*__errno_location ()).h>
19#include <fcntl.h>
20#include <limits.h>
21#include <stddef.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <sys/stat.h>
26#include <sys/types.h>
27#include <unistd.h>
28
29#include <libnvme.h>
30
31#include <ccan/array_size/array_size.h>
32#include <ccan/endian/endian.h>
33#include <shared/compiler-attributes-util.h>
34#include <shared/crypto-util.h>
35#include <shared/fs-util.h>
36
37#include "cleanup.h"
38#include "global-ctx.h"
39#include "nvme-print.h"
40#include "plugin.h"
41
42/* Read data from given file into buffer and return its length */
43static int read_file(const char *file, unsigned char **data, unsigned int *len)
44{
45 struct stat sb;
46 size_t size;
47 unsigned char *buf = NULL((void*)0);
48 int fd;
49 int err = -EINVAL22;
50
51 if (!file)
52 return err;
53
54 fd = shr_open_rawdata(file, O_RDONLY)open((file), (00));
55 if (fd < 0) {
56 nvme_show_error("Failed to open %s: %s", file, libnvme_strerror(errno))nvme_show_message(1, "Failed to open %s: %s", file, libnvme_strerror
((*__errno_location ())))
;
57 return fd;
58 }
59
60 err = fstat(fd, &sb);
61 if (err < 0) {
62 nvme_show_perror("fstat");
63 goto out;
64 }
65
66 size = sb.st_size;
67 buf = libnvme_alloc(size);
68 if (!buf) {
69 nvme_show_error("No memory for reading file: %s", file)nvme_show_message(1, "No memory for reading file: %s", file);
70 err = -ENOMEM12;
71 goto out;
72 }
73
74 err = read(fd, buf, size);
75 if (err < 0) {
76 err = -errno(*__errno_location ());
77 nvme_show_error("Failed to read data from file %s with %s", file,nvme_show_message(1, "Failed to read data from file %s with %s"
, file, libnvme_strerror((*__errno_location ())))
78 libnvme_strerror(errno))nvme_show_message(1, "Failed to read data from file %s with %s"
, file, libnvme_strerror((*__errno_location ())))
;
79 libnvme_free(buf);
80 goto out;
81 }
82 *data = buf;
83 *len = err;
84 err = 0;
85out:
86 close(fd);
87 return err;
88}
89
90/* Write given buffer data to specified file */
91static void write_file(unsigned char *data, size_t len, const char *dir,
92 const char *file, const char *msg)
93{
94 char temp_folder[PATH_MAX4096] = { 0 };
95 __cleanup_file__attribute__((cleanup(shr_cleanup_file))) FILE *fp = NULL((void*)0);
96
97 if (dir)
98 sprintf(temp_folder, "%s/%s", dir, file);
99 else
100 sprintf(temp_folder, "./%s", file);
101
102 fp = fopen(temp_folder, "ab+");
103 if (fp) {
104 if (fwrite(data, 1, len, fp) != len)
105 nvme_show_error("Failed to write %s data to %s", msg ? msg : "",nvme_show_message(1, "Failed to write %s data to %s", msg ? msg
: "", temp_folder)
106 temp_folder)nvme_show_message(1, "Failed to write %s data to %s", msg ? msg
: "", temp_folder)
;
107 } else {
108 nvme_show_error("Failed to open %s file to write %s", temp_folder,nvme_show_message(1, "Failed to open %s file to write %s", temp_folder
, msg ? msg : "")
109 msg ? msg : "")nvme_show_message(1, "Failed to open %s file to write %s", temp_folder
, msg ? msg : "")
;
110 }
111}
112
113/* Various definitions used in RPMB related support */
114enum rpmb_request_type {
115 RPMB_REQ_AUTH_KEY_PROGRAM = 0x0001,
116 RPMB_REQ_READ_WRITE_CNTR = 0x0002,
117 RPMB_REQ_AUTH_DATA_WRITE = 0x0003,
118 RPMB_REQ_AUTH_DATA_READ = 0x0004,
119 RPMB_REQ_READ_RESULT = 0x0005,
120 RPMB_REQ_AUTH_DCB_WRITE = 0x0006,
121 RPMB_REQ_AUTH_DCB_READ = 0x0007,
122};
123
124/* RPMB data frame structure */
125#pragma pack(1)
126struct rpmb_data_frame_t {
127 unsigned char pad[191];
128 unsigned char mac[32];
129 unsigned char target; /* 0-6, should match with NSSF with SS, SR */
130 unsigned char nonce[16];
131 unsigned int write_counter;
132 unsigned int address;
133 unsigned int sectors;
134 unsigned short result;
135 unsigned short type; /* req or response */
136 unsigned char data[0]; /* in sector count times */
137};
138#pragma pack()
139
140struct rpmb_config_block_t {
141 unsigned char bp_enable;
142 unsigned char bp_lock;
143 unsigned char rsvd[510];
144};
145
146#define RPMB_DATA_FRAME_SIZE256 256
147#define RPMB_NVME_SECP0xEA 0xEA
148#define RPMB_NVME_SPSP0x0001 0x0001
149
150union ctrl_rpmbs_reg {
151 struct {
152 unsigned int num_targets:3;
153 unsigned int auth_method:3;
154 unsigned int reserved:10;
155 unsigned int total_size:8; /* 128K units */
156 unsigned int access_size:8; /* in 512 byte count */
157 };
158 unsigned int rpmbs;
159};
160
161static int send_rpmb_req(struct libnvme_transport_handle *hdl, unsigned char tgt,
162 int size, struct rpmb_data_frame_t *req)
163{
164 struct libnvme_passthru_cmd cmd;
165
166 nvme_init_security_send(&cmd, NVME_NSID_NONE, tgt, RPMB_NVME_SPSP0x0001,
167 RPMB_NVME_SECP0xEA, 0, req, size);
168 return libnvme_exec_admin_passthru(hdl, &cmd);
169}
170
171static int recv_rpmb_rsp(struct libnvme_transport_handle *hdl, int tgt, int size,
172 struct rpmb_data_frame_t *rsp)
173{
174 struct libnvme_passthru_cmd cmd;
175
176 nvme_init_security_receive(&cmd, 0, tgt, RPMB_NVME_SPSP0x0001, RPMB_NVME_SECP0xEA, 0, rsp,
177 size);
178 return libnvme_exec_admin_passthru(hdl, &cmd);
179}
180
181/* Initialize nonce value in rpmb request frame. Returns 0 on success, -1 on failure. */
182static int rpmb_nonce_init(struct rpmb_data_frame_t *req)
183{
184 if (shr_getrandom(req->nonce, sizeof(req->nonce)) != 0) {
185 nvme_show_error("Failed to generate RPMB nonce")nvme_show_message(1, "Failed to generate RPMB nonce");
186 return -1;
187 }
188
189 return 0;
190}
191
192/* Read key from a given key buffer or key file */
193static unsigned char *read_rpmb_key(char *keystr, char *keyfile, unsigned int *keysize)
194{
195 unsigned char *keybuf = NULL((void*)0);
196 int err;
197
198 if (!keystr) {
199 if (keyfile) {
200 err = read_file(keyfile, &keybuf, keysize);
201 if (err < 0)
202 return NULL((void*)0);
203 }
204 } else {
205 size_t len = strlen(keystr);
206
207 keybuf = libnvme_alloc(len + 1);
208 if (keybuf) {
209 *keysize = len;
210 memcpy(keybuf, keystr, len);
211 }
212 }
213
214 return keybuf;
215}
216
217/* Initialize RPMB request frame with given values */
218static struct rpmb_data_frame_t *
219rpmb_request_init(unsigned int req_size, unsigned short type, unsigned char target,
220 unsigned char nonce, unsigned int addr, unsigned int sectors,
221 unsigned char *data, unsigned short data_offset, unsigned int data_size)
222{
223 struct rpmb_data_frame_t *req;
224
225 req = calloc(req_size, 1);
226 if (!req) {
227 nvme_show_error("Memory allocation failed for request 0x%04x", type)nvme_show_message(1, "Memory allocation failed for request 0x%04x"
, type)
;
228 return req;
229 }
230
231 req->type = type;
232 req->target = target;
233 req->address = addr;
234 req->sectors = sectors;
235
236 if (nonce && rpmb_nonce_init(req) != 0) {
237 free(req);
238 return NULL((void*)0);
239 }
240 if (data)
241 memcpy((unsigned char *)req + data_offset, data, data_size);
242
243 return req;
244}
245
246/* Process rpmb response and print appropriate error message */
247static int check_rpmb_response(struct rpmb_data_frame_t *req, struct rpmb_data_frame_t *rsp,
248 char *msg)
249{
250 const char *rpmb_result_string[] = {
251 "Operation successful",
252 "General failure",
253 "Authentication (MAC) failure",
254 "Counter failure (not matching/incrementing failure)",
255 "Address failure (out of range or wrong alignment)",
256 "Write (data/counter/result) failure",
257 "Read (data/counter/result) failure",
258 "Authentication key not yet programmed",
259 "Invalid device configuration block",
260 "Unknown error",
261 };
262
263 /* check error status before comparing nonce and mac */
264 if (rsp->result != 0) {
265 if (rsp->type != ((req->type << 8) & 0xFF00)) {
266 nvme_show_error("%s ! non-matching response 0x%04x for 0x%04x", msg,nvme_show_message(1, "%s ! non-matching response 0x%04x for 0x%04x"
, msg, rsp->type, req->type)
267 rsp->type, req->type)nvme_show_message(1, "%s ! non-matching response 0x%04x for 0x%04x"
, msg, rsp->type, req->type)
;
268 } else if ((rsp->result & 0x80) == 0x80) {
269 nvme_show_error("%s ! Expired write-counter !", msg)nvme_show_message(1, "%s ! Expired write-counter !", msg);
270 } else if (rsp->result) {
271 unsigned int code = rsp->result & 0x7F;
272
273 nvme_show_error("%s ! %s", msg,nvme_show_message(1, "%s ! %s", msg, code < (sizeof(rpmb_result_string
) / sizeof((rpmb_result_string)[0]) + 0) ? rpmb_result_string
[code] : "Unknown error")
274 code < ARRAY_SIZE(rpmb_result_string) ?nvme_show_message(1, "%s ! %s", msg, code < (sizeof(rpmb_result_string
) / sizeof((rpmb_result_string)[0]) + 0) ? rpmb_result_string
[code] : "Unknown error")
275 rpmb_result_string[code] : "Unknown error")nvme_show_message(1, "%s ! %s", msg, code < (sizeof(rpmb_result_string
) / sizeof((rpmb_result_string)[0]) + 0) ? rpmb_result_string
[code] : "Unknown error")
;
276 } else if (memcmp(req->nonce, rsp->nonce, 16)) {
277 nvme_show_error("%s ! non-matching nonce", msg)nvme_show_message(1, "%s ! non-matching nonce", msg);
278 } else if (memcmp(req->mac, rsp->mac, 32)) {
279 nvme_show_error("%s ! non-matching MAC", msg)nvme_show_message(1, "%s ! non-matching MAC", msg);
280 } else if ((req->write_counter + 1) != rsp->write_counter) {
281 nvme_show_error("%s ! out-of-sync write-counters", msg)nvme_show_message(1, "%s ! out-of-sync write-counters", msg);
282 }
283 }
284
285 return (int)rsp->result;
286}
287
288/*
289 * send an initialized rpmb request to the controller and read its response;
290 * expected response size given in 'rsp_size'. returns response buffer upon
291 * successful completion (caller must free), NULL otherwise
292 */
293static struct rpmb_data_frame_t *
294rpmb_read_request(struct libnvme_transport_handle *hdl, struct rpmb_data_frame_t *req,
295 int req_size, int rsp_size)
296{
297 struct rpmb_data_frame_t *rsp = NULL((void*)0);
298 unsigned char msg[1024] = { 0 };
299 int error;
300
301 sprintf((char *)msg, "RPMB request 0x%04x to target 0x%x", req->type, req->target);
302
303 error = send_rpmb_req(hdl, req->target, req_size, req);
304 if (error != 0) {
305 nvme_show_error("%s failed with error = 0x%x", msg, error)nvme_show_message(1, "%s failed with error = 0x%x", msg, error
)
;
306 goto error_out;
307 }
308
309 /* read the result back */
310 rsp = calloc(rsp_size, 1);
311 if (!rsp) {
312 nvme_show_error("memory alloc failed for %s", msg)nvme_show_message(1, "memory alloc failed for %s", msg);
313 goto error_out;
314 }
315
316 /* Read result of previous request */
317 error = recv_rpmb_rsp(hdl, req->target, rsp_size, rsp);
318 if (error) {
319 nvme_show_error("error 0x%x receiving response for %s", error, msg)nvme_show_message(1, "error 0x%x receiving response for %s", error
, msg)
;
320 goto error_out;
321 }
322
323 /* validate response buffer - match target, nonce, and mac */
324 error = check_rpmb_response(req, rsp, (char *)msg);
325 if (error == 0)
326 return rsp;
327
328error_out:
329 free(rsp);
330 return NULL((void*)0);
331}
332
333/* read current write counter value from controller */
334static int rpmb_read_write_counter(struct libnvme_transport_handle *hdl, unsigned char target,
335 unsigned int *counter)
336{
337 int error = -1;
338 int req_size = sizeof(struct rpmb_data_frame_t);
339 struct rpmb_data_frame_t *req = NULL((void*)0);
340 struct rpmb_data_frame_t *rsp = NULL((void*)0);
341
342 req = rpmb_request_init(req_size, RPMB_REQ_READ_WRITE_CNTR, target, 1, 0, 0, NULL((void*)0), 0,
343 0);
344 if (!req)
345 goto out;
346 rsp = rpmb_read_request(hdl, req, req_size, req_size);
347 if (!rsp)
348 goto out;
349 *counter = rsp->write_counter;
350 error = 0;
351
352out:
353 free(req);
354 free(rsp);
355 return error;
356}
357
358/*
359 * Read current device configuration block into specified buffer. It also
360 * returns current write counter value returned as part of response, in case
361 * of error it returns 0
362 */
363static unsigned int rpmb_read_config_block(struct libnvme_transport_handle *hdl,
364 unsigned char **config_buf)
365{
366 int req_size = sizeof(struct rpmb_data_frame_t);
367 int cfg_size = sizeof(struct rpmb_config_block_t);
368 int rsp_size = req_size + cfg_size;
369
370 struct rpmb_data_frame_t *req = NULL((void*)0);
371 struct rpmb_data_frame_t *rsp = NULL((void*)0);
372 struct rpmb_config_block_t *cfg = NULL((void*)0);
373 unsigned int retval = 0;
374
375 /* initialize request with nonce, no data on input */
376 req = rpmb_request_init(req_size, RPMB_REQ_AUTH_DCB_READ, 0, 1, 0, 1, 0, 0, 0);
377 if (!req)
378 return 0;
379 rsp = rpmb_read_request(hdl, req, req_size, rsp_size);
380 if (!rsp) {
381 free(req);
382 return 0;
383 }
384
385 /* copy configuration data to be sent back to caller */
386 cfg = calloc(cfg_size, 1);
387 if (!cfg) {
388 nvme_show_error("failed to allocate RPMB config buffer")nvme_show_message(1, "failed to allocate RPMB config buffer");
389 goto out;
390 }
391
392 memcpy(cfg, rsp->data, cfg_size);
393 *config_buf = (unsigned char *)cfg;
394 cfg = NULL((void*)0);
395 retval = rsp->write_counter;
396out:
397 free(req);
398 free(rsp);
399 return retval;
400}
401
402static int rpmb_auth_data_read(struct libnvme_transport_handle *hdl, unsigned char target,
403 unsigned int offset, unsigned char **msg_buf, int msg_size,
404 int acc_size)
405{
406 struct rpmb_data_frame_t *req = NULL((void*)0);
407 struct rpmb_data_frame_t *rsp = NULL((void*)0);
408 int req_size = sizeof(struct rpmb_data_frame_t);
409 int chunk_size = (acc_size < msg_size) ? acc_size : msg_size;
6
Assuming 'acc_size' is < 'msg_size'
7
'?' condition is true
410 int xfer = chunk_size;
411 unsigned char *bufp = malloc(msg_size * 512);
8
Memory is allocated
412 unsigned char *tbufp = bufp;
413 int data_size, rsp_size;
414
415 if (!bufp) {
9
Assuming 'bufp' is non-null
10
Taking false branch
416 nvme_show_error("Failed to allocated memory for read-data req")nvme_show_message(1, "Failed to allocated memory for read-data req"
)
;
417 return -1;
418 }
419
420 while (xfer > 0) {
11
Assuming 'xfer' is <= 0
12
Loop condition is false. Execution continues on line 452
421 rsp_size = req_size + xfer * 512;
422 req = rpmb_request_init(req_size, RPMB_REQ_AUTH_DATA_READ, target, 1, offset,
423 xfer, 0, 0, 0);
424 if (!req) {
425 nvme_show_error("failed to allocate read-data request")nvme_show_message(1, "failed to allocate read-data request");
426 goto err_free_bufp;
427 }
428 rsp = rpmb_read_request(hdl, req, req_size, rsp_size);
429 if (!rsp) {
430 nvme_show_error("read_request failed")nvme_show_message(1, "read_request failed");
431 goto err_free_req;
432 }
433
434 if (rsp->sectors > (unsigned int)xfer) {
435 nvme_show_error("device reported %u sectors, more than the %d requested",nvme_show_message(1, "device reported %u sectors, more than the %d requested"
, rsp->sectors, xfer)
436 rsp->sectors, xfer)nvme_show_message(1, "device reported %u sectors, more than the %d requested"
, rsp->sectors, xfer)
;
437 goto err_free_rsp;
438 }
439
440 data_size = rsp->sectors * 512;
441 memcpy(tbufp, rsp->data, data_size);
442 offset += rsp->sectors;
443 tbufp += data_size;
444 if (offset + chunk_size > msg_size)
445 xfer = msg_size - offset;
446 else
447 xfer = chunk_size;
448 free(req);
449 free(rsp);
450 }
451
452 *msg_buf = bufp;
453 return offset;
454
455err_free_rsp:
456 free(rsp);
457err_free_req:
458 free(req);
459err_free_bufp:
460 free(bufp);
461 return -1;
462}
463
464/* Implementation of programming authentication key to given RPMB target */
465static int rpmb_program_auth_key(struct libnvme_transport_handle *hdl, unsigned char target,
466 unsigned char *key_buf, int key_size)
467{
468 int req_size = sizeof(struct rpmb_data_frame_t);
469 int rsp_size = sizeof(struct rpmb_data_frame_t);
470
471 struct rpmb_data_frame_t *req = NULL((void*)0);
472 struct rpmb_data_frame_t *rsp = NULL((void*)0);
473
474 int err = -ENOMEM12;
475
476 req = rpmb_request_init(req_size, RPMB_REQ_AUTH_KEY_PROGRAM, target, 0, 0, 0, key_buf,
477 (223 - key_size), key_size);
478 if (!req) {
479 nvme_show_error("failed to allocate request buffer memory")nvme_show_message(1, "failed to allocate request buffer memory"
)
;
480 goto out;
481 }
482
483 /* send the request and get response */
484 err = send_rpmb_req(hdl, req->target, req_size, req);
485 if (err) {
486 nvme_show_error("RPMB request 0x%04x for 0x%x, err: %d", req->type, req->target,nvme_show_message(1, "RPMB request 0x%04x for 0x%x, err: %d",
req->type, req->target, err)
487 err)nvme_show_message(1, "RPMB request 0x%04x for 0x%x, err: %d",
req->type, req->target, err)
;
488 goto out;
489 }
490
491 /* send the request to get the result and then request to get the response */
492 rsp = calloc(rsp_size, 1);
493 if (!rsp) {
494 nvme_show_error("failed to allocate response buffer memory")nvme_show_message(1, "failed to allocate response buffer memory"
)
;
495 err = -ENOMEM12;
496 goto out;
497 }
498
499 rsp->target = req->target;
500 rsp->type = RPMB_REQ_READ_RESULT;
501 err = send_rpmb_req(hdl, req->target, rsp_size, rsp);
502 if (err || rsp->result) {
503 nvme_show_error("Program auth key read result 0x%x, error = 0x%x", rsp->result,nvme_show_message(1, "Program auth key read result 0x%x, error = 0x%x"
, rsp->result, err)
504 err)nvme_show_message(1, "Program auth key read result 0x%x, error = 0x%x"
, rsp->result, err)
;
505 goto out;
506 }
507
508 /* reuse response buffer */
509 memset(rsp, 0, rsp_size);
510 err = recv_rpmb_rsp(hdl, req->target, rsp_size, rsp);
511 if (err != 0)
512 nvme_show_error("Program Key recv error = 0x%x", err)nvme_show_message(1, "Program Key recv error = 0x%x", err);
513 else
514 err = check_rpmb_response(req, rsp, "Failed to Program Key");
515out:
516 free(req);
517 free(rsp);
518
519 return err;
520}
521
522/*
523 * Implementation of RPMB authenticated data write command; this function
524 * transfers msg_size bytes from msg_buf to controller 'addr'. Returns
525 * number of bytes actually written to, otherwise negative error code on
526 * failures.
527 */
528static int auth_data_write_chunk(struct libnvme_transport_handle *hdl, unsigned char tgt,
529 unsigned int addr, unsigned char *msg_buf, int msg_size,
530 unsigned char *keybuf, int keysize)
531{
532 int req_size = sizeof(struct rpmb_data_frame_t) + msg_size;
533 int rsp_size = sizeof(struct rpmb_data_frame_t);
534
535 struct rpmb_data_frame_t *req = NULL((void*)0);
536 struct rpmb_data_frame_t *rsp = NULL((void*)0);
537
538 unsigned int write_cntr = 0;
539 unsigned char *mac = NULL((void*)0);
540 int error = -ENOMEM12;
541
542 /* get current write counter and copy to the request */
543 error = rpmb_read_write_counter(hdl, tgt, &write_cntr);
544 if (error != 0) {
545 nvme_show_error("Failed to read write counter for write-data")nvme_show_message(1, "Failed to read write counter for write-data"
)
;
546 goto out;
547 }
548
549 req = rpmb_request_init(req_size, RPMB_REQ_AUTH_DATA_WRITE, tgt, 0, addr,
550 (msg_size / 512), msg_buf,
551 offsetof(struct rpmb_data_frame_t, data)__builtin_offsetof(struct rpmb_data_frame_t, data), msg_size);
552 if (!req) {
553 nvme_show_error("Memory alloc failed for write-data command")nvme_show_message(1, "Memory alloc failed for write-data command"
)
;
554 goto out;
555 }
556
557 req->write_counter = write_cntr;
558
559 /* compute HMAC hash */
560 mac = shr_hmac_sha256(((unsigned char *)req + 223), req_size - 223, keybuf, keysize);
561 if (!mac) {
562 nvme_show_error("failed to compute HMAC-SHA256")nvme_show_message(1, "failed to compute HMAC-SHA256");
563 error = -1;
564 goto out;
565 }
566
567 memcpy(req->mac, mac, 32);
568
569 /* send the request and get response */
570 error = send_rpmb_req(hdl, tgt, req_size, req);
571 if (error != 0) {
572 nvme_show_error("RPMB request 0x%04x for 0x%x, error: %d", req->type, tgt,nvme_show_message(1, "RPMB request 0x%04x for 0x%x, error: %d"
, req->type, tgt, error)
573 error)nvme_show_message(1, "RPMB request 0x%04x for 0x%x, error: %d"
, req->type, tgt, error)
;
574 goto out;
575 }
576
577 /* send the request to get the result and then request to get the response */
578 rsp = calloc(rsp_size, 1);
579 if (!rsp) {
580 nvme_show_error("failed to allocate response buffer memory")nvme_show_message(1, "failed to allocate response buffer memory"
)
;
581 error = -ENOMEM12;
582 goto out;
583 }
584 rsp->target = req->target;
585 rsp->type = RPMB_REQ_READ_RESULT;
586 error = send_rpmb_req(hdl, tgt, rsp_size, rsp);
587 if (error != 0 || rsp->result != 0) {
588 nvme_show_error("Write-data read result 0x%x, error = 0x%x", rsp->result,nvme_show_message(1, "Write-data read result 0x%x, error = 0x%x"
, rsp->result, error)
589 error)nvme_show_message(1, "Write-data read result 0x%x, error = 0x%x"
, rsp->result, error)
;
590 goto out;
591 }
592
593 /* Read final response */
594 memset(rsp, 0, rsp_size);
595 error = recv_rpmb_rsp(hdl, tgt, rsp_size, rsp);
596 if (error != 0)
597 nvme_show_error("Auth data write recv error = 0x%x", error)nvme_show_message(1, "Auth data write recv error = 0x%x", error
)
;
598 else
599 error = check_rpmb_response(req, rsp, "Failed to write-data");
600out:
601 free(req);
602 free(rsp);
603 free(mac);
604
605 return error;
606}
607
608/* send the request and get response */
609static int rpmb_auth_data_write(struct libnvme_transport_handle *hdl, unsigned char target,
610 unsigned int addr, int acc_size, unsigned char *msg_buf,
611 int msg_size, unsigned char *keybuf, int keysize)
612{
613 int chunk_size = acc_size < msg_size ? acc_size : msg_size;
614 int xfer = chunk_size;
615 int offset = 0;
616
617 while (xfer > 0) {
618 if (auth_data_write_chunk(hdl, target, (addr + offset / 512), msg_buf + offset,
619 xfer, keybuf, keysize) != 0) {
620 /* error writing chunk data */
621 break;
622 }
623
624 offset += xfer;
625 if (offset + chunk_size > msg_size)
626 xfer = msg_size - offset;
627 else
628 xfer = chunk_size;
629 }
630
631 return offset;
632}
633
634/* writes given config_block buffer to the drive target 0 */
635static int rpmb_write_config_block(struct libnvme_transport_handle *hdl,
636 unsigned char *cfg_buf, unsigned char *keybuf, int keysize)
637{
638 int cfg_size = sizeof(struct rpmb_config_block_t);
639 int rsp_size = sizeof(struct rpmb_data_frame_t);
640 int req_size = rsp_size + cfg_size;
641
642 struct rpmb_data_frame_t *req = NULL((void*)0);
643 struct rpmb_data_frame_t *rsp = NULL((void*)0);
644 unsigned char *cfg_buf_read = NULL((void*)0), *mac = NULL((void*)0);
645 unsigned int write_cntr = 0;
646 int error = -ENOMEM12;
647
648 /* initialize request */
649 req = rpmb_request_init(req_size, RPMB_REQ_AUTH_DCB_WRITE, 0, 0, 0, 1, cfg_buf,
650 offsetof(struct rpmb_data_frame_t, data)__builtin_offsetof(struct rpmb_data_frame_t, data), cfg_size);
651 if (!req) {
652 nvme_show_error("failed to allocate rpmb request buffer")nvme_show_message(1, "failed to allocate rpmb request buffer"
)
;
653 goto out;
654 }
655
656 /* read config block write_counter from controller */
657 write_cntr = rpmb_read_config_block(hdl, &cfg_buf_read);
658 if (!cfg_buf_read) {
659 nvme_show_error("failed to read config block write counter")nvme_show_message(1, "failed to read config block write counter"
)
;
660 error = -EIO5;
661 goto out;
662 }
663
664 free(cfg_buf_read);
665 req->write_counter = write_cntr;
666 mac = shr_hmac_sha256(((unsigned char *)req + 223), req_size - 223, keybuf, keysize);
667 if (!mac) {
668 nvme_show_error("failed to compute hmac-sha256 hash")nvme_show_message(1, "failed to compute hmac-sha256 hash");
669 error = -EINVAL22;
670 goto out;
671 }
672
673 memcpy(req->mac, mac, sizeof(req->mac));
674
675 error = send_rpmb_req(hdl, 0, req_size, req);
676 if (error != 0) {
677 nvme_show_error("Write-config RPMB request, error = 0x%x", error)nvme_show_message(1, "Write-config RPMB request, error = 0x%x"
, error)
;
678 goto out;
679 }
680
681 /* get response */
682 rsp = calloc(rsp_size, 1);
683 if (!rsp) {
684 nvme_show_error("failed to allocate response buffer memory")nvme_show_message(1, "failed to allocate response buffer memory"
)
;
685 error = -ENOMEM12;
686 goto out;
687 }
688
689 /* get result first */
690 memset(rsp, 0, rsp_size);
691 rsp->target = req->target;
692 rsp->type = RPMB_REQ_READ_RESULT;
693 /* get the response and validate */
694 error = recv_rpmb_rsp(hdl, req->target, rsp_size, rsp);
695 if (error != 0) {
696 nvme_show_error("Failed getting write-config response error = 0x%x", error)nvme_show_message(1, "Failed getting write-config response error = 0x%x"
, error)
;
697 goto out;
698 }
699 error = check_rpmb_response(req, rsp, "Failed to retrieve write-config response");
700out:
701 free(req);
702 free(rsp);
703 free(mac);
704
705 return error;
706}
707
708static bool_Bool invalid_xfer_size(int blocks, unsigned int bpsz)
709{
710 return (blocks <= 0) || (blocks * 512) > ((bpsz + 1) * 128 * 1024);
711}
712
713/* Identify the controller and fetch its RPMBS support register */
714static int rpmb_get_regs(struct libnvme_transport_handle *hdl, union ctrl_rpmbs_reg *regs)
715{
716 struct nvme_id_ctrl ctrl;
717 struct libnvme_passthru_cmd cmd;
718 int err;
719
720 nvme_init_identify_ctrl(&cmd, &ctrl);
721 err = libnvme_exec_admin_passthru(hdl, &cmd);
722 if (err)
723 return err;
724
725 regs->rpmbs = le32_to_cpu(ctrl.rpmbs);
726 if (regs->num_targets == 0) {
727 nvme_show_error("No RPMB targets are supported by the drive")nvme_show_message(1, "No RPMB targets are supported by the drive"
)
;
728 return -1;
729 }
730
731 return 0;
732}
733
734/* Read key from a given key buffer or key file and validate its size */
735static unsigned char *rpmb_read_and_validate_key(char *keystr, char *keyfile,
736 unsigned int *keysize)
737{
738 unsigned char *keybuf = read_rpmb_key(keystr, keyfile, keysize);
739
740 if (!keybuf) {
741 nvme_show_error("Failed to read key")nvme_show_message(1, "Failed to read key");
742 return NULL((void*)0);
743 }
744
745 if (*keysize > 223 || *keysize == 0) {
746 nvme_show_error("Invalid key size %u, valid input 1 to 223", *keysize)nvme_show_message(1, "Invalid key size %u, valid input 1 to 223"
, *keysize)
;
747 libnvme_free(keybuf);
748 return NULL((void*)0);
749 }
750
751 return keybuf;
752}
753
754/* Read msg data from either a literal string or a file */
755static int rpmb_read_msg(char *msgstr, char *msgfile, unsigned char **msg_buf,
756 unsigned int *msg_size)
757{
758 if (msgstr) {
759 size_t len = strlen(msgstr);
760
761 *msg_buf = libnvme_alloc(len + 1);
762 if (!*msg_buf)
763 return -ENOMEM12;
764 *msg_size = len;
765 memcpy(*msg_buf, msgstr, len);
766 return 0;
767 }
768
769 return read_file(msgfile, msg_buf, msg_size);
770}
771
772static int rpmb_info(int argc, char **argv, struct command *acmd, struct plugin *plugin)
773{
774 const char *desc = "Print RPMB support information for the controller";
775
776 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
777 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
778 union ctrl_rpmbs_reg regs;
779 int err;
780
781 NVME_ARGS(opts)nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0
, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT
, &nvme_args.verbose, 0, "Increase output verbosity", 0, }
, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0,
"suppress informational output", 0, }, {"output-format", 'o'
, "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
782
783 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
784 if (err)
785 return err;
786
787 err = rpmb_get_regs(hdl, &regs);
788 if (err)
789 return err;
790
791 nvme_show_id_ctrl_rpmbs(regs.rpmbs, 0);
792
793 return 0;
794}
795
796static int rpmb_program_key(int argc, char **argv, struct command *acmd, struct plugin *plugin)
797{
798 const char *desc = "Program the RPMB authentication key for a given target";
799 const char *key = "key to be used for authentication";
800 const char *kfile = "key file that has authentication key to be used";
801 const char *target = "RPMB target - numerical value of 0 to 6, default 0";
802
803 struct config {
804 char *key;
805 char *keyfile;
806 __u8 target;
807 };
808
809 struct config cfg = {
810 .key = NULL((void*)0),
811 .keyfile = NULL((void*)0),
812 .target = 0,
813 };
814
815 NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"key", 'k', "key", CFG_STRING, &cfg.key, 1, key, 0
, }, {"keyfile", 'g', "FILE", CFG_STRING, &cfg.keyfile, 1
, kfile, 0, }, {"target", 't', "NUM", CFG_BYTE, &cfg.target
, 1, target, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, (
(void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v'
, "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
816 OPT_STRING("key", 'k', "key", &cfg.key, key),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"key", 'k', "key", CFG_STRING, &cfg.key, 1, key, 0
, }, {"keyfile", 'g', "FILE", CFG_STRING, &cfg.keyfile, 1
, kfile, 0, }, {"target", 't', "NUM", CFG_BYTE, &cfg.target
, 1, target, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, (
(void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v'
, "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
817 OPT_STRING("keyfile", 'g', "FILE", &cfg.keyfile, kfile),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"key", 'k', "key", CFG_STRING, &cfg.key, 1, key, 0
, }, {"keyfile", 'g', "FILE", CFG_STRING, &cfg.keyfile, 1
, kfile, 0, }, {"target", 't', "NUM", CFG_BYTE, &cfg.target
, 1, target, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, (
(void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v'
, "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
818 OPT_BYTE("target", 't', &cfg.target, target))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"key", 'k', "key", CFG_STRING, &cfg.key, 1, key, 0
, }, {"keyfile", 'g', "FILE", CFG_STRING, &cfg.keyfile, 1
, kfile, 0, }, {"target", 't', "NUM", CFG_BYTE, &cfg.target
, 1, target, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, (
(void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v'
, "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
819
820 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
821 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
822 __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) unsigned char *key_buf = NULL((void*)0);
823 union ctrl_rpmbs_reg regs;
824 unsigned int key_size = 0;
825 int err;
826
827 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
828 if (err)
829 return err;
830
831 err = rpmb_get_regs(hdl, &regs);
832 if (err)
833 return err;
834
835 key_buf = rpmb_read_and_validate_key(cfg.key, cfg.keyfile, &key_size);
836 if (!key_buf)
837 return -1;
838
839 err = rpmb_program_auth_key(hdl, cfg.target, key_buf, key_size);
840 if (!err)
841 nvme_show_verbose_result("RPMB authentication key programmed")nvme_show_verbose_message("RPMB authentication key programmed"
)
;
842
843 return err;
844}
845
846static int rpmb_read_counter(int argc, char **argv, struct command *acmd,
847 struct plugin *plugin)
848{
849 const char *desc = "Read the current RPMB write counter for a given target";
850 const char *target = "RPMB target - numerical value of 0 to 6, default 0";
851
852 struct config {
853 __u8 target;
854 };
855
856 struct config cfg = {
857 .target = 0,
858 };
859
860 NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"target", 't', "NUM", CFG_BYTE, &cfg.target, 1, target
, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0
, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT
, &nvme_args.verbose, 0, "Increase output verbosity", 0, }
, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0,
"suppress informational output", 0, }, {"output-format", 'o'
, "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
861 OPT_BYTE("target", 't', &cfg.target, target))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"target", 't', "NUM", CFG_BYTE, &cfg.target, 1, target
, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0
, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM", CFG_INCREMENT
, &nvme_args.verbose, 0, "Increase output verbosity", 0, }
, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet, 0,
"suppress informational output", 0, }, {"output-format", 'o'
, "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
862
863 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
864 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
865 union ctrl_rpmbs_reg regs;
866 unsigned int write_cntr = 0;
867 int err;
868
869 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
870 if (err)
871 return err;
872
873 err = rpmb_get_regs(hdl, &regs);
874 if (err)
875 return err;
876
877 err = rpmb_read_write_counter(hdl, cfg.target, &write_cntr);
878 if (!err)
879 nvme_show_result("Write Counter is: %u", write_cntr)nvme_show_message(0, "Write Counter is: %u", write_cntr);
880
881 return err;
882}
883
884static int rpmb_read_data(int argc, char **argv, struct command *acmd, struct plugin *plugin)
885{
886 const char *desc = "Read authenticated data from an RPMB target";
887 const char *mfile = "data file to save read data to";
888 const char *target = "RPMB target - numerical value of 0 to 6, default 0";
889 const char *address = "Sector offset to read from for an RPMB target, default 0";
890 const char *blocks = "Number of 512 byte blocks to read";
891
892 struct config {
893 char *msgfile;
894 __u32 address;
895 __u32 blocks;
896 __u8 target;
897 };
898
899 struct config cfg = {
900 .msgfile = NULL((void*)0),
901 .address = 0,
902 .blocks = 0,
903 .target = 0,
904 };
905
906 NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"msgfile", 'f', "FILE", CFG_STRING, &cfg.msgfile,
1, mfile, 0, }, {"address", 'o', "NUM", CFG_POSITIVE, &cfg
.address, 1, address, 0, }, {"blocks", 'b', "NUM", CFG_POSITIVE
, &cfg.blocks, 1, blocks, 0, }, {"target", 't', "NUM", CFG_BYTE
, &cfg.target, 1, target, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
907 OPT_STRING("msgfile", 'f', "FILE", &cfg.msgfile, mfile),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"msgfile", 'f', "FILE", CFG_STRING, &cfg.msgfile,
1, mfile, 0, }, {"address", 'o', "NUM", CFG_POSITIVE, &cfg
.address, 1, address, 0, }, {"blocks", 'b', "NUM", CFG_POSITIVE
, &cfg.blocks, 1, blocks, 0, }, {"target", 't', "NUM", CFG_BYTE
, &cfg.target, 1, target, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
908 OPT_UINT("address", 'o', &cfg.address, address),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"msgfile", 'f', "FILE", CFG_STRING, &cfg.msgfile,
1, mfile, 0, }, {"address", 'o', "NUM", CFG_POSITIVE, &cfg
.address, 1, address, 0, }, {"blocks", 'b', "NUM", CFG_POSITIVE
, &cfg.blocks, 1, blocks, 0, }, {"target", 't', "NUM", CFG_BYTE
, &cfg.target, 1, target, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
909 OPT_UINT("blocks", 'b', &cfg.blocks, blocks),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"msgfile", 'f', "FILE", CFG_STRING, &cfg.msgfile,
1, mfile, 0, }, {"address", 'o', "NUM", CFG_POSITIVE, &cfg
.address, 1, address, 0, }, {"blocks", 'b', "NUM", CFG_POSITIVE
, &cfg.blocks, 1, blocks, 0, }, {"target", 't', "NUM", CFG_BYTE
, &cfg.target, 1, target, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
910 OPT_BYTE("target", 't', &cfg.target, target))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"msgfile", 'f', "FILE", CFG_STRING, &cfg.msgfile,
1, mfile, 0, }, {"address", 'o', "NUM", CFG_POSITIVE, &cfg
.address, 1, address, 0, }, {"blocks", 'b', "NUM", CFG_POSITIVE
, &cfg.blocks, 1, blocks, 0, }, {"target", 't', "NUM", CFG_BYTE
, &cfg.target, 1, target, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
911
912 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
913 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
914 __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) unsigned char *msg_buf = NULL((void*)0);
915 union ctrl_rpmbs_reg regs;
916 int err;
917
918 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
919 if (err)
1
Assuming 'err' is 0
2
Taking false branch
920 return err;
921
922 err = rpmb_get_regs(hdl, &regs);
923 if (err
2.1
'err' is 0
)
3
Taking false branch
924 return err;
925
926 if (invalid_xfer_size(cfg.blocks, regs.total_size)) {
4
Taking false branch
927 nvme_show_error("invalid transfer size %u", cfg.blocks * 512)nvme_show_message(1, "invalid transfer size %u", cfg.blocks *
512)
;
928 return -1;
929 }
930
931 err = rpmb_auth_data_read(hdl, cfg.target, cfg.address, &msg_buf, cfg.blocks,
5
Calling 'rpmb_auth_data_read'
13
Returned allocated memory via 4th parameter
932 (regs.access_size + 1));
933 if (err > 0 && msg_buf) {
14
Assuming 'err' is <= 0
934 nvme_show_result("Writing %d bytes to file %s", err * 512, cfg.msgfile)nvme_show_message(0, "Writing %d bytes to file %s", err * 512
, cfg.msgfile)
;
935 write_file(msg_buf, err * 512, NULL((void*)0), cfg.msgfile, NULL((void*)0));
936 }
937
938 return err > 0 ? 0 : err;
15
Potential leak of memory pointed to by 'msg_buf'
939}
940
941static int rpmb_write_data(int argc, char **argv, struct command *acmd, struct plugin *plugin)
942{
943 const char *desc = "Write authenticated data to an RPMB target";
944 const char *msg = "data to be written";
945 const char *mfile = "data file to be written";
946 const char *kfile = "key file that has authentication key to be used";
947 const char *target = "RPMB target - numerical value of 0 to 6, default 0";
948 const char *address = "Sector offset to write to for an RPMB target, default 0";
949 const char *blocks = "Number of 512 byte blocks to write";
950 const char *key = "key to be used for authentication";
951
952 struct config {
953 char *key;
954 char *msg;
955 char *keyfile;
956 char *msgfile;
957 __u32 address;
958 __u32 blocks;
959 __u8 target;
960 };
961
962 struct config cfg = {
963 .key = NULL((void*)0),
964 .msg = NULL((void*)0),
965 .msgfile = NULL((void*)0),
966 .keyfile = NULL((void*)0),
967 .address = 0,
968 .blocks = 0,
969 .target = 0,
970 };
971
972 NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"msgfile", 'f', "FILE", CFG_STRING, &cfg.msgfile,
1, mfile, 0, }, {"keyfile", 'g', "FILE", CFG_STRING, &cfg
.keyfile, 1, kfile, 0, }, {"key", 'k', "key", CFG_STRING, &
cfg.key, 1, key, 0, }, {"msg", 'd', "data", CFG_STRING, &
cfg.msg, 1, msg, 0, }, {"address", 'o', "NUM", CFG_POSITIVE, &
cfg.address, 1, address, 0, }, {"blocks", 'b', "NUM", CFG_POSITIVE
, &cfg.blocks, 1, blocks, 0, }, {"target", 't', "NUM", CFG_BYTE
, &cfg.target, 1, target, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
973 OPT_STRING("msgfile", 'f', "FILE", &cfg.msgfile, mfile),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"msgfile", 'f', "FILE", CFG_STRING, &cfg.msgfile,
1, mfile, 0, }, {"keyfile", 'g', "FILE", CFG_STRING, &cfg
.keyfile, 1, kfile, 0, }, {"key", 'k', "key", CFG_STRING, &
cfg.key, 1, key, 0, }, {"msg", 'd', "data", CFG_STRING, &
cfg.msg, 1, msg, 0, }, {"address", 'o', "NUM", CFG_POSITIVE, &
cfg.address, 1, address, 0, }, {"blocks", 'b', "NUM", CFG_POSITIVE
, &cfg.blocks, 1, blocks, 0, }, {"target", 't', "NUM", CFG_BYTE
, &cfg.target, 1, target, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
974 OPT_STRING("keyfile", 'g', "FILE", &cfg.keyfile, kfile),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"msgfile", 'f', "FILE", CFG_STRING, &cfg.msgfile,
1, mfile, 0, }, {"keyfile", 'g', "FILE", CFG_STRING, &cfg
.keyfile, 1, kfile, 0, }, {"key", 'k', "key", CFG_STRING, &
cfg.key, 1, key, 0, }, {"msg", 'd', "data", CFG_STRING, &
cfg.msg, 1, msg, 0, }, {"address", 'o', "NUM", CFG_POSITIVE, &
cfg.address, 1, address, 0, }, {"blocks", 'b', "NUM", CFG_POSITIVE
, &cfg.blocks, 1, blocks, 0, }, {"target", 't', "NUM", CFG_BYTE
, &cfg.target, 1, target, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
975 OPT_STRING("key", 'k', "key", &cfg.key, key),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"msgfile", 'f', "FILE", CFG_STRING, &cfg.msgfile,
1, mfile, 0, }, {"keyfile", 'g', "FILE", CFG_STRING, &cfg
.keyfile, 1, kfile, 0, }, {"key", 'k', "key", CFG_STRING, &
cfg.key, 1, key, 0, }, {"msg", 'd', "data", CFG_STRING, &
cfg.msg, 1, msg, 0, }, {"address", 'o', "NUM", CFG_POSITIVE, &
cfg.address, 1, address, 0, }, {"blocks", 'b', "NUM", CFG_POSITIVE
, &cfg.blocks, 1, blocks, 0, }, {"target", 't', "NUM", CFG_BYTE
, &cfg.target, 1, target, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
976 OPT_STRING("msg", 'd', "data", &cfg.msg, msg),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"msgfile", 'f', "FILE", CFG_STRING, &cfg.msgfile,
1, mfile, 0, }, {"keyfile", 'g', "FILE", CFG_STRING, &cfg
.keyfile, 1, kfile, 0, }, {"key", 'k', "key", CFG_STRING, &
cfg.key, 1, key, 0, }, {"msg", 'd', "data", CFG_STRING, &
cfg.msg, 1, msg, 0, }, {"address", 'o', "NUM", CFG_POSITIVE, &
cfg.address, 1, address, 0, }, {"blocks", 'b', "NUM", CFG_POSITIVE
, &cfg.blocks, 1, blocks, 0, }, {"target", 't', "NUM", CFG_BYTE
, &cfg.target, 1, target, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
977 OPT_UINT("address", 'o', &cfg.address, address),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"msgfile", 'f', "FILE", CFG_STRING, &cfg.msgfile,
1, mfile, 0, }, {"keyfile", 'g', "FILE", CFG_STRING, &cfg
.keyfile, 1, kfile, 0, }, {"key", 'k', "key", CFG_STRING, &
cfg.key, 1, key, 0, }, {"msg", 'd', "data", CFG_STRING, &
cfg.msg, 1, msg, 0, }, {"address", 'o', "NUM", CFG_POSITIVE, &
cfg.address, 1, address, 0, }, {"blocks", 'b', "NUM", CFG_POSITIVE
, &cfg.blocks, 1, blocks, 0, }, {"target", 't', "NUM", CFG_BYTE
, &cfg.target, 1, target, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
978 OPT_UINT("blocks", 'b', &cfg.blocks, blocks),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"msgfile", 'f', "FILE", CFG_STRING, &cfg.msgfile,
1, mfile, 0, }, {"keyfile", 'g', "FILE", CFG_STRING, &cfg
.keyfile, 1, kfile, 0, }, {"key", 'k', "key", CFG_STRING, &
cfg.key, 1, key, 0, }, {"msg", 'd', "data", CFG_STRING, &
cfg.msg, 1, msg, 0, }, {"address", 'o', "NUM", CFG_POSITIVE, &
cfg.address, 1, address, 0, }, {"blocks", 'b', "NUM", CFG_POSITIVE
, &cfg.blocks, 1, blocks, 0, }, {"target", 't', "NUM", CFG_BYTE
, &cfg.target, 1, target, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
979 OPT_BYTE("target", 't', &cfg.target, target))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"msgfile", 'f', "FILE", CFG_STRING, &cfg.msgfile,
1, mfile, 0, }, {"keyfile", 'g', "FILE", CFG_STRING, &cfg
.keyfile, 1, kfile, 0, }, {"key", 'k', "key", CFG_STRING, &
cfg.key, 1, key, 0, }, {"msg", 'd', "data", CFG_STRING, &
cfg.msg, 1, msg, 0, }, {"address", 'o', "NUM", CFG_POSITIVE, &
cfg.address, 1, address, 0, }, {"blocks", 'b', "NUM", CFG_POSITIVE
, &cfg.blocks, 1, blocks, 0, }, {"target", 't', "NUM", CFG_BYTE
, &cfg.target, 1, target, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
980
981 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
982 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
983 __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) unsigned char *key_buf = NULL((void*)0);
984 __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) unsigned char *msg_buf = NULL((void*)0);
985 union ctrl_rpmbs_reg regs;
986 unsigned int key_size = 0;
987 unsigned int msg_size = 0;
988 int err;
989
990 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
991 if (err)
992 return err;
993
994 err = rpmb_get_regs(hdl, &regs);
995 if (err)
996 return err;
997
998 key_buf = rpmb_read_and_validate_key(cfg.key, cfg.keyfile, &key_size);
999 if (!key_buf)
1000 return -1;
1001
1002 err = rpmb_read_msg(cfg.msg, cfg.msgfile, &msg_buf, &msg_size);
1003 if (err || !msg_size) {
1004 nvme_show_error("Failed to read msg data")nvme_show_message(1, "Failed to read msg data");
1005 return -1;
1006 }
1007
1008 if (invalid_xfer_size(cfg.blocks, regs.total_size) || (cfg.blocks * 512) > msg_size) {
1009 nvme_show_error("invalid transfer size %u", cfg.blocks * 512)nvme_show_message(1, "invalid transfer size %u", cfg.blocks *
512)
;
1010 return -1;
1011 } else if ((cfg.blocks * 512) < msg_size) {
1012 msg_size = cfg.blocks * 512;
1013 }
1014
1015 err = rpmb_auth_data_write(hdl, cfg.target, cfg.address, ((regs.access_size + 1) * 512),
1016 msg_buf, msg_size, key_buf, key_size);
1017
1018 /* print whatever extent of data written to target */
1019 nvme_show_result("Written %d sectors out of %u @target(%d):0x%x", err / 512,nvme_show_message(0, "Written %d sectors out of %u @target(%d):0x%x"
, err / 512, msg_size / 512, cfg.target, cfg.address)
1020 msg_size / 512, cfg.target, cfg.address)nvme_show_message(0, "Written %d sectors out of %u @target(%d):0x%x"
, err / 512, msg_size / 512, cfg.target, cfg.address)
;
1021
1022 return err == (int)msg_size ? 0 : -1;
1023}
1024
1025static int rpmb_read_config(int argc, char **argv, struct command *acmd,
1026 struct plugin *plugin)
1027{
1028 const char *desc = "Read the RPMB device configuration block";
1029 const char *mfile = "data file to save the read configuration block to";
1030
1031 struct config {
1032 char *msgfile;
1033 };
1034
1035 struct config cfg = {
1036 .msgfile = NULL((void*)0),
1037 };
1038
1039 NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"msgfile", 'f', "FILE", CFG_STRING, &cfg.msgfile,
1, mfile, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void
*)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM"
, CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
1040 OPT_STRING("msgfile", 'f', "FILE", &cfg.msgfile, mfile))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"msgfile", 'f', "FILE", CFG_STRING, &cfg.msgfile,
1, mfile, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR, ((void
*)0), 0, "Global options", 0, ((void*)0)}, {"verbose", 'v', "NUM"
, CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
1041
1042 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
1043 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
1044 __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) unsigned char *msg_buf = NULL((void*)0);
1045 union ctrl_rpmbs_reg regs;
1046 unsigned int write_cntr;
1047 int err;
1048
1049 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
1050 if (err)
1051 return err;
1052
1053 err = rpmb_get_regs(hdl, &regs);
1054 if (err)
1055 return err;
1056
1057 write_cntr = rpmb_read_config_block(hdl, &msg_buf);
1058 if (!msg_buf) {
1059 nvme_show_error("failed to read config block")nvme_show_message(1, "failed to read config block");
1060 return -1;
1061 }
1062
1063 if (!cfg.msgfile) {
1064 struct rpmb_config_block_t *rcfg = (struct rpmb_config_block_t *)msg_buf;
1065
1066 nvme_show_result("Boot Partition Protection is %s",nvme_show_message(0, "Boot Partition Protection is %s", (rcfg
->bp_enable & 0x1) ? "Enabled" : "Disabled")
1067 (rcfg->bp_enable & 0x1) ? "Enabled" : "Disabled")nvme_show_message(0, "Boot Partition Protection is %s", (rcfg
->bp_enable & 0x1) ? "Enabled" : "Disabled")
;
1068 nvme_show_result("Boot Partition 1 is %s",nvme_show_message(0, "Boot Partition 1 is %s", (rcfg->bp_lock
& 0x2) ? "Locked" : "Unlocked")
1069 (rcfg->bp_lock & 0x2) ? "Locked" : "Unlocked")nvme_show_message(0, "Boot Partition 1 is %s", (rcfg->bp_lock
& 0x2) ? "Locked" : "Unlocked")
;
1070 nvme_show_result("Boot Partition 0 is %s",nvme_show_message(0, "Boot Partition 0 is %s", (rcfg->bp_lock
& 0x1) ? "Locked" : "Unlocked")
1071 (rcfg->bp_lock & 0x1) ? "Locked" : "Unlocked")nvme_show_message(0, "Boot Partition 0 is %s", (rcfg->bp_lock
& 0x1) ? "Locked" : "Unlocked")
;
1072 } else {
1073 nvme_show_result("Saving received config data to %s file", cfg.msgfile)nvme_show_message(0, "Saving received config data to %s file"
, cfg.msgfile)
;
1074 write_file(msg_buf, sizeof(struct rpmb_config_block_t), NULL((void*)0), cfg.msgfile,
1075 NULL((void*)0));
1076 }
1077
1078 return write_cntr == 0 ? -1 : 0;
1079}
1080
1081static int rpmb_write_config(int argc, char **argv, struct command *acmd,
1082 struct plugin *plugin)
1083{
1084 const char *desc = "Write the RPMB device configuration block";
1085 const char *msg = "configuration block data to be written";
1086 const char *mfile = "data file with the configuration block to be written";
1087 const char *kfile = "key file that has authentication key to be used";
1088 const char *key = "key to be used for authentication";
1089
1090 struct config {
1091 char *key;
1092 char *msg;
1093 char *keyfile;
1094 char *msgfile;
1095 };
1096
1097 struct config cfg = {
1098 .key = NULL((void*)0),
1099 .msg = NULL((void*)0),
1100 .msgfile = NULL((void*)0),
1101 .keyfile = NULL((void*)0),
1102 };
1103
1104 NVME_ARGS(opts,nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"msgfile", 'f', "FILE", CFG_STRING, &cfg.msgfile,
1, mfile, 0, }, {"keyfile", 'g', "FILE", CFG_STRING, &cfg
.keyfile, 1, kfile, 0, }, {"key", 'k', "key", CFG_STRING, &
cfg.key, 1, key, 0, }, {"msg", 'd', "data", CFG_STRING, &
cfg.msg, 1, msg, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
1105 OPT_STRING("msgfile", 'f', "FILE", &cfg.msgfile, mfile),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"msgfile", 'f', "FILE", CFG_STRING, &cfg.msgfile,
1, mfile, 0, }, {"keyfile", 'g', "FILE", CFG_STRING, &cfg
.keyfile, 1, kfile, 0, }, {"key", 'k', "key", CFG_STRING, &
cfg.key, 1, key, 0, }, {"msg", 'd', "data", CFG_STRING, &
cfg.msg, 1, msg, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
1106 OPT_STRING("keyfile", 'g', "FILE", &cfg.keyfile, kfile),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"msgfile", 'f', "FILE", CFG_STRING, &cfg.msgfile,
1, mfile, 0, }, {"keyfile", 'g', "FILE", CFG_STRING, &cfg
.keyfile, 1, kfile, 0, }, {"key", 'k', "key", CFG_STRING, &
cfg.key, 1, key, 0, }, {"msg", 'd', "data", CFG_STRING, &
cfg.msg, 1, msg, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
1107 OPT_STRING("key", 'k', "key", &cfg.key, key),nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"msgfile", 'f', "FILE", CFG_STRING, &cfg.msgfile,
1, mfile, 0, }, {"keyfile", 'g', "FILE", CFG_STRING, &cfg
.keyfile, 1, kfile, 0, }, {"key", 'k', "key", CFG_STRING, &
cfg.key, 1, key, 0, }, {"msg", 'd', "data", CFG_STRING, &
cfg.msg, 1, msg, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
1108 OPT_STRING("msg", 'd', "data", &cfg.msg, msg))nvme_args.supported_output_formats = (NORMAL | JSON | BINARY)
; struct argconfig_commandline_options opts[] = { {"", 0, ((void
*)0), CFG_GROUP_SEPARATOR, ((void*)0), 0, "Options", 0, ((void
*)0)}, {"msgfile", 'f', "FILE", CFG_STRING, &cfg.msgfile,
1, mfile, 0, }, {"keyfile", 'g', "FILE", CFG_STRING, &cfg
.keyfile, 1, kfile, 0, }, {"key", 'k', "key", CFG_STRING, &
cfg.key, 1, key, 0, }, {"msg", 'd', "data", CFG_STRING, &
cfg.msg, 1, msg, 0, }, {"", 0, ((void*)0), CFG_GROUP_SEPARATOR
, ((void*)0), 0, "Global options", 0, ((void*)0)}, {"verbose"
, 'v', "NUM", CFG_INCREMENT, &nvme_args.verbose, 0, "Increase output verbosity"
, 0, }, {"quiet", 0, ((void*)0), CFG_FLAG, &nvme_args.quiet
, 0, "suppress informational output", 0, }, {"output-format",
'o', "FMT", CFG_STRING, &nvme_args.output_format, 1, "Output format: normal|json|binary"
, 0, }, {"timeout", 0, "NUM", CFG_POSITIVE, &nvme_args.timeout
, 1, "timeout value, in milliseconds", 0, }, {"dry-run", 0, (
(void*)0), CFG_FLAG, &nvme_args.dry_run, 0, "show command instead of executing"
, 0, }, {"no-retries", 0, ((void*)0), CFG_FLAG, &nvme_args
.no_retries, 0, "disable retry logic on errors", 0, }, {"no-ioctl-probing"
, 0, ((void*)0), CFG_FLAG, &nvme_args.no_ioctl_probing, 0
, "disable 64-bit IOCTL support probing", 0, }, {"output-format-version"
, 0, "NUM", CFG_POSITIVE, &nvme_args.output_format_ver, 1
, "output format version: 1|2", 0, }, {"human-readable", 'H',
((void*)0), CFG_FLAG, &nvme_args.verbose, 0, ((void*)0),
0, ((void*)0), 1}, {"set-options", 0, "KEY=VALUE", CFG_STRING
, &nvme_args.set_options, 1, "set a libnvme library option (key=value[,key=value,...]);"
, 0, }, { ((void*)0) } }
;
1109
1110 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
1111 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
1112 __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) unsigned char *key_buf = NULL((void*)0);
1113 __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) unsigned char *msg_buf = NULL((void*)0);
1114 union ctrl_rpmbs_reg regs;
1115 unsigned int key_size = 0;
1116 unsigned int msg_size = 0;
1117 int err;
1118
1119 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
1120 if (err)
1121 return err;
1122
1123 err = rpmb_get_regs(hdl, &regs);
1124 if (err)
1125 return err;
1126
1127 key_buf = rpmb_read_and_validate_key(cfg.key, cfg.keyfile, &key_size);
1128 if (!key_buf)
1129 return -1;
1130
1131 err = rpmb_read_msg(cfg.msg, cfg.msgfile, &msg_buf, &msg_size);
1132 if (err || !msg_size) {
1133 nvme_show_error("Failed to read msg data")nvme_show_message(1, "Failed to read msg data");
1134 return -1;
1135 }
1136
1137 if (msg_size < sizeof(struct rpmb_config_block_t)) {
1138 nvme_show_error("invalid config block size %u, expected %zu", msg_size,nvme_show_message(1, "invalid config block size %u, expected %zu"
, msg_size, sizeof(struct rpmb_config_block_t))
1139 sizeof(struct rpmb_config_block_t))nvme_show_message(1, "invalid config block size %u, expected %zu"
, msg_size, sizeof(struct rpmb_config_block_t))
;
1140 return -1;
1141 }
1142
1143 err = rpmb_write_config_block(hdl, msg_buf, key_buf, key_size);
1144 if (!err)
1145 nvme_show_verbose_result("RPMB configuration block written")nvme_show_verbose_message("RPMB configuration block written");
1146
1147 return err;
1148}
1149
1150static struct command rpmb_info_cmd = {
1151 .name = "info",
1152 .help = "Print RPMB support information for the controller",
1153 .fn = rpmb_info,
1154};
1155
1156static struct command rpmb_program_key_cmd = {
1157 .name = "program-key",
1158 .help = "Program the RPMB authentication key",
1159 .fn = rpmb_program_key,
1160};
1161
1162static struct command rpmb_read_counter_cmd = {
1163 .name = "read-counter",
1164 .help = "Read the RPMB write counter",
1165 .fn = rpmb_read_counter,
1166};
1167
1168static struct command rpmb_read_data_cmd = {
1169 .name = "read-data",
1170 .help = "Read authenticated data from an RPMB target",
1171 .fn = rpmb_read_data,
1172};
1173
1174static struct command rpmb_write_data_cmd = {
1175 .name = "write-data",
1176 .help = "Write authenticated data to an RPMB target",
1177 .fn = rpmb_write_data,
1178};
1179
1180static struct command rpmb_read_config_cmd = {
1181 .name = "read-config",
1182 .help = "Read the RPMB device configuration block",
1183 .fn = rpmb_read_config,
1184};
1185
1186static struct command rpmb_write_config_cmd = {
1187 .name = "write-config",
1188 .help = "Write the RPMB device configuration block",
1189 .fn = rpmb_write_config,
1190};
1191
1192static struct command *commands[] = {
1193 &rpmb_info_cmd,
1194 &rpmb_program_key_cmd,
1195 &rpmb_read_counter_cmd,
1196 &rpmb_read_data_cmd,
1197 &rpmb_write_data_cmd,
1198 &rpmb_read_config_cmd,
1199 &rpmb_write_config_cmd,
1200 NULL((void*)0),
1201};
1202
1203static struct plugin plugin = {
1204 .name = "rpmb",
1205 .desc = "Replay Protected Memory Block commands",
1206 .version = NVME_VERSION"3.1",
1207 .core = true1,
1208 .group = "Security & Access Control",
1209};
1210
1211static void __shr_constructor__attribute__((constructor)) register_plugin(void)
1212{
1213 plugin_add_group(&plugin, NULL((void*)0), commands);
1214 register_extension(&plugin);
1215}