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