xref: /linux/arch/um/drivers/cow_user.c (revision 91e901c65b4da02a6fd543e3f0049829ae9645b7)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
4  */
5 
6 /*
7  * _XOPEN_SOURCE is needed for pread, but we define _GNU_SOURCE, which defines
8  * that.
9  */
10 #include <unistd.h>
11 #include <errno.h>
12 #include <string.h>
13 #include <arpa/inet.h>
14 #include <endian.h>
15 #include "cow.h"
16 #include "cow_sys.h"
17 
18 /*
19  * arch/um/Makefile remaps strrchr to kernel_strrchr; call the kernel
20  * name directly to avoid glibc >= 2.43's C23 strrchr macro.
21  */
22 char *kernel_strrchr(const char *, int);
23 
24 #define PATH_LEN_V1 256
25 
26 /* unsigned time_t works until year 2106 */
27 typedef __u32 time32_t;
28 
29 struct cow_header_v1 {
30 	__s32 magic;
31 	__s32 version;
32 	char backing_file[PATH_LEN_V1];
33 	time32_t mtime;
34 	__u64 size;
35 	__s32 sectorsize;
36 } __attribute__((packed));
37 
38 /*
39  * Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in
40  * case other systems have different values for MAXPATHLEN.
41  *
42  * The same must hold for V2 - we want file format compatibility, not anything
43  * else.
44  */
45 #define PATH_LEN_V3 4096
46 #define PATH_LEN_V2 PATH_LEN_V3
47 
48 struct cow_header_v2 {
49 	__u32 magic;
50 	__u32 version;
51 	char backing_file[PATH_LEN_V2];
52 	time32_t mtime;
53 	__u64 size;
54 	__s32 sectorsize;
55 } __attribute__((packed));
56 
57 /*
58  * Changes from V2 -
59  *	PATH_LEN_V3 as described above
60  *	Explicitly specify field bit lengths for systems with different
61  *		lengths for the usual C types.  Not sure whether char or
62  *		time_t should be changed, this can be changed later without
63  *		breaking compatibility
64  *	Add alignment field so that different alignments can be used for the
65  *		bitmap and data
66  * 	Add cow_format field to allow for the possibility of different ways
67  *		of specifying the COW blocks.  For now, the only value is 0,
68  * 		for the traditional COW bitmap.
69  *	Move the backing_file field to the end of the header.  This allows
70  *		for the possibility of expanding it into the padding required
71  *		by the bitmap alignment.
72  * 	The bitmap and data portions of the file will be aligned as specified
73  * 		by the alignment field.  This is to allow COW files to be
74  *		put on devices with restrictions on access alignments, such as
75  *		/dev/raw, with a 512 byte alignment restriction.  This also
76  *		allows the data to be more aligned more strictly than on
77  *		sector boundaries.  This is needed for ubd-mmap, which needs
78  *		the data to be page aligned.
79  *	Fixed (finally!) the rounding bug
80  */
81 
82 /*
83  * Until Dec2005, __attribute__((packed)) was left out from the below
84  * definition, leading on 64-bit systems to 4 bytes of padding after mtime, to
85  * align size to 8-byte alignment.  This shifted all fields above (no padding
86  * was present on 32-bit, no other padding was added).
87  *
88  * However, this _can be detected_: it means that cow_format (always 0 until
89  * now) is shifted onto the first 4 bytes of backing_file, where it is otherwise
90  * impossible to find 4 zeros. -bb */
91 
92 struct cow_header_v3 {
93 	__u32 magic;
94 	__u32 version;
95 	__u32 mtime;
96 	__u64 size;
97 	__u32 sectorsize;
98 	__u32 alignment;
99 	__u32 cow_format;
100 	char backing_file[PATH_LEN_V3];
101 } __attribute__((packed));
102 
103 /* This is the broken layout used by some 64-bit binaries. */
104 struct cow_header_v3_broken {
105 	__u32 magic;
106 	__u32 version;
107 	__s64 mtime;
108 	__u64 size;
109 	__u32 sectorsize;
110 	__u32 alignment;
111 	__u32 cow_format;
112 	char backing_file[PATH_LEN_V3];
113 };
114 
115 /* COW format definitions - for now, we have only the usual COW bitmap */
116 #define COW_BITMAP 0
117 
118 union cow_header {
119 	struct cow_header_v1 v1;
120 	struct cow_header_v2 v2;
121 	struct cow_header_v3 v3;
122 	struct cow_header_v3_broken v3_b;
123 };
124 
125 #define COW_MAGIC 0x4f4f4f4d  /* MOOO */
126 #define COW_VERSION 3
127 
128 #define DIV_ROUND(x, len) (((x) + (len) - 1) / (len))
129 #define ROUND_UP(x, align) DIV_ROUND(x, align) * (align)
130 
131 void cow_sizes(int version, __u64 size, int sectorsize, int align,
132 	       int bitmap_offset, unsigned long *bitmap_len_out,
133 	       int *data_offset_out)
134 {
135 	if (version < 3) {
136 		*bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize);
137 
138 		*data_offset_out = bitmap_offset + *bitmap_len_out;
139 		*data_offset_out = (*data_offset_out + sectorsize - 1) /
140 			sectorsize;
141 		*data_offset_out *= sectorsize;
142 	}
143 	else {
144 		*bitmap_len_out = DIV_ROUND(size, sectorsize);
145 		*bitmap_len_out = DIV_ROUND(*bitmap_len_out, 8);
146 
147 		*data_offset_out = bitmap_offset + *bitmap_len_out;
148 		*data_offset_out = ROUND_UP(*data_offset_out, align);
149 	}
150 }
151 
152 static int absolutize(char *to, int size, char *from)
153 {
154 	char save_cwd[256], *slash;
155 	int remaining;
156 
157 	if (getcwd(save_cwd, sizeof(save_cwd)) == NULL) {
158 		cow_printf("absolutize : unable to get cwd - errno = %d\n",
159 			   errno);
160 		return -1;
161 	}
162 	slash = kernel_strrchr(from, '/');
163 	if (slash != NULL) {
164 		*slash = '\0';
165 		if (chdir(from)) {
166 			*slash = '/';
167 			cow_printf("absolutize : Can't cd to '%s' - "
168 				   "errno = %d\n", from, errno);
169 			return -1;
170 		}
171 		*slash = '/';
172 		if (getcwd(to, size) == NULL) {
173 			cow_printf("absolutize : unable to get cwd of '%s' - "
174 			       "errno = %d\n", from, errno);
175 			return -1;
176 		}
177 		remaining = size - strlen(to);
178 		if (strlen(slash) + 1 > remaining) {
179 			cow_printf("absolutize : unable to fit '%s' into %d "
180 			       "chars\n", from, size);
181 			return -1;
182 		}
183 		strcat(to, slash);
184 	}
185 	else {
186 		if (strlen(save_cwd) + 1 + strlen(from) + 1 > size) {
187 			cow_printf("absolutize : unable to fit '%s' into %d "
188 			       "chars\n", from, size);
189 			return -1;
190 		}
191 		strcpy(to, save_cwd);
192 		strcat(to, "/");
193 		strcat(to, from);
194 	}
195 	if (chdir(save_cwd)) {
196 		cow_printf("absolutize : Can't cd to '%s' - "
197 			   "errno = %d\n", save_cwd, errno);
198 		return -1;
199 	}
200 	return 0;
201 }
202 
203 int write_cow_header(char *cow_file, int fd, char *backing_file,
204 		     int sectorsize, int alignment, unsigned long long *size)
205 {
206 	struct cow_header_v3 *header;
207 	long long modtime;
208 	int err;
209 
210 	err = cow_seek_file(fd, 0);
211 	if (err < 0) {
212 		cow_printf("write_cow_header - lseek failed, err = %d\n", -err);
213 		goto out;
214 	}
215 
216 	err = -ENOMEM;
217 	header = cow_malloc(sizeof(*header));
218 	if (header == NULL) {
219 		cow_printf("write_cow_header - failed to allocate COW V3 "
220 			   "header\n");
221 		goto out;
222 	}
223 	header->magic = htobe32(COW_MAGIC);
224 	header->version = htobe32(COW_VERSION);
225 
226 	err = -EINVAL;
227 	if (strlen(backing_file) > sizeof(header->backing_file) - 1) {
228 		/* Below, %zd is for a size_t value */
229 		cow_printf("Backing file name \"%s\" is too long - names are "
230 			   "limited to %zd characters\n", backing_file,
231 			   sizeof(header->backing_file) - 1);
232 		goto out_free;
233 	}
234 
235 	if (absolutize(header->backing_file, sizeof(header->backing_file),
236 		      backing_file))
237 		goto out_free;
238 
239 	err = os_file_modtime(header->backing_file, &modtime);
240 	if (err < 0) {
241 		cow_printf("write_cow_header - backing file '%s' mtime "
242 			   "request failed, err = %d\n", header->backing_file,
243 			   -err);
244 		goto out_free;
245 	}
246 
247 	err = cow_file_size(header->backing_file, size);
248 	if (err < 0) {
249 		cow_printf("write_cow_header - couldn't get size of "
250 			   "backing file '%s', err = %d\n",
251 			   header->backing_file, -err);
252 		goto out_free;
253 	}
254 
255 	header->mtime = htobe32(modtime);
256 	header->size = htobe64(*size);
257 	header->sectorsize = htobe32(sectorsize);
258 	header->alignment = htobe32(alignment);
259 	header->cow_format = COW_BITMAP;
260 
261 	err = cow_write_file(fd, header, sizeof(*header));
262 	if (err != sizeof(*header)) {
263 		cow_printf("write_cow_header - write of header to "
264 			   "new COW file '%s' failed, err = %d\n", cow_file,
265 			   -err);
266 		goto out_free;
267 	}
268 	err = 0;
269  out_free:
270 	cow_free(header);
271  out:
272 	return err;
273 }
274 
275 int file_reader(__u64 offset, char *buf, int len, void *arg)
276 {
277 	int fd = *((int *) arg);
278 
279 	return pread(fd, buf, len, offset);
280 }
281 
282 /* XXX Need to sanity-check the values read from the header */
283 
284 int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg,
285 		    __u32 *version_out, char **backing_file_out,
286 		    long long *mtime_out, unsigned long long *size_out,
287 		    int *sectorsize_out, __u32 *align_out,
288 		    int *bitmap_offset_out)
289 {
290 	union cow_header *header;
291 	char *file;
292 	int err, n;
293 	unsigned long version, magic;
294 
295 	header = cow_malloc(sizeof(*header));
296 	if (header == NULL) {
297 	        cow_printf("read_cow_header - Failed to allocate header\n");
298 		return -ENOMEM;
299 	}
300 	err = -EINVAL;
301 	n = (*reader)(0, (char *) header, sizeof(*header), arg);
302 	if (n < offsetof(typeof(header->v1), backing_file)) {
303 		cow_printf("read_cow_header - short header\n");
304 		goto out;
305 	}
306 
307 	magic = header->v1.magic;
308 	if (magic == COW_MAGIC)
309 		version = header->v1.version;
310 	else if (magic == be32toh(COW_MAGIC))
311 		version = be32toh(header->v1.version);
312 	/* No error printed because the non-COW case comes through here */
313 	else goto out;
314 
315 	*version_out = version;
316 
317 	if (version == 1) {
318 		if (n < sizeof(header->v1)) {
319 			cow_printf("read_cow_header - failed to read V1 "
320 				   "header\n");
321 			goto out;
322 		}
323 		*mtime_out = header->v1.mtime;
324 		*size_out = header->v1.size;
325 		*sectorsize_out = header->v1.sectorsize;
326 		*bitmap_offset_out = sizeof(header->v1);
327 		*align_out = *sectorsize_out;
328 		file = header->v1.backing_file;
329 	}
330 	else if (version == 2) {
331 		if (n < sizeof(header->v2)) {
332 			cow_printf("read_cow_header - failed to read V2 "
333 				   "header\n");
334 			goto out;
335 		}
336 		*mtime_out = be32toh(header->v2.mtime);
337 		*size_out = be64toh(header->v2.size);
338 		*sectorsize_out = be32toh(header->v2.sectorsize);
339 		*bitmap_offset_out = sizeof(header->v2);
340 		*align_out = *sectorsize_out;
341 		file = header->v2.backing_file;
342 	}
343 	/* This is very subtle - see above at union cow_header definition */
344 	else if (version == 3 && (*((int*)header->v3.backing_file) != 0)) {
345 		if (n < sizeof(header->v3)) {
346 			cow_printf("read_cow_header - failed to read V3 "
347 				   "header\n");
348 			goto out;
349 		}
350 		*mtime_out = be32toh(header->v3.mtime);
351 		*size_out = be64toh(header->v3.size);
352 		*sectorsize_out = be32toh(header->v3.sectorsize);
353 		*align_out = be32toh(header->v3.alignment);
354 		if (*align_out == 0) {
355 			cow_printf("read_cow_header - invalid COW header, "
356 				   "align == 0\n");
357 		}
358 		*bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out);
359 		file = header->v3.backing_file;
360 	}
361 	else if (version == 3) {
362 		cow_printf("read_cow_header - broken V3 file with"
363 			   " 64-bit layout - recovering content.\n");
364 
365 		if (n < sizeof(header->v3_b)) {
366 			cow_printf("read_cow_header - failed to read V3 "
367 				   "header\n");
368 			goto out;
369 		}
370 
371 		/*
372 		 * this was used until Dec2005 - 64bits are needed to represent
373 		 * 2106+. I.e. we can safely do this truncating cast.
374 		 *
375 		 * Additionally, we must use be32toh() instead of be64toh(), since
376 		 * the program used to use the former (tested - I got mtime
377 		 * mismatch "0 vs whatever").
378 		 *
379 		 * Ever heard about bug-to-bug-compatibility ? ;-) */
380 		*mtime_out = (time32_t) be32toh(header->v3_b.mtime);
381 
382 		*size_out = be64toh(header->v3_b.size);
383 		*sectorsize_out = be32toh(header->v3_b.sectorsize);
384 		*align_out = be32toh(header->v3_b.alignment);
385 		if (*align_out == 0) {
386 			cow_printf("read_cow_header - invalid COW header, "
387 				   "align == 0\n");
388 		}
389 		*bitmap_offset_out = ROUND_UP(sizeof(header->v3_b), *align_out);
390 		file = header->v3_b.backing_file;
391 	}
392 	else {
393 		cow_printf("read_cow_header - invalid COW version\n");
394 		goto out;
395 	}
396 	err = -ENOMEM;
397 	*backing_file_out = cow_strdup(file);
398 	if (*backing_file_out == NULL) {
399 		cow_printf("read_cow_header - failed to allocate backing "
400 			   "file\n");
401 		goto out;
402 	}
403 	err = 0;
404  out:
405 	cow_free(header);
406 	return err;
407 }
408 
409 int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize,
410 		  int alignment, int *bitmap_offset_out,
411 		  unsigned long *bitmap_len_out, int *data_offset_out)
412 {
413 	unsigned long long size, offset;
414 	char zero = 0;
415 	int err;
416 
417 	err = write_cow_header(cow_file, fd, backing_file, sectorsize,
418 			       alignment, &size);
419 	if (err)
420 		goto out;
421 
422 	*bitmap_offset_out = ROUND_UP(sizeof(struct cow_header_v3), alignment);
423 	cow_sizes(COW_VERSION, size, sectorsize, alignment, *bitmap_offset_out,
424 		  bitmap_len_out, data_offset_out);
425 
426 	offset = *data_offset_out + size - sizeof(zero);
427 	err = cow_seek_file(fd, offset);
428 	if (err < 0) {
429 		cow_printf("cow bitmap lseek failed : err = %d\n", -err);
430 		goto out;
431 	}
432 
433 	/*
434 	 * does not really matter how much we write it is just to set EOF
435 	 * this also sets the entire COW bitmap
436 	 * to zero without having to allocate it
437 	 */
438 	err = cow_write_file(fd, &zero, sizeof(zero));
439 	if (err != sizeof(zero)) {
440 		cow_printf("Write of bitmap to new COW file '%s' failed, "
441 			   "err = %d\n", cow_file, -err);
442 		if (err >= 0)
443 			err = -EINVAL;
444 		goto out;
445 	}
446 
447 	return 0;
448  out:
449 	return err;
450 }
451