xref: /openbmc/u-boot/lib/efi_loader/efi_file.c (revision 57ade079)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  EFI utils
4  *
5  *  Copyright (c) 2017 Rob Clark
6  */
7 
8 #include <common.h>
9 #include <charset.h>
10 #include <efi_loader.h>
11 #include <malloc.h>
12 #include <mapmem.h>
13 #include <fs.h>
14 
15 /* GUID for file system information */
16 const efi_guid_t efi_file_system_info_guid = EFI_FILE_SYSTEM_INFO_GUID;
17 
18 struct file_system {
19 	struct efi_simple_file_system_protocol base;
20 	struct efi_device_path *dp;
21 	struct blk_desc *desc;
22 	int part;
23 };
24 #define to_fs(x) container_of(x, struct file_system, base)
25 
26 struct file_handle {
27 	struct efi_file_handle base;
28 	struct file_system *fs;
29 	loff_t offset;       /* current file position/cursor */
30 	int isdir;
31 
32 	/* for reading a directory: */
33 	struct fs_dir_stream *dirs;
34 	struct fs_dirent *dent;
35 
36 	char path[0];
37 };
38 #define to_fh(x) container_of(x, struct file_handle, base)
39 
40 static const struct efi_file_handle efi_file_handle_protocol;
41 
42 static char *basename(struct file_handle *fh)
43 {
44 	char *s = strrchr(fh->path, '/');
45 	if (s)
46 		return s + 1;
47 	return fh->path;
48 }
49 
50 static int set_blk_dev(struct file_handle *fh)
51 {
52 	return fs_set_blk_dev_with_part(fh->fs->desc, fh->fs->part);
53 }
54 
55 /**
56  * is_dir() - check if file handle points to directory
57  *
58  * We assume that set_blk_dev(fh) has been called already.
59  *
60  * @fh:		file handle
61  * Return:	true if file handle points to a directory
62  */
63 static int is_dir(struct file_handle *fh)
64 {
65 	struct fs_dir_stream *dirs;
66 
67 	dirs = fs_opendir(fh->path);
68 	if (!dirs)
69 		return 0;
70 
71 	fs_closedir(dirs);
72 
73 	return 1;
74 }
75 
76 /*
77  * Normalize a path which may include either back or fwd slashes,
78  * double slashes, . or .. entries in the path, etc.
79  */
80 static int sanitize_path(char *path)
81 {
82 	char *p;
83 
84 	/* backslash to slash: */
85 	p = path;
86 	while ((p = strchr(p, '\\')))
87 		*p++ = '/';
88 
89 	/* handle double-slashes: */
90 	p = path;
91 	while ((p = strstr(p, "//"))) {
92 		char *src = p + 1;
93 		memmove(p, src, strlen(src) + 1);
94 	}
95 
96 	/* handle extra /.'s */
97 	p = path;
98 	while ((p = strstr(p, "/."))) {
99 		/*
100 		 * You'd be tempted to do this *after* handling ".."s
101 		 * below to avoid having to check if "/." is start of
102 		 * a "/..", but that won't have the correct results..
103 		 * for example, "/foo/./../bar" would get resolved to
104 		 * "/foo/bar" if you did these two passes in the other
105 		 * order
106 		 */
107 		if (p[2] == '.') {
108 			p += 2;
109 			continue;
110 		}
111 		char *src = p + 2;
112 		memmove(p, src, strlen(src) + 1);
113 	}
114 
115 	/* handle extra /..'s: */
116 	p = path;
117 	while ((p = strstr(p, "/.."))) {
118 		char *src = p + 3;
119 
120 		p--;
121 
122 		/* find beginning of previous path entry: */
123 		while (true) {
124 			if (p < path)
125 				return -1;
126 			if (*p == '/')
127 				break;
128 			p--;
129 		}
130 
131 		memmove(p, src, strlen(src) + 1);
132 	}
133 
134 	return 0;
135 }
136 
137 /**
138  * file_open() - open a file handle
139  *
140  * @fs:			file system
141  * @parent:		directory relative to which the file is to be opened
142  * @file_name:		path of the file to be opened. '\', '.', or '..' may
143  *			be used as modifiers. A leading backslash indicates an
144  *			absolute path.
145  * @mode:		bit mask indicating the access mode (read, write,
146  *			create)
147  * @attributes:		attributes for newly created file
148  * Returns:		handle to the opened file or NULL
149  */
150 static struct efi_file_handle *file_open(struct file_system *fs,
151 		struct file_handle *parent, u16 *file_name, u64 mode,
152 		u64 attributes)
153 {
154 	struct file_handle *fh;
155 	char f0[MAX_UTF8_PER_UTF16] = {0};
156 	int plen = 0;
157 	int flen = 0;
158 
159 	if (file_name) {
160 		utf16_to_utf8((u8 *)f0, file_name, 1);
161 		flen = u16_strlen(file_name);
162 	}
163 
164 	/* we could have a parent, but also an absolute path: */
165 	if (f0[0] == '\\') {
166 		plen = 0;
167 	} else if (parent) {
168 		plen = strlen(parent->path) + 1;
169 	}
170 
171 	/* +2 is for null and '/' */
172 	fh = calloc(1, sizeof(*fh) + plen + (flen * MAX_UTF8_PER_UTF16) + 2);
173 
174 	fh->base = efi_file_handle_protocol;
175 	fh->fs = fs;
176 
177 	if (parent) {
178 		char *p = fh->path;
179 
180 		if (plen > 0) {
181 			strcpy(p, parent->path);
182 			p += plen - 1;
183 			*p++ = '/';
184 		}
185 
186 		utf16_to_utf8((u8 *)p, file_name, flen);
187 
188 		if (sanitize_path(fh->path))
189 			goto error;
190 
191 		/* check if file exists: */
192 		if (set_blk_dev(fh))
193 			goto error;
194 
195 		if ((mode & EFI_FILE_MODE_CREATE) &&
196 		    (attributes & EFI_FILE_DIRECTORY)) {
197 			if (fs_mkdir(fh->path))
198 				goto error;
199 		} else if (!((mode & EFI_FILE_MODE_CREATE) ||
200 			     fs_exists(fh->path)))
201 			goto error;
202 
203 		/* fs_exists() calls fs_close(), so open file system again */
204 		if (set_blk_dev(fh))
205 			goto error;
206 
207 		/* figure out if file is a directory: */
208 		fh->isdir = is_dir(fh);
209 	} else {
210 		fh->isdir = 1;
211 		strcpy(fh->path, "");
212 	}
213 
214 	return &fh->base;
215 
216 error:
217 	free(fh);
218 	return NULL;
219 }
220 
221 static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file,
222 		struct efi_file_handle **new_handle,
223 		u16 *file_name, u64 open_mode, u64 attributes)
224 {
225 	struct file_handle *fh = to_fh(file);
226 	efi_status_t ret;
227 
228 	EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu", file, new_handle,
229 		  (wchar_t *)file_name, open_mode, attributes);
230 
231 	/* Check parameters */
232 	if (!file || !new_handle || !file_name) {
233 		ret = EFI_INVALID_PARAMETER;
234 		goto out;
235 	}
236 	if (open_mode != EFI_FILE_MODE_READ &&
237 	    open_mode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE) &&
238 	    open_mode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE |
239 			 EFI_FILE_MODE_CREATE)) {
240 		ret = EFI_INVALID_PARAMETER;
241 		goto out;
242 	}
243 	/*
244 	 * The UEFI spec requires that attributes are only set in create mode.
245 	 * The SCT does not care about this and sets EFI_FILE_DIRECTORY in
246 	 * read mode. EDK2 does not check that attributes are zero if not in
247 	 * create mode.
248 	 *
249 	 * So here we only check attributes in create mode and do not check
250 	 * that they are zero otherwise.
251 	 */
252 	if ((open_mode & EFI_FILE_MODE_CREATE) &&
253 	    (attributes & (EFI_FILE_READ_ONLY | ~EFI_FILE_VALID_ATTR))) {
254 		ret = EFI_INVALID_PARAMETER;
255 		goto out;
256 	}
257 
258 	/* Open file */
259 	*new_handle = file_open(fh->fs, fh, file_name, open_mode, attributes);
260 	if (*new_handle)
261 		ret = EFI_SUCCESS;
262 	else
263 		ret = EFI_NOT_FOUND;
264 out:
265 	return EFI_EXIT(ret);
266 }
267 
268 static efi_status_t file_close(struct file_handle *fh)
269 {
270 	fs_closedir(fh->dirs);
271 	free(fh);
272 	return EFI_SUCCESS;
273 }
274 
275 static efi_status_t EFIAPI efi_file_close(struct efi_file_handle *file)
276 {
277 	struct file_handle *fh = to_fh(file);
278 	EFI_ENTRY("%p", file);
279 	return EFI_EXIT(file_close(fh));
280 }
281 
282 static efi_status_t EFIAPI efi_file_delete(struct efi_file_handle *file)
283 {
284 	struct file_handle *fh = to_fh(file);
285 	efi_status_t ret = EFI_SUCCESS;
286 
287 	EFI_ENTRY("%p", file);
288 
289 	if (set_blk_dev(fh)) {
290 		ret = EFI_DEVICE_ERROR;
291 		goto error;
292 	}
293 
294 	if (fs_unlink(fh->path))
295 		ret = EFI_DEVICE_ERROR;
296 	file_close(fh);
297 
298 error:
299 	return EFI_EXIT(ret);
300 }
301 
302 static efi_status_t file_read(struct file_handle *fh, u64 *buffer_size,
303 		void *buffer)
304 {
305 	loff_t actread;
306 
307 	if (fs_read(fh->path, map_to_sysmem(buffer), fh->offset,
308 		    *buffer_size, &actread))
309 		return EFI_DEVICE_ERROR;
310 
311 	*buffer_size = actread;
312 	fh->offset += actread;
313 
314 	return EFI_SUCCESS;
315 }
316 
317 static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size,
318 		void *buffer)
319 {
320 	struct efi_file_info *info = buffer;
321 	struct fs_dirent *dent;
322 	unsigned int required_size;
323 
324 	if (!fh->dirs) {
325 		assert(fh->offset == 0);
326 		fh->dirs = fs_opendir(fh->path);
327 		if (!fh->dirs)
328 			return EFI_DEVICE_ERROR;
329 	}
330 
331 	/*
332 	 * So this is a bit awkward.  Since fs layer is stateful and we
333 	 * can't rewind an entry, in the EFI_BUFFER_TOO_SMALL case below
334 	 * we might have to return without consuming the dent.. so we
335 	 * have to stash it for next call.
336 	 */
337 	if (fh->dent) {
338 		dent = fh->dent;
339 		fh->dent = NULL;
340 	} else {
341 		dent = fs_readdir(fh->dirs);
342 	}
343 
344 
345 	if (!dent) {
346 		/* no more files in directory: */
347 		/* workaround shim.efi bug/quirk.. as find_boot_csv()
348 		 * loops through directory contents, it initially calls
349 		 * read w/ zero length buffer to find out how much mem
350 		 * to allocate for the EFI_FILE_INFO, then allocates,
351 		 * and then calls a 2nd time.  If we return size of
352 		 * zero the first time, it happily passes that to
353 		 * AllocateZeroPool(), and when that returns NULL it
354 		 * thinks it is EFI_OUT_OF_RESOURCES.  So on first
355 		 * call return a non-zero size:
356 		 */
357 		if (*buffer_size == 0)
358 			*buffer_size = sizeof(*info);
359 		else
360 			*buffer_size = 0;
361 		return EFI_SUCCESS;
362 	}
363 
364 	/* check buffer size: */
365 	required_size = sizeof(*info) + 2 * (strlen(dent->name) + 1);
366 	if (*buffer_size < required_size) {
367 		*buffer_size = required_size;
368 		fh->dent = dent;
369 		return EFI_BUFFER_TOO_SMALL;
370 	}
371 
372 	*buffer_size = required_size;
373 	memset(info, 0, required_size);
374 
375 	info->size = required_size;
376 	info->file_size = dent->size;
377 	info->physical_size = dent->size;
378 
379 	if (dent->type == FS_DT_DIR)
380 		info->attribute |= EFI_FILE_DIRECTORY;
381 
382 	ascii2unicode(info->file_name, dent->name);
383 
384 	fh->offset++;
385 
386 	return EFI_SUCCESS;
387 }
388 
389 static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file,
390 					 efi_uintn_t *buffer_size, void *buffer)
391 {
392 	struct file_handle *fh = to_fh(file);
393 	efi_status_t ret = EFI_SUCCESS;
394 	u64 bs;
395 
396 	EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer);
397 
398 	if (!buffer_size || !buffer) {
399 		ret = EFI_INVALID_PARAMETER;
400 		goto error;
401 	}
402 
403 	if (set_blk_dev(fh)) {
404 		ret = EFI_DEVICE_ERROR;
405 		goto error;
406 	}
407 
408 	bs = *buffer_size;
409 	if (fh->isdir)
410 		ret = dir_read(fh, &bs, buffer);
411 	else
412 		ret = file_read(fh, &bs, buffer);
413 	if (bs <= SIZE_MAX)
414 		*buffer_size = bs;
415 	else
416 		*buffer_size = SIZE_MAX;
417 
418 error:
419 	return EFI_EXIT(ret);
420 }
421 
422 static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file,
423 					  efi_uintn_t *buffer_size,
424 					  void *buffer)
425 {
426 	struct file_handle *fh = to_fh(file);
427 	efi_status_t ret = EFI_SUCCESS;
428 	loff_t actwrite;
429 
430 	EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer);
431 
432 	if (set_blk_dev(fh)) {
433 		ret = EFI_DEVICE_ERROR;
434 		goto error;
435 	}
436 
437 	if (fs_write(fh->path, map_to_sysmem(buffer), fh->offset, *buffer_size,
438 		     &actwrite)) {
439 		ret = EFI_DEVICE_ERROR;
440 		goto error;
441 	}
442 
443 	*buffer_size = actwrite;
444 	fh->offset += actwrite;
445 
446 error:
447 	return EFI_EXIT(ret);
448 }
449 
450 /**
451  * efi_file_getpos() - get current position in file
452  *
453  * This function implements the GetPosition service of the EFI file protocol.
454  * See the UEFI spec for details.
455  *
456  * @file:	file handle
457  * @pos:	pointer to file position
458  * Return:	status code
459  */
460 static efi_status_t EFIAPI efi_file_getpos(struct efi_file_handle *file,
461 					   u64 *pos)
462 {
463 	efi_status_t ret = EFI_SUCCESS;
464 	struct file_handle *fh = to_fh(file);
465 
466 	EFI_ENTRY("%p, %p", file, pos);
467 
468 	if (fh->isdir) {
469 		ret = EFI_UNSUPPORTED;
470 		goto out;
471 	}
472 
473 	*pos = fh->offset;
474 out:
475 	return EFI_EXIT(ret);
476 }
477 
478 /**
479  * efi_file_setpos() - set current position in file
480  *
481  * This function implements the SetPosition service of the EFI file protocol.
482  * See the UEFI spec for details.
483  *
484  * @file:	file handle
485  * @pos:	new file position
486  * Return:	status code
487  */
488 static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file,
489 					   u64 pos)
490 {
491 	struct file_handle *fh = to_fh(file);
492 	efi_status_t ret = EFI_SUCCESS;
493 
494 	EFI_ENTRY("%p, %llu", file, pos);
495 
496 	if (fh->isdir) {
497 		if (pos != 0) {
498 			ret = EFI_UNSUPPORTED;
499 			goto error;
500 		}
501 		fs_closedir(fh->dirs);
502 		fh->dirs = NULL;
503 	}
504 
505 	if (pos == ~0ULL) {
506 		loff_t file_size;
507 
508 		if (set_blk_dev(fh)) {
509 			ret = EFI_DEVICE_ERROR;
510 			goto error;
511 		}
512 
513 		if (fs_size(fh->path, &file_size)) {
514 			ret = EFI_DEVICE_ERROR;
515 			goto error;
516 		}
517 
518 		pos = file_size;
519 	}
520 
521 	fh->offset = pos;
522 
523 error:
524 	return EFI_EXIT(ret);
525 }
526 
527 static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file,
528 					    const efi_guid_t *info_type,
529 					    efi_uintn_t *buffer_size,
530 					    void *buffer)
531 {
532 	struct file_handle *fh = to_fh(file);
533 	efi_status_t ret = EFI_SUCCESS;
534 
535 	EFI_ENTRY("%p, %pUl, %p, %p", file, info_type, buffer_size, buffer);
536 
537 	if (!guidcmp(info_type, &efi_file_info_guid)) {
538 		struct efi_file_info *info = buffer;
539 		char *filename = basename(fh);
540 		unsigned int required_size;
541 		loff_t file_size;
542 
543 		/* check buffer size: */
544 		required_size = sizeof(*info) + 2 * (strlen(filename) + 1);
545 		if (*buffer_size < required_size) {
546 			*buffer_size = required_size;
547 			ret = EFI_BUFFER_TOO_SMALL;
548 			goto error;
549 		}
550 
551 		if (set_blk_dev(fh)) {
552 			ret = EFI_DEVICE_ERROR;
553 			goto error;
554 		}
555 
556 		if (fs_size(fh->path, &file_size)) {
557 			ret = EFI_DEVICE_ERROR;
558 			goto error;
559 		}
560 
561 		memset(info, 0, required_size);
562 
563 		info->size = required_size;
564 		info->file_size = file_size;
565 		info->physical_size = file_size;
566 
567 		if (fh->isdir)
568 			info->attribute |= EFI_FILE_DIRECTORY;
569 
570 		ascii2unicode(info->file_name, filename);
571 	} else if (!guidcmp(info_type, &efi_file_system_info_guid)) {
572 		struct efi_file_system_info *info = buffer;
573 		disk_partition_t part;
574 		efi_uintn_t required_size;
575 		int r;
576 
577 		if (fh->fs->part >= 1)
578 			r = part_get_info(fh->fs->desc, fh->fs->part, &part);
579 		else
580 			r = part_get_info_whole_disk(fh->fs->desc, &part);
581 		if (r < 0) {
582 			ret = EFI_DEVICE_ERROR;
583 			goto error;
584 		}
585 		required_size = sizeof(info) + 2 *
586 				(strlen((const char *)part.name) + 1);
587 		if (*buffer_size < required_size) {
588 			*buffer_size = required_size;
589 			ret = EFI_BUFFER_TOO_SMALL;
590 			goto error;
591 		}
592 
593 		memset(info, 0, required_size);
594 
595 		info->size = required_size;
596 		info->read_only = true;
597 		info->volume_size = part.size * part.blksz;
598 		info->free_space = 0;
599 		info->block_size = part.blksz;
600 		/*
601 		 * TODO: The volume label is not available in U-Boot.
602 		 * Use the partition name as substitute.
603 		 */
604 		ascii2unicode((u16 *)info->volume_label,
605 			      (const char *)part.name);
606 	} else {
607 		ret = EFI_UNSUPPORTED;
608 	}
609 
610 error:
611 	return EFI_EXIT(ret);
612 }
613 
614 static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file,
615 					    const efi_guid_t *info_type,
616 					    efi_uintn_t buffer_size,
617 					    void *buffer)
618 {
619 	EFI_ENTRY("%p, %p, %zu, %p", file, info_type, buffer_size, buffer);
620 
621 	return EFI_EXIT(EFI_UNSUPPORTED);
622 }
623 
624 static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *file)
625 {
626 	EFI_ENTRY("%p", file);
627 	return EFI_EXIT(EFI_SUCCESS);
628 }
629 
630 static const struct efi_file_handle efi_file_handle_protocol = {
631 	.rev = EFI_FILE_PROTOCOL_REVISION,
632 	.open = efi_file_open,
633 	.close = efi_file_close,
634 	.delete = efi_file_delete,
635 	.read = efi_file_read,
636 	.write = efi_file_write,
637 	.getpos = efi_file_getpos,
638 	.setpos = efi_file_setpos,
639 	.getinfo = efi_file_getinfo,
640 	.setinfo = efi_file_setinfo,
641 	.flush = efi_file_flush,
642 };
643 
644 /**
645  * efi_file_from_path() - open file via device path
646  *
647  * @fp:		device path
648  * @return:	EFI_FILE_PROTOCOL for the file or NULL
649  */
650 struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp)
651 {
652 	struct efi_simple_file_system_protocol *v;
653 	struct efi_file_handle *f;
654 	efi_status_t ret;
655 
656 	v = efi_fs_from_path(fp);
657 	if (!v)
658 		return NULL;
659 
660 	EFI_CALL(ret = v->open_volume(v, &f));
661 	if (ret != EFI_SUCCESS)
662 		return NULL;
663 
664 	/* Skip over device-path nodes before the file path. */
665 	while (fp && !EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH))
666 		fp = efi_dp_next(fp);
667 
668 	/*
669 	 * Step through the nodes of the directory path until the actual file
670 	 * node is reached which is the final node in the device path.
671 	 */
672 	while (fp) {
673 		struct efi_device_path_file_path *fdp =
674 			container_of(fp, struct efi_device_path_file_path, dp);
675 		struct efi_file_handle *f2;
676 
677 		if (!EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) {
678 			printf("bad file path!\n");
679 			f->close(f);
680 			return NULL;
681 		}
682 
683 		EFI_CALL(ret = f->open(f, &f2, fdp->str,
684 				       EFI_FILE_MODE_READ, 0));
685 		if (ret != EFI_SUCCESS)
686 			return NULL;
687 
688 		fp = efi_dp_next(fp);
689 
690 		EFI_CALL(f->close(f));
691 		f = f2;
692 	}
693 
694 	return f;
695 }
696 
697 static efi_status_t EFIAPI
698 efi_open_volume(struct efi_simple_file_system_protocol *this,
699 		struct efi_file_handle **root)
700 {
701 	struct file_system *fs = to_fs(this);
702 
703 	EFI_ENTRY("%p, %p", this, root);
704 
705 	*root = file_open(fs, NULL, NULL, 0, 0);
706 
707 	return EFI_EXIT(EFI_SUCCESS);
708 }
709 
710 struct efi_simple_file_system_protocol *
711 efi_simple_file_system(struct blk_desc *desc, int part,
712 		       struct efi_device_path *dp)
713 {
714 	struct file_system *fs;
715 
716 	fs = calloc(1, sizeof(*fs));
717 	fs->base.rev = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
718 	fs->base.open_volume = efi_open_volume;
719 	fs->desc = desc;
720 	fs->part = part;
721 	fs->dp = dp;
722 
723 	return &fs->base;
724 }
725