1 /*
2 * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
3 */
4
5 #include <fcntl.h>
6 #include <libgen.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/mman.h>
11 #include <sys/stat.h>
12 #include <time.h>
13 #include <unistd.h>
14 #include <xenctrl.h>
15 #include <xenstore.h>
16
17 #include <xen/errno.h>
18 #include <xen-tools/libs.h>
19
20 static xc_interface *xch;
21
show_help(void)22 void show_help(void)
23 {
24 fprintf(stderr,
25 "xen-livepatch: live patching tool\n"
26 "Usage: xen-livepatch <command> [args]\n"
27 " <name> An unique name of payload. Up to %d characters.\n"
28 "Commands:\n"
29 " help display this help\n"
30 " upload <name> <file> upload file <file> with <name> name\n"
31 " list list payloads uploaded.\n"
32 " apply <name> apply <name> patch.\n"
33 " revert <name> revert name <name> patch.\n"
34 " replace <name> apply <name> patch and revert all others.\n"
35 " unload <name> unload name <name> patch.\n"
36 " load <file> upload and apply <file>.\n"
37 " name is the <file> name\n",
38 XEN_LIVEPATCH_NAME_SIZE);
39 }
40
41 /* wrapper function */
help_func(int argc,char * argv[])42 static int help_func(int argc, char *argv[])
43 {
44 show_help();
45 return 0;
46 }
47
48 #define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
49
state2str(unsigned int state)50 static const char *state2str(unsigned int state)
51 {
52 #define STATE(x) [LIVEPATCH_STATE_##x] = #x
53 static const char *const names[] = {
54 STATE(CHECKED),
55 STATE(APPLIED),
56 };
57 #undef STATE
58 if (state >= ARRAY_SIZE(names) || !names[state])
59 return "unknown";
60
61 return names[state];
62 }
63
64 /* This value was choosen adhoc. It could be 42 too. */
65 #define MAX_LEN 11
list_func(int argc,char * argv[])66 static int list_func(int argc, char *argv[])
67 {
68 unsigned int idx, done, left, i;
69 xen_livepatch_status_t *info = NULL;
70 char *name = NULL;
71 uint32_t *len = NULL;
72 int rc = ENOMEM;
73
74 if ( argc )
75 {
76 show_help();
77 return -1;
78 }
79 idx = left = 0;
80 info = malloc(sizeof(*info) * MAX_LEN);
81 if ( !info )
82 return rc;
83 name = malloc(sizeof(*name) * XEN_LIVEPATCH_NAME_SIZE * MAX_LEN);
84 if ( !name )
85 {
86 free(info);
87 return rc;
88 }
89 len = malloc(sizeof(*len) * MAX_LEN);
90 if ( !len ) {
91 free(name);
92 free(info);
93 return rc;
94 }
95
96 do {
97 done = 0;
98 /* The memset is done to catch errors. */
99 memset(info, 'A', sizeof(*info) * MAX_LEN);
100 memset(name, 'B', sizeof(*name) * MAX_LEN * XEN_LIVEPATCH_NAME_SIZE);
101 memset(len, 'C', sizeof(*len) * MAX_LEN);
102 rc = xc_livepatch_list(xch, MAX_LEN, idx, info, name, len, &done, &left);
103 if ( rc )
104 {
105 rc = errno;
106 fprintf(stderr, "Failed to list %d/%d.\n"
107 "Error %d: %s\n",
108 idx, left, rc, strerror(rc));
109 break;
110 }
111 if ( !idx )
112 fprintf(stdout," ID | status\n"
113 "----------------------------------------+------------\n");
114
115 for ( i = 0; i < done; i++ )
116 {
117 unsigned int j;
118 uint32_t sz;
119 char *str;
120
121 sz = len[i];
122 str = name + (i * XEN_LIVEPATCH_NAME_SIZE);
123 for ( j = sz; j < XEN_LIVEPATCH_NAME_SIZE; j++ )
124 str[j] = '\0';
125
126 printf("%-40s| %s", str, state2str(info[i].state));
127 if ( info[i].rc )
128 printf(" (%d, %s)\n", -info[i].rc, strerror(-info[i].rc));
129 else
130 puts("");
131 }
132 idx += done;
133 } while ( left );
134
135 free(name);
136 free(info);
137 free(len);
138 return rc;
139 }
140 #undef MAX_LEN
141
get_name(int argc,char * argv[],char * name)142 static int get_name(int argc, char *argv[], char *name)
143 {
144 ssize_t len = strlen(argv[0]);
145 if ( len > XEN_LIVEPATCH_NAME_SIZE )
146 {
147 fprintf(stderr, "ID must be no more than %d characters.\n",
148 XEN_LIVEPATCH_NAME_SIZE);
149 errno = EINVAL;
150 return errno;
151 }
152 /* Don't want any funny strings from the stack. */
153 memset(name, 0, XEN_LIVEPATCH_NAME_SIZE);
154 strncpy(name, argv[0], len);
155 return 0;
156 }
157
upload_func(int argc,char * argv[])158 static int upload_func(int argc, char *argv[])
159 {
160 char *filename;
161 char name[XEN_LIVEPATCH_NAME_SIZE];
162 int fd = 0, rc;
163 struct stat buf;
164 unsigned char *fbuf;
165 ssize_t len;
166
167 if ( argc != 2 )
168 {
169 show_help();
170 return -1;
171 }
172
173 if ( get_name(argc, argv, name) )
174 return EINVAL;
175
176 filename = argv[1];
177 fd = open(filename, O_RDONLY);
178 if ( fd < 0 )
179 {
180 int saved_errno = errno;
181 fprintf(stderr, "Could not open %s.\n"
182 "Error %d: %s\n",
183 filename, saved_errno, strerror(saved_errno));
184 return saved_errno;
185 }
186 if ( stat(filename, &buf) != 0 )
187 {
188 int saved_errno = errno;
189 fprintf(stderr, "Could not get size of %s.\n"
190 "Error %d: %s\n",
191 filename, saved_errno, strerror(saved_errno));
192 close(fd);
193 return saved_errno;
194 }
195
196 len = buf.st_size;
197 fbuf = mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0);
198 if ( fbuf == MAP_FAILED )
199 {
200 int saved_errno = errno;
201 fprintf(stderr, "Could not map %s.\n"
202 "Error %d: %s\n",
203 filename, saved_errno, strerror(saved_errno));
204 close (fd);
205 return saved_errno;
206 }
207 printf("Uploading %s... ", filename);
208 rc = xc_livepatch_upload(xch, name, fbuf, len);
209 if ( rc )
210 {
211 rc = errno;
212 printf("failed\n");
213 fprintf(stderr, "Error %d: %s\n", rc, strerror(rc));
214 }
215 else
216 printf("completed\n");
217
218
219 if ( munmap( fbuf, len) )
220 {
221 fprintf(stderr, "Could not unmap %s.\n"
222 "Error %d: %s\n",
223 filename, errno, strerror(errno));
224 }
225 close(fd);
226
227 return rc;
228 }
229
230 /* These MUST match to the 'action_options[]' array slots. */
231 enum {
232 ACTION_APPLY = 0,
233 ACTION_REVERT = 1,
234 ACTION_UNLOAD = 2,
235 ACTION_REPLACE = 3,
236 };
237
238 struct {
239 int allow; /* State it must be in to call function. */
240 int expected; /* The state to be in after the function. */
241 const char *name;
242 const char *verb;
243 int (*function)(xc_interface *xch, char *name, uint32_t timeout);
244 } action_options[] = {
245 { .allow = LIVEPATCH_STATE_CHECKED,
246 .expected = LIVEPATCH_STATE_APPLIED,
247 .name = "apply",
248 .verb = "Applying",
249 .function = xc_livepatch_apply,
250 },
251 { .allow = LIVEPATCH_STATE_APPLIED,
252 .expected = LIVEPATCH_STATE_CHECKED,
253 .name = "revert",
254 .verb = "Reverting",
255 .function = xc_livepatch_revert,
256 },
257 { .allow = LIVEPATCH_STATE_CHECKED,
258 .expected = -XEN_ENOENT,
259 .name = "unload",
260 .verb = "Unloading",
261 .function = xc_livepatch_unload,
262 },
263 { .allow = LIVEPATCH_STATE_CHECKED,
264 .expected = LIVEPATCH_STATE_APPLIED,
265 .name = "replace",
266 .verb = "Replacing all live patches with",
267 .function = xc_livepatch_replace,
268 },
269 };
270
271 /* The hypervisor timeout for the live patching operation is 30 msec,
272 * but it could take some time for the operation to start, so wait twice
273 * that period. */
274 #define HYPERVISOR_TIMEOUT_NS 30000000
275 #define DELAY (2 * HYPERVISOR_TIMEOUT_NS)
276
nanosleep_retry(long ns)277 static void nanosleep_retry(long ns)
278 {
279 struct timespec req, rem;
280 int rc;
281
282 rem.tv_sec = 0;
283 rem.tv_nsec = ns;
284
285 do {
286 req = rem;
287 rc = nanosleep(&req, &rem);
288 } while ( rc == -1 && errno == EINTR );
289 }
290
action_func(int argc,char * argv[],unsigned int idx)291 int action_func(int argc, char *argv[], unsigned int idx)
292 {
293 char name[XEN_LIVEPATCH_NAME_SIZE];
294 int rc;
295 xen_livepatch_status_t status;
296
297 if ( argc != 1 )
298 {
299 show_help();
300 return -1;
301 }
302
303 if ( idx >= ARRAY_SIZE(action_options) )
304 return -1;
305
306 if ( get_name(argc, argv, name) )
307 return EINVAL;
308
309 /* Check initial status. */
310 rc = xc_livepatch_get(xch, name, &status);
311 if ( rc )
312 {
313 int saved_errno = errno;
314 fprintf(stderr, "Failed to get status of %s.\n"
315 "Error %d: %s\n",
316 name, saved_errno, strerror(saved_errno));
317 return saved_errno;
318 }
319 if ( status.rc == -XEN_EAGAIN )
320 {
321 fprintf(stderr,
322 "Cannot execute %s.\n"
323 "Operation already in progress.\n", action_options[idx].name);
324 return EAGAIN;
325 }
326
327 if ( status.state == action_options[idx].expected )
328 {
329 printf("No action needed.\n");
330 return 0;
331 }
332
333 /* Perform action. */
334 if ( action_options[idx].allow & status.state )
335 {
336 printf("%s %s... ", action_options[idx].verb, name);
337 rc = action_options[idx].function(xch, name, HYPERVISOR_TIMEOUT_NS);
338 if ( rc )
339 {
340 int saved_errno = errno;
341 printf("failed\n");
342 fprintf(stderr, "Error %d: %s\n",
343 saved_errno, strerror(saved_errno));
344 return saved_errno;
345 }
346 }
347 else
348 {
349 fprintf(stderr, "%s is in the wrong state.\n"
350 "Current state: %s\n"
351 "Expected state: %s\n",
352 name, state2str(status.state),
353 state2str(action_options[idx].allow));
354 return -1;
355 }
356
357 nanosleep_retry(DELAY);
358 rc = xc_livepatch_get(xch, name, &status);
359
360 if ( rc )
361 rc = -errno;
362 else if ( status.rc )
363 rc = status.rc;
364
365 if ( rc == -XEN_EAGAIN )
366 {
367 printf("failed\n");
368 fprintf(stderr, "Operation didn't complete.\n");
369 return EAGAIN;
370 }
371
372 if ( rc == 0 )
373 rc = status.state;
374
375 if ( action_options[idx].expected == rc )
376 printf("completed\n");
377 else if ( rc < 0 )
378 {
379 printf("failed\n");
380 fprintf(stderr, "Error %d: %s\n", -rc, strerror(-rc));
381 return -rc;
382 }
383 else
384 {
385 printf("failed\n");
386 fprintf(stderr, "%s is in the wrong state.\n"
387 "Current state: %s\n"
388 "Expected state: %s\n",
389 name, state2str(rc),
390 state2str(action_options[idx].expected));
391 return -1;
392 }
393
394 return 0;
395 }
396
load_func(int argc,char * argv[])397 static int load_func(int argc, char *argv[])
398 {
399 int rc;
400 char *new_argv[2];
401 char *path, *name, *lastdot;
402
403 if ( argc != 1 )
404 {
405 show_help();
406 return -1;
407 }
408 /* <file> */
409 new_argv[1] = argv[0];
410
411 /* Synthesize the <id> */
412 path = strdup(argv[0]);
413
414 name = basename(path);
415 lastdot = strrchr(name, '.');
416 if ( lastdot != NULL )
417 *lastdot = '\0';
418 new_argv[0] = name;
419
420 rc = upload_func(2 /* <id> <file> */, new_argv);
421 if ( rc )
422 return rc;
423
424 rc = action_func(1 /* only <id> */, new_argv, ACTION_APPLY);
425 if ( rc )
426 action_func(1, new_argv, ACTION_UNLOAD);
427
428 free(path);
429 return rc;
430 }
431
432 /*
433 * These are also functions in action_options that are called in case
434 * none of the ones in main_options match.
435 */
436 struct {
437 const char *name;
438 int (*function)(int argc, char *argv[]);
439 } main_options[] = {
440 { "help", help_func },
441 { "list", list_func },
442 { "upload", upload_func },
443 { "load", load_func },
444 };
445
main(int argc,char * argv[])446 int main(int argc, char *argv[])
447 {
448 int i, j = 0, ret;
449
450 /*
451 * Set stdout to be unbuffered to avoid having to fflush when
452 * printing without a newline.
453 */
454 setvbuf(stdout, NULL, _IONBF, 0);
455
456 if ( argc <= 1 )
457 {
458 show_help();
459 return 0;
460 }
461 for ( i = 0; i < ARRAY_SIZE(main_options); i++ )
462 if (!strncmp(main_options[i].name, argv[1], strlen(argv[1])))
463 break;
464
465 if ( i == ARRAY_SIZE(main_options) )
466 {
467 for ( j = 0; j < ARRAY_SIZE(action_options); j++ )
468 if (!strncmp(action_options[j].name, argv[1], strlen(argv[1])))
469 break;
470
471 if ( j == ARRAY_SIZE(action_options) )
472 {
473 fprintf(stderr, "Unrecognised command '%s' -- try "
474 "'xen-livepatch help'\n", argv[1]);
475 return 1;
476 }
477 }
478
479 xch = xc_interface_open(0,0,0);
480 if ( !xch )
481 {
482 fprintf(stderr, "failed to get the handler\n");
483 return 0;
484 }
485
486 if ( i == ARRAY_SIZE(main_options) )
487 ret = action_func(argc -2, argv + 2, j);
488 else
489 ret = main_options[i].function(argc -2, argv + 2);
490
491 xc_interface_close(xch);
492
493 /*
494 * Exitcode 0 for success.
495 * Exitcode 1 for an error.
496 * Exitcode 2 if the operation should be retried for any reason (e.g. a
497 * timeout or because another operation was in progress).
498 */
499 #define EXIT_TIMEOUT (EXIT_FAILURE + 1)
500
501 BUILD_BUG_ON(EXIT_SUCCESS != 0);
502 BUILD_BUG_ON(EXIT_FAILURE != 1);
503 BUILD_BUG_ON(EXIT_TIMEOUT != 2);
504
505 switch ( ret )
506 {
507 case 0:
508 return EXIT_SUCCESS;
509 case EAGAIN:
510 case EBUSY:
511 return EXIT_TIMEOUT;
512 default:
513 return EXIT_FAILURE;
514 }
515 }
516
517 /*
518 * Local variables:
519 * mode: C
520 * c-file-style: "BSD"
521 * c-basic-offset: 4
522 * tab-width: 4
523 * indent-tabs-mode: nil
524 * End:
525 */
526