Bug Summary

File:.build-ci/../plugins/rpmb/rpmb.c
Warning:line 1085, column 3
Potential leak of memory pointed to by 'rcfg'

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-11-02-081605-642-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 *file,
92 const char *msg)
93{
94 __cleanup_file__attribute__((cleanup(shr_cleanup_file))) FILE *fp = NULL((void*)0);
95
96 fp = fopen(file, "ab+");
97 if (fp) {
98 if (fwrite(data, 1, len, fp) != len)
99 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
: "", file)
100 file)nvme_show_message(1, "Failed to write %s data to %s", msg ? msg
: "", file)
;
101 } else {
102 nvme_show_error("Failed to open %s file to write %s", file,nvme_show_message(1, "Failed to open %s file to write %s", file
, msg ? msg : "")
103 msg ? msg : "")nvme_show_message(1, "Failed to open %s file to write %s", file
, msg ? msg : "")
;
104 }
105}
106
107/* Various definitions used in RPMB related support */
108enum rpmb_request_type {
109 RPMB_REQ_AUTH_KEY_PROGRAM = 0x0001,
110 RPMB_REQ_READ_WRITE_CNTR = 0x0002,
111 RPMB_REQ_AUTH_DATA_WRITE = 0x0003,
112 RPMB_REQ_AUTH_DATA_READ = 0x0004,
113 RPMB_REQ_READ_RESULT = 0x0005,
114 RPMB_REQ_AUTH_DCB_WRITE = 0x0006,
115 RPMB_REQ_AUTH_DCB_READ = 0x0007,
116};
117
118/* RPMB data frame structure */
119#pragma pack(1)
120struct rpmb_data_frame_t {
121 __u8 pad[191];
122 __u8 mac[32];
123 __u8 target; /* 0-6, should match with NSSF with SS, SR */
124 __u8 nonce[16];
125 __le32 write_counter;
126 __le32 address;
127 __le32 sectors;
128 __le16 result;
129 __le16 type; /* req or response */
130 __u8 data[0]; /* in sector count times */
131};
132#pragma pack()
133
134struct rpmb_config_block_t {
135 unsigned char bp_enable;
136 unsigned char bp_lock;
137 unsigned char rsvd[510];
138};
139
140#define RPMB_DATA_FRAME_SIZE256 256
141#define RPMB_NVME_SECP0xEA 0xEA
142#define RPMB_NVME_SPSP0x0001 0x0001
143
144/* The RPMBS field of Identify Controller and its fields */
145struct ctrl_rpmbs_reg {
146 unsigned int rpmbs;
147 unsigned int num_targets;
148 unsigned int total_size; /* 128K units */
149 unsigned int access_size; /* in 512 byte count */
150};
151
152static int send_rpmb_req(struct libnvme_transport_handle *hdl, unsigned char tgt,
153 int size, struct rpmb_data_frame_t *req)
154{
155 struct libnvme_passthru_cmd cmd;
156
157 nvme_init_security_send(&cmd, NVME_NSID_NONE, tgt, RPMB_NVME_SPSP0x0001,
158 RPMB_NVME_SECP0xEA, 0, req, size);
159 return libnvme_exec_admin_passthru(hdl, &cmd);
160}
161
162static int recv_rpmb_rsp(struct libnvme_transport_handle *hdl, int tgt, int size,
163 struct rpmb_data_frame_t *rsp)
164{
165 struct libnvme_passthru_cmd cmd;
166
167 nvme_init_security_receive(&cmd, 0, tgt, RPMB_NVME_SPSP0x0001, RPMB_NVME_SECP0xEA, 0, rsp,
168 size);
169 return libnvme_exec_admin_passthru(hdl, &cmd);
170}
171
172/* Initialize nonce value in rpmb request frame. Returns 0 on success, -1 on failure. */
173static int rpmb_nonce_init(struct rpmb_data_frame_t *req)
174{
175 if (shr_getrandom(req->nonce, sizeof(req->nonce)) != 0) {
176 nvme_show_error("Failed to generate RPMB nonce")nvme_show_message(1, "Failed to generate RPMB nonce");
177 return -1;
178 }
179
180 return 0;
181}
182
183/* Read key from a given key buffer or key file */
184static unsigned char *read_rpmb_key(char *keystr, char *keyfile, unsigned int *keysize)
185{
186 unsigned char *keybuf = NULL((void*)0);
187 int err;
188
189 if (!keystr) {
190 if (keyfile) {
191 err = read_file(keyfile, &keybuf, keysize);
192 if (err < 0)
193 return NULL((void*)0);
194 }
195 } else {
196 size_t len = strlen(keystr);
197
198 keybuf = libnvme_alloc(len + 1);
199 if (keybuf) {
200 *keysize = len;
201 memcpy(keybuf, keystr, len);
202 }
203 }
204
205 return keybuf;
206}
207
208/* Initialize RPMB request frame with given values */
209static struct rpmb_data_frame_t *
210rpmb_request_init(unsigned int req_size, unsigned short type, unsigned char target,
211 unsigned char nonce, unsigned int addr, unsigned int sectors,
212 unsigned char *data, unsigned short data_offset, unsigned int data_size)
213{
214 struct rpmb_data_frame_t *req;
215
216 req = calloc(req_size, 1);
217 if (!req) {
218 nvme_show_error("Memory allocation failed for request 0x%04x", type)nvme_show_message(1, "Memory allocation failed for request 0x%04x"
, type)
;
219 return req;
220 }
221
222 req->type = cpu_to_le16(type);
223 req->target = target;
224 req->address = cpu_to_le32(addr);
225 req->sectors = cpu_to_le32(sectors);
226
227 if (nonce && rpmb_nonce_init(req) != 0) {
228 free(req);
229 return NULL((void*)0);
230 }
231 if (data)
232 memcpy((unsigned char *)req + data_offset, data, data_size);
233
234 return req;
235}
236
237/* Process rpmb response and print appropriate error message */
238static int check_rpmb_response(struct rpmb_data_frame_t *req, struct rpmb_data_frame_t *rsp,
239 char *msg)
240{
241 const char *rpmb_result_string[] = {
242 "Operation successful",
243 "General failure",
244 "Authentication (MAC) failure",
245 "Counter failure (not matching/incrementing failure)",
246 "Address failure (out of range or wrong alignment)",
247 "Write (data/counter/result) failure",
248 "Read (data/counter/result) failure",
249 "Authentication key not yet programmed",
250 "Invalid device configuration block",
251 "Unknown error",
252 };
253
254 __u16 result = le16_to_cpu(rsp->result);
255 __u16 rsp_type = le16_to_cpu(rsp->type);
256 __u16 req_type = le16_to_cpu(req->type);
257
258 /* check error status before comparing nonce and mac */
259 if (result != 0) {
260 if (rsp_type != ((req_type << 8) & 0xFF00)) {
261 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)
262 rsp_type, req_type)nvme_show_message(1, "%s ! non-matching response 0x%04x for 0x%04x"
, msg, rsp_type, req_type)
;
263 } else if ((result & 0x80) == 0x80) {
264 nvme_show_error("%s ! Expired write-counter !", msg)nvme_show_message(1, "%s ! Expired write-counter !", msg);
265 } else if (result) {
266 unsigned int code = result & 0x7F;
267
268 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")
269 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")
270 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")
;
271 } else if (memcmp(req->nonce, rsp->nonce, 16)) {
272 nvme_show_error("%s ! non-matching nonce", msg)nvme_show_message(1, "%s ! non-matching nonce", msg);
273 } else if (memcmp(req->mac, rsp->mac, 32)) {
274 nvme_show_error("%s ! non-matching MAC", msg)nvme_show_message(1, "%s ! non-matching MAC", msg);
275 } else if (le32_to_cpu(req->write_counter) + 1 !=
276 le32_to_cpu(rsp->write_counter)) {
277 nvme_show_error("%s ! out-of-sync write-counters", msg)nvme_show_message(1, "%s ! out-of-sync write-counters", msg);
278 }
279 }
280
281 return (int)result;
282}
283
284/*
285 * send an initialized rpmb request to the controller and read its response;
286 * expected response size given in 'rsp_size'. returns response buffer upon
287 * successful completion (caller must free), NULL otherwise
288 */
289static struct rpmb_data_frame_t *
290rpmb_read_request(struct libnvme_transport_handle *hdl, struct rpmb_data_frame_t *req,
291 int req_size, int rsp_size)
292{
293 struct rpmb_data_frame_t *rsp = NULL((void*)0);
294 unsigned char msg[1024] = { 0 };
295 int error;
296
297 snprintf((char *)msg, sizeof(msg), "RPMB request 0x%04x to target 0x%x",
298 le16_to_cpu(req->type), req->target);
299
300 error = send_rpmb_req(hdl, req->target, req_size, req);
301 if (error != 0) {
302 nvme_show_error("%s failed with error = 0x%x", msg, error)nvme_show_message(1, "%s failed with error = 0x%x", msg, error
)
;
303 goto error_out;
304 }
305
306 /* read the result back */
307 rsp = calloc(rsp_size, 1);
308 if (!rsp) {
309 nvme_show_error("memory alloc failed for %s", msg)nvme_show_message(1, "memory alloc failed for %s", msg);
310 goto error_out;
311 }
312
313 /* Read result of previous request */
314 error = recv_rpmb_rsp(hdl, req->target, rsp_size, rsp);
315 if (error) {
316 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)
;
317 goto error_out;
318 }
319
320 /* validate response buffer - match target, nonce, and mac */
321 error = check_rpmb_response(req, rsp, (char *)msg);
322 if (error == 0)
323 return rsp;
324
325error_out:
326 free(rsp);
327 return NULL((void*)0);
328}
329
330/* read current write counter value from controller */
331static int rpmb_read_write_counter(struct libnvme_transport_handle *hdl, unsigned char target,
332 unsigned int *counter)
333{
334 int error = -1;
335 int req_size = sizeof(struct rpmb_data_frame_t);
336 struct rpmb_data_frame_t *req = NULL((void*)0);
337 struct rpmb_data_frame_t *rsp = NULL((void*)0);
338
339 req = rpmb_request_init(req_size, RPMB_REQ_READ_WRITE_CNTR, target, 1, 0, 0, NULL((void*)0), 0,
340 0);
341 if (!req)
342 goto out;
343 rsp = rpmb_read_request(hdl, req, req_size, req_size);
344 if (!rsp)
345 goto out;
346 *counter = le32_to_cpu(rsp->write_counter);
347 error = 0;
348
349out:
350 free(req);
351 free(rsp);
352 return error;
353}
354
355/*
356 * Read current device configuration block into specified buffer. It also
357 * returns current write counter value returned as part of response, in case
358 * of error it returns 0
359 */
360static unsigned int rpmb_read_config_block(struct libnvme_transport_handle *hdl,
361 unsigned char **config_buf)
362{
363 int req_size = sizeof(struct rpmb_data_frame_t);
364 int cfg_size = sizeof(struct rpmb_config_block_t);
365 int rsp_size = req_size + cfg_size;
366
367 struct rpmb_data_frame_t *req = NULL((void*)0);
368 struct rpmb_data_frame_t *rsp = NULL((void*)0);
369 struct rpmb_config_block_t *cfg = NULL((void*)0);
370 unsigned int retval = 0;
371
372 /* initialize request with nonce, no data on input */
373 req = rpmb_request_init(req_size, RPMB_REQ_AUTH_DCB_READ, 0, 1, 0, 1, 0, 0, 0);
374 if (!req
4.1
'req' is non-null
)
5
Taking false branch
375 return 0;
376 rsp = rpmb_read_request(hdl, req, req_size, rsp_size);
377 if (!rsp
5.1
'rsp' is non-null
) {
6
Taking false branch
378 free(req);
379 return 0;
380 }
381
382 /* copy configuration data to be sent back to caller */
383 cfg = calloc(cfg_size, 1);
7
Memory is allocated
384 if (!cfg) {
8
Assuming 'cfg' is non-null
9
Taking false branch
385 nvme_show_error("failed to allocate RPMB config buffer")nvme_show_message(1, "failed to allocate RPMB config buffer");
386 goto out;
387 }
388
389 memcpy(cfg, rsp->data, cfg_size);
390 *config_buf = (unsigned char *)cfg;
391 cfg = NULL((void*)0);
392 retval = le32_to_cpu(rsp->write_counter);
393out:
394 free(req);
395 free(rsp);
396 return retval;
397}
398
399static int rpmb_auth_data_read(struct libnvme_transport_handle *hdl, unsigned char target,
400 unsigned int offset, unsigned char **msg_buf, int msg_size,
401 int acc_size)
402{
403 struct rpmb_data_frame_t *req = NULL((void*)0);
404 struct rpmb_data_frame_t *rsp = NULL((void*)0);
405 int req_size = sizeof(struct rpmb_data_frame_t);
406 int chunk_size = (acc_size < msg_size) ? acc_size : msg_size;
407 unsigned char *bufp = malloc(msg_size * 512);
408 int done = 0, xfer, rsp_size;
409 __u32 sectors;
410
411 if (!bufp) {
412 nvme_show_error("Failed to allocated memory for read-data req")nvme_show_message(1, "Failed to allocated memory for read-data req"
)
;
413 return -1;
414 }
415
416 /* @offset is the first sector to read, @done the sectors read */
417 while (done < msg_size) {
418 xfer = msg_size - done < chunk_size ?
419 msg_size - done : chunk_size;
420 rsp_size = req_size + xfer * 512;
421 req = rpmb_request_init(req_size, RPMB_REQ_AUTH_DATA_READ,
422 target, 1, offset + done, xfer,
423 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 sectors = le32_to_cpu(rsp->sectors);
435 if (!sectors || sectors > (unsigned int)xfer) {
436 nvme_show_error("device returned %u of %d sectors",nvme_show_message(1, "device returned %u of %d sectors", sectors
, xfer)
437 sectors, xfer)nvme_show_message(1, "device returned %u of %d sectors", sectors
, xfer)
;
438 goto err_free_rsp;
439 }
440
441 memcpy(bufp + done * 512, rsp->data, sectors * 512);
442 done += sectors;
443 free(req);
444 free(rsp);
445 }
446
447 *msg_buf = bufp;
448 return done;
449
450err_free_rsp:
451 free(rsp);
452err_free_req:
453 free(req);
454err_free_bufp:
455 free(bufp);
456 return -1;
457}
458
459/* Implementation of programming authentication key to given RPMB target */
460static int rpmb_program_auth_key(struct libnvme_transport_handle *hdl, unsigned char target,
461 unsigned char *key_buf, int key_size)
462{
463 int req_size = sizeof(struct rpmb_data_frame_t);
464 int rsp_size = sizeof(struct rpmb_data_frame_t);
465
466 struct rpmb_data_frame_t *req = NULL((void*)0);
467 struct rpmb_data_frame_t *rsp = NULL((void*)0);
468
469 int err = -ENOMEM12;
470
471 req = rpmb_request_init(req_size, RPMB_REQ_AUTH_KEY_PROGRAM, target, 0, 0, 0, key_buf,
472 (223 - key_size), key_size);
473 if (!req) {
474 nvme_show_error("failed to allocate request buffer memory")nvme_show_message(1, "failed to allocate request buffer memory"
)
;
475 goto out;
476 }
477
478 /* send the request and get response */
479 err = send_rpmb_req(hdl, req->target, req_size, req);
480 if (err) {
481 nvme_show_error("RPMB request 0x%04x for 0x%x, err: %d",nvme_show_message(1, "RPMB request 0x%04x for 0x%x, err: %d",
le16_to_cpu(req->type), req->target, err)
482 le16_to_cpu(req->type), req->target,nvme_show_message(1, "RPMB request 0x%04x for 0x%x, err: %d",
le16_to_cpu(req->type), req->target, err)
483 err)nvme_show_message(1, "RPMB request 0x%04x for 0x%x, err: %d",
le16_to_cpu(req->type), req->target, err)
;
484 goto out;
485 }
486
487 /* send the request to get the result and then request to get the response */
488 rsp = calloc(rsp_size, 1);
489 if (!rsp) {
490 nvme_show_error("failed to allocate response buffer memory")nvme_show_message(1, "failed to allocate response buffer memory"
)
;
491 err = -ENOMEM12;
492 goto out;
493 }
494
495 rsp->target = req->target;
496 rsp->type = cpu_to_le16(RPMB_REQ_READ_RESULT);
497 err = send_rpmb_req(hdl, req->target, rsp_size, rsp);
498 if (err || rsp->result) {
499 nvme_show_error(nvme_show_message(1, "Program auth key read result 0x%x, error = 0x%x"
, le16_to_cpu(rsp->result), err)
500 "Program auth key read result 0x%x, error = 0x%x",nvme_show_message(1, "Program auth key read result 0x%x, error = 0x%x"
, le16_to_cpu(rsp->result), err)
501 le16_to_cpu(rsp->result), err)nvme_show_message(1, "Program auth key read result 0x%x, error = 0x%x"
, le16_to_cpu(rsp->result), err)
;
502 goto out;
503 }
504
505 /* reuse response buffer */
506 memset(rsp, 0, rsp_size);
507 err = recv_rpmb_rsp(hdl, req->target, rsp_size, rsp);
508 if (err != 0)
509 nvme_show_error("Program Key recv error = 0x%x", err)nvme_show_message(1, "Program Key recv error = 0x%x", err);
510 else
511 err = check_rpmb_response(req, rsp, "Failed to Program Key");
512out:
513 free(req);
514 free(rsp);
515
516 return err;
517}
518
519/*
520 * Implementation of RPMB authenticated data write command; this function
521 * transfers msg_size bytes from msg_buf to controller 'addr'. Returns
522 * number of bytes actually written to, otherwise negative error code on
523 * failures.
524 */
525static int auth_data_write_chunk(struct libnvme_transport_handle *hdl, unsigned char tgt,
526 unsigned int addr, unsigned char *msg_buf, int msg_size,
527 unsigned char *keybuf, int keysize)
528{
529 int req_size = sizeof(struct rpmb_data_frame_t) + msg_size;
530 int rsp_size = sizeof(struct rpmb_data_frame_t);
531
532 struct rpmb_data_frame_t *req = NULL((void*)0);
533 struct rpmb_data_frame_t *rsp = NULL((void*)0);
534
535 unsigned int write_cntr = 0;
536 unsigned char *mac = NULL((void*)0);
537 int error = -ENOMEM12;
538
539 /* get current write counter and copy to the request */
540 error = rpmb_read_write_counter(hdl, tgt, &write_cntr);
541 if (error != 0) {
542 nvme_show_error("Failed to read write counter for write-data")nvme_show_message(1, "Failed to read write counter for write-data"
)
;
543 goto out;
544 }
545
546 req = rpmb_request_init(req_size, RPMB_REQ_AUTH_DATA_WRITE, tgt, 0, addr,
547 (msg_size / 512), msg_buf,
548 offsetof(struct rpmb_data_frame_t, data)__builtin_offsetof(struct rpmb_data_frame_t, data), msg_size);
549 if (!req) {
550 nvme_show_error("Memory alloc failed for write-data command")nvme_show_message(1, "Memory alloc failed for write-data command"
)
;
551 goto out;
552 }
553
554 req->write_counter = cpu_to_le32(write_cntr);
555
556 /* compute HMAC hash */
557 mac = shr_hmac_sha256(((unsigned char *)req + 223), req_size - 223, keybuf, keysize);
558 if (!mac) {
559 nvme_show_error("failed to compute HMAC-SHA256")nvme_show_message(1, "failed to compute HMAC-SHA256");
560 error = -1;
561 goto out;
562 }
563
564 memcpy(req->mac, mac, 32);
565
566 /* send the request and get response */
567 error = send_rpmb_req(hdl, tgt, req_size, req);
568 if (error != 0) {
569 nvme_show_error("RPMB request 0x%04x for 0x%x, error: %d",nvme_show_message(1, "RPMB request 0x%04x for 0x%x, error: %d"
, le16_to_cpu(req->type), tgt, error)
570 le16_to_cpu(req->type), tgt,nvme_show_message(1, "RPMB request 0x%04x for 0x%x, error: %d"
, le16_to_cpu(req->type), tgt, error)
571 error)nvme_show_message(1, "RPMB request 0x%04x for 0x%x, error: %d"
, le16_to_cpu(req->type), tgt, error)
;
572 goto out;
573 }
574
575 /* send the request to get the result and then request to get the response */
576 rsp = calloc(rsp_size, 1);
577 if (!rsp) {
578 nvme_show_error("failed to allocate response buffer memory")nvme_show_message(1, "failed to allocate response buffer memory"
)
;
579 error = -ENOMEM12;
580 goto out;
581 }
582 rsp->target = req->target;
583 rsp->type = cpu_to_le16(RPMB_REQ_READ_RESULT);
584 error = send_rpmb_req(hdl, tgt, rsp_size, rsp);
585 if (error != 0 || rsp->result != 0) {
586 nvme_show_error("Write-data read result 0x%x, error = 0x%x",nvme_show_message(1, "Write-data read result 0x%x, error = 0x%x"
, le16_to_cpu(rsp->result), error)
587 le16_to_cpu(rsp->result),nvme_show_message(1, "Write-data read result 0x%x, error = 0x%x"
, le16_to_cpu(rsp->result), error)
588 error)nvme_show_message(1, "Write-data read result 0x%x, error = 0x%x"
, le16_to_cpu(rsp->result), error)
;
589 goto out;
590 }
591
592 /* Read final response */
593 memset(rsp, 0, rsp_size);
594 error = recv_rpmb_rsp(hdl, tgt, rsp_size, rsp);
595 if (error != 0)
596 nvme_show_error("Auth data write recv error = 0x%x", error)nvme_show_message(1, "Auth data write recv error = 0x%x", error
)
;
597 else
598 error = check_rpmb_response(req, rsp, "Failed to write-data");
599out:
600 free(req);
601 free(rsp);
602 free(mac);
603
604 return error;
605}
606
607/* send the request and get response */
608static int rpmb_auth_data_write(struct libnvme_transport_handle *hdl, unsigned char target,
609 unsigned int addr, int acc_size, unsigned char *msg_buf,
610 int msg_size, unsigned char *keybuf, int keysize)
611{
612 int chunk_size = acc_size < msg_size ? acc_size : msg_size;
613 int xfer = chunk_size;
614 int offset = 0;
615
616 while (xfer > 0) {
617 if (auth_data_write_chunk(hdl, target, (addr + offset / 512), msg_buf + offset,
618 xfer, keybuf, keysize) != 0) {
619 /* error writing chunk data */
620 break;
621 }
622
623 offset += xfer;
624 if (offset + chunk_size > msg_size)
625 xfer = msg_size - offset;
626 else
627 xfer = chunk_size;
628 }
629
630 return offset;
631}
632
633/* writes given config_block buffer to the drive target 0 */
634static int rpmb_write_config_block(struct libnvme_transport_handle *hdl,
635 unsigned char *cfg_buf, unsigned char *keybuf, int keysize)
636{
637 int cfg_size = sizeof(struct rpmb_config_block_t);
638 int rsp_size = sizeof(struct rpmb_data_frame_t);
639 int req_size = rsp_size + cfg_size;
640
641 struct rpmb_data_frame_t *req = NULL((void*)0);
642 struct rpmb_data_frame_t *rsp = NULL((void*)0);
643 unsigned char *cfg_buf_read = NULL((void*)0), *mac = NULL((void*)0);
644 unsigned int write_cntr = 0;
645 int error = -ENOMEM12;
646
647 /* initialize request */
648 req = rpmb_request_init(req_size, RPMB_REQ_AUTH_DCB_WRITE, 0, 0, 0, 1, cfg_buf,
649 offsetof(struct rpmb_data_frame_t, data)__builtin_offsetof(struct rpmb_data_frame_t, data), cfg_size);
650 if (!req) {
651 nvme_show_error("failed to allocate rpmb request buffer")nvme_show_message(1, "failed to allocate rpmb request buffer"
)
;
652 goto out;
653 }
654
655 /* read config block write_counter from controller */
656 write_cntr = rpmb_read_config_block(hdl, &cfg_buf_read);
657 if (!cfg_buf_read) {
658 nvme_show_error("failed to read config block write counter")nvme_show_message(1, "failed to read config block write counter"
)
;
659 error = -EIO5;
660 goto out;
661 }
662
663 free(cfg_buf_read);
664 req->write_counter = cpu_to_le32(write_cntr);
665 mac = shr_hmac_sha256(((unsigned char *)req + 223), req_size - 223, keybuf, keysize);
666 if (!mac) {
667 nvme_show_error("failed to compute hmac-sha256 hash")nvme_show_message(1, "failed to compute hmac-sha256 hash");
668 error = -EINVAL22;
669 goto out;
670 }
671
672 memcpy(req->mac, mac, sizeof(req->mac));
673
674 error = send_rpmb_req(hdl, 0, req_size, req);
675 if (error != 0) {
676 nvme_show_error("Write-config RPMB request, error = 0x%x", error)nvme_show_message(1, "Write-config RPMB request, error = 0x%x"
, error)
;
677 goto out;
678 }
679
680 /* get response */
681 rsp = calloc(rsp_size, 1);
682 if (!rsp) {
683 nvme_show_error("failed to allocate response buffer memory")nvme_show_message(1, "failed to allocate response buffer memory"
)
;
684 error = -ENOMEM12;
685 goto out;
686 }
687
688 /* get result first */
689 memset(rsp, 0, rsp_size);
690 rsp->target = req->target;
691 rsp->type = cpu_to_le16(RPMB_REQ_READ_RESULT);
692 /* get the response and validate */
693 error = recv_rpmb_rsp(hdl, req->target, rsp_size, rsp);
694 if (error != 0) {
695 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)
;
696 goto out;
697 }
698 error = check_rpmb_response(req, rsp, "Failed to retrieve write-config response");
699out:
700 free(req);
701 free(rsp);
702 free(mac);
703
704 return error;
705}
706
707static bool_Bool invalid_xfer_size(int blocks, unsigned int bpsz)
708{
709 return (blocks <= 0) || (blocks * 512) > ((bpsz + 1) * 128 * 1024);
710}
711
712/* Identify the controller and fetch its RPMBS support register */
713static int rpmb_get_regs(struct libnvme_transport_handle *hdl,
714 struct 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 regs->num_targets = regs->rpmbs & NVME_CTRL_RPMBS_NR_UNITS;
727 regs->total_size = (regs->rpmbs & NVME_CTRL_RPMBS_TOTAL_SIZE) >> 16;
728 regs->access_size = (regs->rpmbs & NVME_CTRL_RPMBS_ACCESS_SIZE) >> 24;
729 if (regs->num_targets == 0) {
730 nvme_show_error("No RPMB targets are supported by the drive")nvme_show_message(1, "No RPMB targets are supported by the drive"
)
;
731 return -1;
732 }
733
734 return 0;
735}
736
737/* Read key from a given key buffer or key file and validate its size */
738static unsigned char *rpmb_read_and_validate_key(char *keystr, char *keyfile,
739 unsigned int *keysize)
740{
741 unsigned char *keybuf = read_rpmb_key(keystr, keyfile, keysize);
742
743 if (!keybuf) {
744 nvme_show_error("Failed to read key")nvme_show_message(1, "Failed to read key");
745 return NULL((void*)0);
746 }
747
748 if (*keysize > 223 || *keysize == 0) {
749 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)
;
750 libnvme_free(keybuf);
751 return NULL((void*)0);
752 }
753
754 return keybuf;
755}
756
757/* Read msg data from either a literal string or a file */
758static int rpmb_read_msg(char *msgstr, char *msgfile, unsigned char **msg_buf,
759 unsigned int *msg_size)
760{
761 if (msgstr) {
762 size_t len = strlen(msgstr);
763
764 *msg_buf = libnvme_alloc(len + 1);
765 if (!*msg_buf)
766 return -ENOMEM12;
767 *msg_size = len;
768 memcpy(*msg_buf, msgstr, len);
769 return 0;
770 }
771
772 return read_file(msgfile, msg_buf, msg_size);
773}
774
775static int rpmb_info(int argc, char **argv, struct command *acmd, struct plugin *plugin)
776{
777 const char *desc = "Print RPMB support information for the controller";
778
779 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
780 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
781 struct ctrl_rpmbs_reg regs;
782 int err;
783
784 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
785 OPT_END(){ ((void*)0) }
786 };
787
788 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
789 if (err)
790 return err;
791
792 err = rpmb_get_regs(hdl, &regs);
793 if (err)
794 return err;
795
796 nvme_show_id_ctrl_rpmbs(regs.rpmbs, 0);
797
798 return 0;
799}
800
801static int rpmb_program_key(int argc, char **argv, struct command *acmd, struct plugin *plugin)
802{
803 const char *desc = "Program the RPMB authentication key for a given target";
804 const char *key = "key to be used for authentication";
805 const char *kfile = "key file that has authentication key to be used";
806 const char *target = "RPMB target - numerical value of 0 to 6, default 0";
807
808 struct config {
809 char *key;
810 char *keyfile;
811 __u8 target;
812 };
813
814 struct config cfg = {
815 .key = NULL((void*)0),
816 .keyfile = NULL((void*)0),
817 .target = 0,
818 };
819
820 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
821 OPT_STRING("key", 'k', "key", &cfg.key, key){"key", 'k', "key", CFG_STRING, _Generic(&cfg.key, char *
* : (&cfg.key), const char ** : (&cfg.key)), ARGCONFIG_ARG_REQUIRED
, key, 0, }
,
822 OPT_FILE("keyfile", 'g', &cfg.keyfile, kfile){"keyfile", 'g', "FILE", CFG_FILE, _Generic(&cfg.keyfile,
char ** : (&cfg.keyfile), const char ** : (&cfg.keyfile
)), ARGCONFIG_ARG_REQUIRED, kfile, 0, }
,
823 OPT_BYTE("target", 't', &cfg.target, target){"target", 't', "NUM", CFG_BYTE, _Generic(&cfg.target, uint8_t
* : (&cfg.target)), ARGCONFIG_ARG_REQUIRED, target, 0, }
,
824 OPT_END(){ ((void*)0) }
825 };
826
827 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
828 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
829 __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) unsigned char *key_buf = NULL((void*)0);
830 struct ctrl_rpmbs_reg regs;
831 unsigned int key_size = 0;
832 int err;
833
834 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
835 if (err)
836 return err;
837
838 err = rpmb_get_regs(hdl, &regs);
839 if (err)
840 return err;
841
842 key_buf = rpmb_read_and_validate_key(cfg.key, cfg.keyfile, &key_size);
843 if (!key_buf)
844 return -1;
845
846 err = rpmb_program_auth_key(hdl, cfg.target, key_buf, key_size);
847 if (!err)
848 nvme_show_verbose_result("RPMB authentication key programmed")nvme_show_verbose_message("RPMB authentication key programmed"
)
;
849
850 return err;
851}
852
853static int rpmb_read_counter(int argc, char **argv, struct command *acmd,
854 struct plugin *plugin)
855{
856 const char *desc = "Read the current RPMB write counter for a given target";
857 const char *target = "RPMB target - numerical value of 0 to 6, default 0";
858
859 struct config {
860 __u8 target;
861 };
862
863 struct config cfg = {
864 .target = 0,
865 };
866
867 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
868 OPT_BYTE("target", 't', &cfg.target, target){"target", 't', "NUM", CFG_BYTE, _Generic(&cfg.target, uint8_t
* : (&cfg.target)), ARGCONFIG_ARG_REQUIRED, target, 0, }
,
869 OPT_END(){ ((void*)0) }
870 };
871
872 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
873 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
874 struct ctrl_rpmbs_reg regs;
875 unsigned int write_cntr = 0;
876 int err;
877
878 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
879 if (err)
880 return err;
881
882 err = rpmb_get_regs(hdl, &regs);
883 if (err)
884 return err;
885
886 err = rpmb_read_write_counter(hdl, cfg.target, &write_cntr);
887 if (!err)
888 nvme_show_result("Write Counter is: %u", write_cntr)nvme_show_message(0, "Write Counter is: %u", write_cntr);
889
890 return err;
891}
892
893static int rpmb_read_data(int argc, char **argv, struct command *acmd, struct plugin *plugin)
894{
895 const char *desc = "Read authenticated data from an RPMB target";
896 const char *mfile = "data file to save read data to";
897 const char *target = "RPMB target - numerical value of 0 to 6, default 0";
898 const char *address = "Sector offset to read from for an RPMB target, default 0";
899 const char *blocks = "Number of 512 byte blocks to read";
900
901 struct config {
902 char *msgfile;
903 __u32 address;
904 __u32 blocks;
905 __u8 target;
906 };
907
908 struct config cfg = {
909 .msgfile = NULL((void*)0),
910 .address = 0,
911 .blocks = 0,
912 .target = 0,
913 };
914
915 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
916 OPT_FILE("msgfile", 'f', &cfg.msgfile, mfile){"msgfile", 'f', "FILE", CFG_FILE, _Generic(&cfg.msgfile,
char ** : (&cfg.msgfile), const char ** : (&cfg.msgfile
)), ARGCONFIG_ARG_REQUIRED, mfile, 0, }
,
917 OPT_UINT("address", 0, &cfg.address, address){"address", 0, "NUM", CFG_POSITIVE, _Generic(&cfg.address
, uint32_t * : (&cfg.address)), ARGCONFIG_ARG_REQUIRED, address
, 0, }
,
918 OPT_UINT("blocks", 'b', &cfg.blocks, blocks){"blocks", 'b', "NUM", CFG_POSITIVE, _Generic(&cfg.blocks
, uint32_t * : (&cfg.blocks)), ARGCONFIG_ARG_REQUIRED, blocks
, 0, }
,
919 OPT_BYTE("target", 't', &cfg.target, target){"target", 't', "NUM", CFG_BYTE, _Generic(&cfg.target, uint8_t
* : (&cfg.target)), ARGCONFIG_ARG_REQUIRED, target, 0, }
,
920 OPT_END(){ ((void*)0) }
921 };
922
923 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
924 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
925 __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) unsigned char *msg_buf = NULL((void*)0);
926 struct ctrl_rpmbs_reg regs;
927 int err;
928
929 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
930 if (err)
931 return err;
932
933 err = rpmb_get_regs(hdl, &regs);
934 if (err)
935 return err;
936
937 if (invalid_xfer_size(cfg.blocks, regs.total_size)) {
938 nvme_show_error("invalid transfer size %u", cfg.blocks * 512)nvme_show_message(1, "invalid transfer size %u", cfg.blocks *
512)
;
939 return -1;
940 }
941
942 err = rpmb_auth_data_read(hdl, cfg.target, cfg.address, &msg_buf, cfg.blocks,
943 (regs.access_size + 1));
944 if (err > 0 && msg_buf) {
945 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)
;
946 write_file(msg_buf, err * 512, cfg.msgfile, NULL((void*)0));
947 }
948
949 return err > 0 ? 0 : err;
950}
951
952static int rpmb_write_data(int argc, char **argv, struct command *acmd, struct plugin *plugin)
953{
954 const char *desc = "Write authenticated data to an RPMB target";
955 const char *msg = "data to be written";
956 const char *mfile = "data file to be written";
957 const char *kfile = "key file that has authentication key to be used";
958 const char *target = "RPMB target - numerical value of 0 to 6, default 0";
959 const char *address = "Sector offset to write to for an RPMB target, default 0";
960 const char *blocks = "Number of 512 byte blocks to write";
961 const char *key = "key to be used for authentication";
962
963 struct config {
964 char *key;
965 char *msg;
966 char *keyfile;
967 char *msgfile;
968 __u32 address;
969 __u32 blocks;
970 __u8 target;
971 };
972
973 struct config cfg = {
974 .key = NULL((void*)0),
975 .msg = NULL((void*)0),
976 .msgfile = NULL((void*)0),
977 .keyfile = NULL((void*)0),
978 .address = 0,
979 .blocks = 0,
980 .target = 0,
981 };
982
983 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
984 OPT_FILE("msgfile", 'f', &cfg.msgfile, mfile){"msgfile", 'f', "FILE", CFG_FILE, _Generic(&cfg.msgfile,
char ** : (&cfg.msgfile), const char ** : (&cfg.msgfile
)), ARGCONFIG_ARG_REQUIRED, mfile, 0, }
,
985 OPT_FILE("keyfile", 'g', &cfg.keyfile, kfile){"keyfile", 'g', "FILE", CFG_FILE, _Generic(&cfg.keyfile,
char ** : (&cfg.keyfile), const char ** : (&cfg.keyfile
)), ARGCONFIG_ARG_REQUIRED, kfile, 0, }
,
986 OPT_STRING("key", 'k', "key", &cfg.key, key){"key", 'k', "key", CFG_STRING, _Generic(&cfg.key, char *
* : (&cfg.key), const char ** : (&cfg.key)), ARGCONFIG_ARG_REQUIRED
, key, 0, }
,
987 OPT_STRING("msg", 'd', "data", &cfg.msg, msg){"msg", 'd', "data", CFG_STRING, _Generic(&cfg.msg, char *
* : (&cfg.msg), const char ** : (&cfg.msg)), ARGCONFIG_ARG_REQUIRED
, msg, 0, }
,
988 OPT_UINT("address", 0, &cfg.address, address){"address", 0, "NUM", CFG_POSITIVE, _Generic(&cfg.address
, uint32_t * : (&cfg.address)), ARGCONFIG_ARG_REQUIRED, address
, 0, }
,
989 OPT_UINT("blocks", 'b', &cfg.blocks, blocks){"blocks", 'b', "NUM", CFG_POSITIVE, _Generic(&cfg.blocks
, uint32_t * : (&cfg.blocks)), ARGCONFIG_ARG_REQUIRED, blocks
, 0, }
,
990 OPT_BYTE("target", 't', &cfg.target, target){"target", 't', "NUM", CFG_BYTE, _Generic(&cfg.target, uint8_t
* : (&cfg.target)), ARGCONFIG_ARG_REQUIRED, target, 0, }
,
991 OPT_END(){ ((void*)0) }
992 };
993
994 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
995 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
996 __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) unsigned char *key_buf = NULL((void*)0);
997 __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) unsigned char *msg_buf = NULL((void*)0);
998 struct ctrl_rpmbs_reg regs;
999 unsigned int key_size = 0;
1000 unsigned int msg_size = 0;
1001 int err;
1002
1003 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
1004 if (err)
1005 return err;
1006
1007 err = rpmb_get_regs(hdl, &regs);
1008 if (err)
1009 return err;
1010
1011 key_buf = rpmb_read_and_validate_key(cfg.key, cfg.keyfile, &key_size);
1012 if (!key_buf)
1013 return -1;
1014
1015 err = rpmb_read_msg(cfg.msg, cfg.msgfile, &msg_buf, &msg_size);
1016 if (err || !msg_size) {
1017 nvme_show_error("Failed to read msg data")nvme_show_message(1, "Failed to read msg data");
1018 return -1;
1019 }
1020
1021 if (invalid_xfer_size(cfg.blocks, regs.total_size) || (cfg.blocks * 512) > msg_size) {
1022 nvme_show_error("invalid transfer size %u", cfg.blocks * 512)nvme_show_message(1, "invalid transfer size %u", cfg.blocks *
512)
;
1023 return -1;
1024 } else if ((cfg.blocks * 512) < msg_size) {
1025 msg_size = cfg.blocks * 512;
1026 }
1027
1028 err = rpmb_auth_data_write(hdl, cfg.target, cfg.address, ((regs.access_size + 1) * 512),
1029 msg_buf, msg_size, key_buf, key_size);
1030
1031 /* print whatever extent of data written to target */
1032 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)
1033 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)
;
1034
1035 return err == (int)msg_size ? 0 : -1;
1036}
1037
1038static int rpmb_read_config(int argc, char **argv, struct command *acmd,
1039 struct plugin *plugin)
1040{
1041 const char *desc = "Read the RPMB device configuration block";
1042 const char *mfile = "data file to save the read configuration block to";
1043
1044 struct config {
1045 char *msgfile;
1046 };
1047
1048 struct config cfg = {
1049 .msgfile = NULL((void*)0),
1050 };
1051
1052 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
1053 OPT_FILE("msgfile", 'f', &cfg.msgfile, mfile){"msgfile", 'f', "FILE", CFG_FILE, _Generic(&cfg.msgfile,
char ** : (&cfg.msgfile), const char ** : (&cfg.msgfile
)), ARGCONFIG_ARG_REQUIRED, mfile, 0, }
,
1054 OPT_END(){ ((void*)0) }
1055 };
1056
1057 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
1058 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
1059 __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) unsigned char *msg_buf = NULL((void*)0);
1060 struct ctrl_rpmbs_reg regs;
1061 unsigned int write_cntr;
1062 int err;
1063
1064 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
1065 if (err)
1
Assuming 'err' is 0
2
Taking false branch
1066 return err;
1067
1068 err = rpmb_get_regs(hdl, &regs);
1069 if (err
2.1
'err' is 0
)
3
Taking false branch
1070 return err;
1071
1072 write_cntr = rpmb_read_config_block(hdl, &msg_buf);
4
Calling 'rpmb_read_config_block'
10
Returned allocated memory via 2nd parameter
1073 if (!msg_buf
10.1
'msg_buf' is non-null
) {
11
Taking false branch
1074 nvme_show_error("failed to read config block")nvme_show_message(1, "failed to read config block");
1075 return -1;
1076 }
1077
1078 if (!cfg.msgfile) {
12
Assuming field 'msgfile' is null
13
Taking true branch
1079 struct rpmb_config_block_t *rcfg = (struct rpmb_config_block_t *)msg_buf;
1080
1081 nvme_show_result("Boot Partition Protection is %s",nvme_show_message(0, "Boot Partition Protection is %s", (rcfg
->bp_enable & 0x1) ? "Enabled" : "Disabled")
14
Assuming the condition is false
15
'?' condition is false
1082 (rcfg->bp_enable & 0x1) ? "Enabled" : "Disabled")nvme_show_message(0, "Boot Partition Protection is %s", (rcfg
->bp_enable & 0x1) ? "Enabled" : "Disabled")
;
1083 nvme_show_result("Boot Partition 1 is %s",nvme_show_message(0, "Boot Partition 1 is %s", (rcfg->bp_lock
& 0x2) ? "Locked" : "Unlocked")
16
Assuming the condition is false
17
'?' condition is false
1084 (rcfg->bp_lock & 0x2) ? "Locked" : "Unlocked")nvme_show_message(0, "Boot Partition 1 is %s", (rcfg->bp_lock
& 0x2) ? "Locked" : "Unlocked")
;
1085 nvme_show_result("Boot Partition 0 is %s",nvme_show_message(0, "Boot Partition 0 is %s", (rcfg->bp_lock
& 0x1) ? "Locked" : "Unlocked")
18
Assuming the condition is false
19
'?' condition is false
20
Potential leak of memory pointed to by 'rcfg'
1086 (rcfg->bp_lock & 0x1) ? "Locked" : "Unlocked")nvme_show_message(0, "Boot Partition 0 is %s", (rcfg->bp_lock
& 0x1) ? "Locked" : "Unlocked")
;
1087 } else {
1088 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)
;
1089 write_file(msg_buf, sizeof(struct rpmb_config_block_t),
1090 cfg.msgfile, NULL((void*)0));
1091 }
1092
1093 return write_cntr == 0 ? -1 : 0;
1094}
1095
1096static int rpmb_write_config(int argc, char **argv, struct command *acmd,
1097 struct plugin *plugin)
1098{
1099 const char *desc = "Write the RPMB device configuration block";
1100 const char *msg = "configuration block data to be written";
1101 const char *mfile = "data file with the configuration block to be written";
1102 const char *kfile = "key file that has authentication key to be used";
1103 const char *key = "key to be used for authentication";
1104
1105 struct config {
1106 char *key;
1107 char *msg;
1108 char *keyfile;
1109 char *msgfile;
1110 };
1111
1112 struct config cfg = {
1113 .key = NULL((void*)0),
1114 .msg = NULL((void*)0),
1115 .msgfile = NULL((void*)0),
1116 .keyfile = NULL((void*)0),
1117 };
1118
1119 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
1120 OPT_FILE("msgfile", 'f', &cfg.msgfile, mfile){"msgfile", 'f', "FILE", CFG_FILE, _Generic(&cfg.msgfile,
char ** : (&cfg.msgfile), const char ** : (&cfg.msgfile
)), ARGCONFIG_ARG_REQUIRED, mfile, 0, }
,
1121 OPT_FILE("keyfile", 'g', &cfg.keyfile, kfile){"keyfile", 'g', "FILE", CFG_FILE, _Generic(&cfg.keyfile,
char ** : (&cfg.keyfile), const char ** : (&cfg.keyfile
)), ARGCONFIG_ARG_REQUIRED, kfile, 0, }
,
1122 OPT_STRING("key", 'k', "key", &cfg.key, key){"key", 'k', "key", CFG_STRING, _Generic(&cfg.key, char *
* : (&cfg.key), const char ** : (&cfg.key)), ARGCONFIG_ARG_REQUIRED
, key, 0, }
,
1123 OPT_STRING("msg", 'd', "data", &cfg.msg, msg){"msg", 'd', "data", CFG_STRING, _Generic(&cfg.msg, char *
* : (&cfg.msg), const char ** : (&cfg.msg)), ARGCONFIG_ARG_REQUIRED
, msg, 0, }
,
1124 OPT_END(){ ((void*)0) }
1125 };
1126
1127 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
1128 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
1129 __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) unsigned char *key_buf = NULL((void*)0);
1130 __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) unsigned char *msg_buf = NULL((void*)0);
1131 struct ctrl_rpmbs_reg regs;
1132 unsigned int key_size = 0;
1133 unsigned int msg_size = 0;
1134 int err;
1135
1136 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
1137 if (err)
1138 return err;
1139
1140 err = rpmb_get_regs(hdl, &regs);
1141 if (err)
1142 return err;
1143
1144 key_buf = rpmb_read_and_validate_key(cfg.key, cfg.keyfile, &key_size);
1145 if (!key_buf)
1146 return -1;
1147
1148 err = rpmb_read_msg(cfg.msg, cfg.msgfile, &msg_buf, &msg_size);
1149 if (err || !msg_size) {
1150 nvme_show_error("Failed to read msg data")nvme_show_message(1, "Failed to read msg data");
1151 return -1;
1152 }
1153
1154 if (msg_size < sizeof(struct rpmb_config_block_t)) {
1155 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))
1156 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))
;
1157 return -1;
1158 }
1159
1160 err = rpmb_write_config_block(hdl, msg_buf, key_buf, key_size);
1161 if (!err)
1162 nvme_show_verbose_result("RPMB configuration block written")nvme_show_verbose_message("RPMB configuration block written");
1163
1164 return err;
1165}
1166
1167static struct command rpmb_info_cmd = {
1168 .name = "info",
1169 .help = "Print RPMB support information for the controller",
1170 .fn = rpmb_info,
1171};
1172
1173static struct command rpmb_program_key_cmd = {
1174 .name = "program-key",
1175 .help = "Program the RPMB authentication key",
1176 .fn = rpmb_program_key,
1177};
1178
1179static struct command rpmb_read_counter_cmd = {
1180 .name = "read-counter",
1181 .help = "Read the RPMB write counter",
1182 .fn = rpmb_read_counter,
1183};
1184
1185static struct command rpmb_read_data_cmd = {
1186 .name = "read-data",
1187 .help = "Read authenticated data from an RPMB target",
1188 .fn = rpmb_read_data,
1189};
1190
1191static struct command rpmb_write_data_cmd = {
1192 .name = "write-data",
1193 .help = "Write authenticated data to an RPMB target",
1194 .fn = rpmb_write_data,
1195};
1196
1197static struct command rpmb_read_config_cmd = {
1198 .name = "read-config",
1199 .help = "Read the RPMB device configuration block",
1200 .fn = rpmb_read_config,
1201};
1202
1203static struct command rpmb_write_config_cmd = {
1204 .name = "write-config",
1205 .help = "Write the RPMB device configuration block",
1206 .fn = rpmb_write_config,
1207};
1208
1209static struct command *commands[] = {
1210 &rpmb_info_cmd,
1211 &rpmb_program_key_cmd,
1212 &rpmb_read_counter_cmd,
1213 &rpmb_read_data_cmd,
1214 &rpmb_write_data_cmd,
1215 &rpmb_read_config_cmd,
1216 &rpmb_write_config_cmd,
1217 NULL((void*)0),
1218};
1219
1220static struct plugin plugin = {
1221 .name = "rpmb",
1222 .desc = "Replay Protected Memory Block commands",
1223 .version = NVME_VERSION"3.2",
1224 .core = true1,
1225 .group = "Security & Access Control",
1226};
1227
1228static void __shr_constructor__attribute__((constructor)) register_plugin(void)
1229{
1230 plugin_add_group(&plugin, NULL((void*)0), commands);
1231 register_extension(&plugin);
1232}