File: libkmod-file-zlib.c

package info (click to toggle)
kmod 34.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,864 kB
  • sloc: ansic: 16,990; makefile: 498; sh: 382; xml: 61; perl: 12
file content (112 lines) | stat: -rw-r--r-- 2,083 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
 * Copyright © 2024 Intel Corporation
 */

#define DLSYM_LOCALLY_ENABLED ENABLE_ZLIB_DLOPEN

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <zlib.h>

#include <shared/elf-note.h>
#include <shared/util.h>

#include "libkmod.h"
#include "libkmod-internal.h"
#include "libkmod-internal-file.h"

#define READ_STEP (4 * 1024 * 1024)

#define DL_SYMBOL_TABLE(M) \
	M(gzclose)         \
	M(gzdopen)         \
	M(gzerror)         \
	M(gzread)

DL_SYMBOL_TABLE(DECLARE_SYM)

static int dlopen_zlib(void)
{
#if !DLSYM_LOCALLY_ENABLED
	return 0;
#else
	static void *dl = NULL;

	ELF_NOTE_DLOPEN("zlib", "Support for uncompressing zlib-compressed modules",
			ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED, "libz.so.1");

	return dlsym_many(&dl, "libz.so.1", DL_SYMBOL_TABLE(DLSYM_ARG) NULL);
#endif
}

int kmod_file_load_zlib(struct kmod_file *file)
{
	_cleanup_free_ unsigned char *p = NULL;
	int ret = 0;
	off_t did = 0, total = 0;
	gzFile gzf;
	int gzfd;

	ret = dlopen_zlib();
	if (ret < 0) {
		ERR(file->ctx, "zlib: can't load and resolve symbols (%s)",
		    strerror(-ret));
		return -EINVAL;
	}

	errno = 0;
	gzfd = fcntl(file->fd, F_DUPFD_CLOEXEC, 3);
	if (gzfd < 0)
		return -errno;

	gzf = sym_gzdopen(gzfd, "rb"); /* takes ownership of the fd */
	if (gzf == NULL) {
		close(gzfd);
		return -errno;
	}

	for (;;) {
		int r;

		if (did == total) {
			void *tmp = realloc(p, total + READ_STEP);
			if (tmp == NULL) {
				ret = -errno;
				goto error;
			}
			total += READ_STEP;
			p = tmp;
		}

		r = sym_gzread(gzf, p + did, total - did);
		if (r == 0)
			break;
		else if (r < 0) {
			int gzerr;
			const char *gz_errmsg = sym_gzerror(gzf, &gzerr);

			ERR(file->ctx, "gzip: %s\n", gz_errmsg);

			/* gzip might not set errno here */
			ret = gzerr == Z_ERRNO ? -errno : -EINVAL;
			goto error;
		}
		did += r;
	}

	file->memory = TAKE_PTR(p);
	file->size = did;
	sym_gzclose(gzf);

	return 0;

error:
	sym_gzclose(gzf);
	return ret;
}