1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 /*
4  * Live Update interfaces for Xen Store Daemon.
5  * Copyright (C) 2022 Juergen Gross, SUSE LLC
6  */
7 
8 #include <assert.h>
9 #include <ctype.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <syslog.h>
13 #include <time.h>
14 #include <unistd.h>
15 #include <sys/mman.h>
16 #include <sys/stat.h>
17 
18 #include "talloc.h"
19 #include "core.h"
20 #include "domain.h"
21 #include "lu.h"
22 #include "watch.h"
23 
24 struct live_update *lu_status;
25 
26 #ifndef NO_LIVE_UPDATE
27 
28 struct lu_dump_state {
29 	void *buf;
30 	unsigned int buf_size;
31 	size_t size;
32 	size_t offset;
33 	char *filename;
34 	FILE *fp;
35 };
36 
lu_destroy(void * data)37 static int lu_destroy(void *data)
38 {
39 	lu_status = NULL;
40 
41 	return 0;
42 }
43 
lu_begin(struct connection * conn)44 const char *lu_begin(struct connection *conn)
45 {
46 	if (lu_status)
47 		return "live-update session already active.";
48 
49 	lu_status = talloc_zero(conn, struct live_update);
50 	if (!lu_status)
51 		return "Allocation failure.";
52 	lu_status->conn = conn;
53 	talloc_set_destructor(lu_status, lu_destroy);
54 
55 	return NULL;
56 }
57 
lu_get_connection(void)58 struct connection *lu_get_connection(void)
59 {
60 	return lu_status ? lu_status->conn : NULL;
61 }
62 
lu_write_response(FILE * fp)63 unsigned int lu_write_response(FILE *fp)
64 {
65 	struct xsd_sockmsg msg;
66 
67 	assert(lu_status);
68 
69 	msg = lu_status->in->hdr.msg;
70 
71 	msg.len = sizeof("OK");
72 	if (fp && fwrite(&msg, sizeof(msg), 1, fp) != 1)
73 		return 0;
74 	if (fp && fwrite("OK", msg.len, 1, fp) != 1)
75 		return 0;
76 
77 	return sizeof(msg) + msg.len;
78 }
79 
lu_is_pending(void)80 bool lu_is_pending(void)
81 {
82 	return lu_status != NULL;
83 }
84 
lu_get_dump_state(void * ctx,struct lu_dump_state * state)85 static void lu_get_dump_state(void *ctx, struct lu_dump_state *state)
86 {
87 	struct stat statbuf;
88 	int fd;
89 
90 	state->size = 0;
91 
92 	state->filename = talloc_asprintf(NULL, "%s/state_dump",
93 					  xenstore_rundir());
94 	if (!state->filename)
95 		barf("Allocation failure");
96 
97 	fd = open(state->filename, O_RDONLY);
98 	if (fd < 0)
99 		barf("No state file found");
100 	if (fstat(fd, &statbuf) != 0)
101 		barf("Could not fstat state file");
102 	state->size = statbuf.st_size;
103 
104 	/* Start with a 4k buffer. If needed we'll reallocate a larger one. */
105 	state->buf_size = 4096;
106 	state->buf = talloc_size(ctx, state->buf_size);
107 	if (!state->buf)
108 		barf("Allocation failure");
109 
110 	state->fp = fdopen(fd, "r");
111 }
112 
lu_dump_close(FILE * fp)113 static void lu_dump_close(FILE *fp)
114 {
115 	fclose(fp);
116 }
117 
lu_close_dump_state(struct lu_dump_state * state)118 static void lu_close_dump_state(struct lu_dump_state *state)
119 {
120 	assert(state->filename != NULL);
121 
122 	lu_dump_close(state->fp);
123 
124 	unlink(state->filename);
125 	talloc_free(state->filename);
126 	talloc_free(state->buf);
127 }
128 
lu_read_data(void * ctx,struct lu_dump_state * state,unsigned int size)129 static void lu_read_data(void *ctx, struct lu_dump_state *state,
130 			 unsigned int size)
131 {
132 	if (state->offset + size > state->size)
133 		barf("Inconsistent state data");
134 
135 	if (size > state->buf_size) {
136 		state->buf = talloc_realloc_size(ctx, state->buf, size);
137 		if (!state->buf)
138 			barf("Allocation failure");
139 		state->buf_size = size;
140 	}
141 
142 	if (fread(state->buf, size, 1, state->fp) != 1)
143 		barf("State read error");
144 
145 	state->offset += size;
146 }
147 
lu_read_state(void)148 void lu_read_state(void)
149 {
150 	struct lu_dump_state state = {};
151 	struct xs_state_record_header head;
152 	void *ctx = talloc_new(NULL); /* Work context for subfunctions. */
153 	struct xs_state_preamble *pre;
154 	unsigned int version;
155 
156 	syslog(LOG_INFO, "live-update: read state\n");
157 	lu_get_dump_state(ctx, &state);
158 	if (state.size == 0)
159 		barf_perror("No state found after live-update");
160 
161 	lu_read_data(ctx, &state, sizeof(*pre));
162 	pre = state.buf;
163 	version = be32toh(pre->version);
164 	if (memcmp(pre->ident, XS_STATE_IDENT, sizeof(pre->ident)) ||
165 	    !version || version > XS_STATE_VERSION ||
166 	    pre->flags != XS_STATE_FLAGS)
167 		barf("Unknown record identifier");
168 
169 	for (;;) {
170 		lu_read_data(ctx, &state, sizeof(head));
171 		head = *(struct xs_state_record_header *)(state.buf);
172 		if (head.type == XS_STATE_TYPE_END)
173 			break;
174 		lu_read_data(ctx, &state, head.length);
175 
176 		switch (head.type) {
177 		case XS_STATE_TYPE_GLOBAL:
178 			read_state_global(ctx, state.buf);
179 			break;
180 		case XS_STATE_TYPE_CONN:
181 			read_state_connection(ctx, state.buf);
182 			break;
183 		case XS_STATE_TYPE_WATCH:
184 			read_state_watch(ctx, state.buf);
185 			break;
186 		case XS_STATE_TYPE_TA:
187 			xprintf("live-update: ignore transaction record\n");
188 			break;
189 		case XS_STATE_TYPE_NODE:
190 			read_state_node(ctx, state.buf);
191 			break;
192 		case XS_STATE_TYPE_DOMAIN:
193 			read_state_domain(ctx, state.buf, version);
194 			break;
195 		default:
196 			xprintf("live-update: unknown state record %08x\n",
197 				head.type);
198 			break;
199 		}
200 	}
201 
202 	lu_close_dump_state(&state);
203 
204 	talloc_free(ctx);
205 
206 	/*
207 	 * We may have missed the VIRQ_DOM_EXC notification and a domain may
208 	 * have died while we were live-updating. So check all the domains are
209 	 * still alive.
210 	 */
211 	check_domains();
212 }
213 
lu_abort(const void * ctx,struct connection * conn)214 static const char *lu_abort(const void *ctx, struct connection *conn)
215 {
216 	syslog(LOG_INFO, "live-update: abort\n");
217 
218 	if (!lu_status)
219 		return "No live-update session active.";
220 
221 	/* Destructor will do the real abort handling. */
222 	talloc_free(lu_status);
223 
224 	return NULL;
225 }
226 
lu_cmdline(const void * ctx,struct connection * conn,const char * cmdline)227 static const char *lu_cmdline(const void *ctx, struct connection *conn,
228 			      const char *cmdline)
229 {
230 	syslog(LOG_INFO, "live-update: cmdline %s\n", cmdline);
231 
232 	if (!lu_status || lu_status->conn != conn)
233 		return "Not in live-update session.";
234 
235 	lu_status->cmdline = talloc_strdup(lu_status, cmdline);
236 	if (!lu_status->cmdline)
237 		return "Allocation failure.";
238 
239 	return NULL;
240 }
241 
lu_check_lu_allowed(void)242 static bool lu_check_lu_allowed(void)
243 {
244 	struct connection *conn;
245 	time_t now = time(NULL);
246 	unsigned int ta_total = 0, ta_long = 0;
247 
248 	list_for_each_entry(conn, &connections, list) {
249 		if (conn->ta_start_time) {
250 			ta_total++;
251 			if (now - conn->ta_start_time >= lu_status->timeout)
252 				ta_long++;
253 		}
254 	}
255 
256 	/*
257 	 * Allow LiveUpdate if one of the following conditions is met:
258 	 *	- There is no active transactions
259 	 *	- All transactions are long running (e.g. they have been
260 	 *	active for more than lu_status->timeout sec) and the admin as
261 	 *	requested to force the operation.
262 	 */
263 	return ta_total ? (lu_status->force && ta_long == ta_total) : true;
264 }
265 
lu_reject_reason(const void * ctx)266 static const char *lu_reject_reason(const void *ctx)
267 {
268 	char *ret = NULL;
269 	struct connection *conn;
270 	time_t now = time(NULL);
271 
272 	list_for_each_entry(conn, &connections, list) {
273 		unsigned long tdiff = now - conn->ta_start_time;
274 
275 		if (conn->ta_start_time && (tdiff >= lu_status->timeout)) {
276 			ret = talloc_asprintf(ctx, "%s\nDomain %u: %ld s",
277 					      ret ? : "Domains with long running transactions:",
278 					      conn->id, tdiff);
279 		}
280 	}
281 
282 	return ret ? (const char *)ret : "Overlapping transactions";
283 }
284 
lu_dump_open(const void * ctx)285 static FILE *lu_dump_open(const void *ctx)
286 {
287 	char *filename;
288 	int fd;
289 
290 	filename = talloc_asprintf(ctx, "%s/state_dump",
291 				   xenstore_rundir());
292 	if (!filename)
293 		return NULL;
294 
295 	fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
296 	if (fd < 0)
297 		return NULL;
298 
299 	return fdopen(fd, "w");
300 }
301 
lu_dump_state(const void * ctx,struct connection * conn)302 static const char *lu_dump_state(const void *ctx, struct connection *conn)
303 {
304 	FILE *fp;
305 	const char *ret;
306 	struct xs_state_record_header end;
307 	struct xs_state_preamble pre;
308 
309 	fp = lu_dump_open(ctx);
310 	if (!fp)
311 		return "Dump state open error";
312 
313 	memcpy(pre.ident, XS_STATE_IDENT, sizeof(pre.ident));
314 	pre.version = htobe32(lu_status->version);
315 	pre.flags = XS_STATE_FLAGS;
316 	if (fwrite(&pre, sizeof(pre), 1, fp) != 1) {
317 		ret = "Dump write error";
318 		goto out;
319 	}
320 
321 	ret = dump_state_global(fp);
322 	if (ret)
323 		goto out;
324 	ret = dump_state_connections(fp);
325 	if (ret)
326 		goto out;
327 	ret = dump_state_nodes(fp, ctx);
328 	if (ret)
329 		goto out;
330 	ret = dump_state_domains(fp);
331 	if (ret)
332 		goto out;
333 
334 	end.type = XS_STATE_TYPE_END;
335 	end.length = 0;
336 	if (fwrite(&end, sizeof(end), 1, fp) != 1)
337 		ret = "Dump write error";
338 
339  out:
340 	lu_dump_close(fp);
341 
342 	return ret;
343 }
344 
lu_activate_binary(const void * ctx)345 static const char *lu_activate_binary(const void *ctx)
346 {
347 	int argc;
348 	char **argv;
349 	unsigned int i;
350 
351 	if (lu_status->cmdline) {
352 		argc = 4;   /* At least one arg + progname + "-U" + NULL. */
353 		for (i = 0; lu_status->cmdline[i]; i++)
354 			if (isspace(lu_status->cmdline[i]))
355 				argc++;
356 		argv = talloc_array(ctx, char *, argc);
357 		if (!argv)
358 			return "Allocation failure.";
359 
360 		i = 0;
361 		argc = 1;
362 		argv[1] = strtok(lu_status->cmdline, " \t");
363 		while (argv[argc]) {
364 			if (!strcmp(argv[argc], "-U"))
365 				i = 1;
366 			argc++;
367 			argv[argc] = strtok(NULL, " \t");
368 		}
369 
370 		if (!i) {
371 			argv[argc++] = "-U";
372 			argv[argc] = NULL;
373 		}
374 	} else {
375 		for (i = 0; i < orig_argc; i++)
376 			if (!strcmp(orig_argv[i], "-U"))
377 				break;
378 
379 		argc = orig_argc;
380 		argv = talloc_array(ctx, char *, orig_argc + 2);
381 		if (!argv)
382 			return "Allocation failure.";
383 
384 		memcpy(argv, orig_argv, orig_argc * sizeof(*argv));
385 		if (i == orig_argc)
386 			argv[argc++] = "-U";
387 		argv[argc] = NULL;
388 	}
389 
390 	domain_deinit();
391 
392 	return lu_exec(ctx, argc, argv);
393 }
394 
do_lu_start(struct delayed_request * req)395 static bool do_lu_start(struct delayed_request *req)
396 {
397 	time_t now = time(NULL);
398 	const char *ret;
399 	struct buffered_data *saved_in;
400 	struct connection *conn = req->data;
401 
402 	/*
403 	 * Cancellation may have been requested asynchronously. In this
404 	 * case, lu_status will be NULL.
405 	 */
406 	if (!lu_status) {
407 		ret = "Cancellation was requested";
408 		goto out;
409 	}
410 
411 	assert(lu_status->conn == conn);
412 
413 	if (!lu_check_lu_allowed()) {
414 		if (now < lu_status->started_at + lu_status->timeout)
415 			return false;
416 		if (!lu_status->force) {
417 			ret = lu_reject_reason(req);
418 			goto out;
419 		}
420 	}
421 
422 	assert(req->in == lu_status->in);
423 	/* Dump out internal state, including "OK" for live update. */
424 	ret = lu_dump_state(req->in, conn);
425 	if (!ret) {
426 		/* Perform the activation of new binary. */
427 		ret = lu_activate_binary(req->in);
428 	}
429 
430 	/* We will reach this point only in case of failure. */
431  out:
432 	/*
433 	 * send_reply() will send the response for conn->in. Save the current
434 	 * conn->in and restore it afterwards.
435 	 */
436 	saved_in = conn->in;
437 	conn->in = req->in;
438 	send_reply(conn, XS_CONTROL, ret, strlen(ret) + 1);
439 	conn->in = saved_in;
440 	talloc_free(lu_status);
441 
442 	return true;
443 }
444 
lu_start(const void * ctx,struct connection * conn,bool force,unsigned int to,unsigned int vers)445 static const char *lu_start(const void *ctx, struct connection *conn,
446 			    bool force, unsigned int to, unsigned int vers)
447 {
448 	syslog(LOG_INFO, "live-update: start, force=%d, to=%u\n", force, to);
449 
450 	if (!lu_status || lu_status->conn != conn)
451 		return "Not in live-update session.";
452 
453 	if (!vers || vers > XS_STATE_VERSION)
454 		return "Migration stream version not supported.";
455 
456 #ifdef __MINIOS__
457 	if (lu_status->kernel_size != lu_status->kernel_off)
458 		return "Kernel not complete.";
459 #endif
460 
461 	lu_status->force = force;
462 	lu_status->timeout = to;
463 	lu_status->version = vers;
464 	lu_status->started_at = time(NULL);
465 	lu_status->in = conn->in;
466 
467 	errno = delay_request(conn, conn->in, do_lu_start, conn, false);
468 
469 	return NULL;
470 }
471 
do_control_lu(const void * ctx,struct connection * conn,const char ** vec,int num)472 int do_control_lu(const void *ctx, struct connection *conn, const char **vec,
473 		  int num)
474 {
475 	const char *ret = NULL;
476 	unsigned int i;
477 	bool force = false;
478 	unsigned int to = 0;
479 	unsigned int vers = XS_STATE_VERSION;
480 
481 	if (num < 1)
482 		return EINVAL;
483 
484 	if (!strcmp(vec[0], "-a")) {
485 		if (num == 1)
486 			ret = lu_abort(ctx, conn);
487 		else
488 			return EINVAL;
489 	} else if (!strcmp(vec[0], "-c")) {
490 		if (num == 2)
491 			ret = lu_cmdline(ctx, conn, vec[1]);
492 		else
493 			return EINVAL;
494 	} else if (!strcmp(vec[0], "-s")) {
495 		for (i = 1; i < num; i++) {
496 			if (!strcmp(vec[i], "-F")) {
497 				force = true;
498 			} else if (!strcmp(vec[i], "-t") && i < num - 1) {
499 				i++;
500 				to = atoi(vec[i]);
501 			} else if (!strcmp(vec[i], "-v") && i < num - 1) {
502 				i++;
503 				vers = atoi(vec[i]);
504 			} else {
505 				return EINVAL;
506 			}
507 		}
508 		ret = lu_start(ctx, conn, force, to, vers);
509 		if (!ret)
510 			return errno;
511 	} else {
512 		ret = lu_arch(ctx, conn, vec, num);
513 		if (!ret && errno)
514 			return errno;
515 	}
516 
517 	if (!ret)
518 		ret = "OK";
519 	send_reply(conn, XS_CONTROL, ret, strlen(ret) + 1);
520 	return 0;
521 }
522 #endif
523