mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	libbpf: Use mmap to parse vmlinux BTF from sysfs
Teach libbpf to use mmap when parsing vmlinux BTF from /sys. We don't apply this to fall-back paths on the regular file system because there is no way to ensure that modifications underlying the MAP_PRIVATE mapping are not visible to the process. Signed-off-by: Lorenz Bauer <lmb@isovalent.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Tested-by: Alan Maguire <alan.maguire@oracle.com> Acked-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/bpf/20250520-vmlinux-mmap-v5-3-e8c941acc414@isovalent.com
This commit is contained in:
		
							parent
							
								
									828226b69f
								
							
						
					
					
						commit
						3c0421c93c
					
				
					 1 changed files with 71 additions and 18 deletions
				
			
		| 
						 | 
					@ -12,6 +12,7 @@
 | 
				
			||||||
#include <sys/utsname.h>
 | 
					#include <sys/utsname.h>
 | 
				
			||||||
#include <sys/param.h>
 | 
					#include <sys/param.h>
 | 
				
			||||||
#include <sys/stat.h>
 | 
					#include <sys/stat.h>
 | 
				
			||||||
 | 
					#include <sys/mman.h>
 | 
				
			||||||
#include <linux/kernel.h>
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
#include <linux/err.h>
 | 
					#include <linux/err.h>
 | 
				
			||||||
#include <linux/btf.h>
 | 
					#include <linux/btf.h>
 | 
				
			||||||
| 
						 | 
					@ -120,6 +121,9 @@ struct btf {
 | 
				
			||||||
	/* whether base_btf should be freed in btf_free for this instance */
 | 
						/* whether base_btf should be freed in btf_free for this instance */
 | 
				
			||||||
	bool owns_base;
 | 
						bool owns_base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* whether raw_data is a (read-only) mmap */
 | 
				
			||||||
 | 
						bool raw_data_is_mmap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* BTF object FD, if loaded into kernel */
 | 
						/* BTF object FD, if loaded into kernel */
 | 
				
			||||||
	int fd;
 | 
						int fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -951,6 +955,17 @@ static bool btf_is_modifiable(const struct btf *btf)
 | 
				
			||||||
	return (void *)btf->hdr != btf->raw_data;
 | 
						return (void *)btf->hdr != btf->raw_data;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void btf_free_raw_data(struct btf *btf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (btf->raw_data_is_mmap) {
 | 
				
			||||||
 | 
							munmap(btf->raw_data, btf->raw_size);
 | 
				
			||||||
 | 
							btf->raw_data_is_mmap = false;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							free(btf->raw_data);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						btf->raw_data = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void btf__free(struct btf *btf)
 | 
					void btf__free(struct btf *btf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (IS_ERR_OR_NULL(btf))
 | 
						if (IS_ERR_OR_NULL(btf))
 | 
				
			||||||
| 
						 | 
					@ -970,7 +985,7 @@ void btf__free(struct btf *btf)
 | 
				
			||||||
		free(btf->types_data);
 | 
							free(btf->types_data);
 | 
				
			||||||
		strset__free(btf->strs_set);
 | 
							strset__free(btf->strs_set);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	free(btf->raw_data);
 | 
						btf_free_raw_data(btf);
 | 
				
			||||||
	free(btf->raw_data_swapped);
 | 
						free(btf->raw_data_swapped);
 | 
				
			||||||
	free(btf->type_offs);
 | 
						free(btf->type_offs);
 | 
				
			||||||
	if (btf->owns_base)
 | 
						if (btf->owns_base)
 | 
				
			||||||
| 
						 | 
					@ -1030,7 +1045,7 @@ struct btf *btf__new_empty_split(struct btf *base_btf)
 | 
				
			||||||
	return libbpf_ptr(btf_new_empty(base_btf));
 | 
						return libbpf_ptr(btf_new_empty(base_btf));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf)
 | 
					static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf, bool is_mmap)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct btf *btf;
 | 
						struct btf *btf;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
| 
						 | 
					@ -1050,12 +1065,18 @@ static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf)
 | 
				
			||||||
		btf->start_str_off = base_btf->hdr->str_len;
 | 
							btf->start_str_off = base_btf->hdr->str_len;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (is_mmap) {
 | 
				
			||||||
 | 
							btf->raw_data = (void *)data;
 | 
				
			||||||
 | 
							btf->raw_data_is_mmap = true;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
		btf->raw_data = malloc(size);
 | 
							btf->raw_data = malloc(size);
 | 
				
			||||||
		if (!btf->raw_data) {
 | 
							if (!btf->raw_data) {
 | 
				
			||||||
			err = -ENOMEM;
 | 
								err = -ENOMEM;
 | 
				
			||||||
			goto done;
 | 
								goto done;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		memcpy(btf->raw_data, data, size);
 | 
							memcpy(btf->raw_data, data, size);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	btf->raw_size = size;
 | 
						btf->raw_size = size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	btf->hdr = btf->raw_data;
 | 
						btf->hdr = btf->raw_data;
 | 
				
			||||||
| 
						 | 
					@ -1083,12 +1104,12 @@ static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct btf *btf__new(const void *data, __u32 size)
 | 
					struct btf *btf__new(const void *data, __u32 size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return libbpf_ptr(btf_new(data, size, NULL));
 | 
						return libbpf_ptr(btf_new(data, size, NULL, false));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct btf *btf__new_split(const void *data, __u32 size, struct btf *base_btf)
 | 
					struct btf *btf__new_split(const void *data, __u32 size, struct btf *base_btf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return libbpf_ptr(btf_new(data, size, base_btf));
 | 
						return libbpf_ptr(btf_new(data, size, base_btf, false));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct btf_elf_secs {
 | 
					struct btf_elf_secs {
 | 
				
			||||||
| 
						 | 
					@ -1209,7 +1230,7 @@ static struct btf *btf_parse_elf(const char *path, struct btf *base_btf,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (secs.btf_base_data) {
 | 
						if (secs.btf_base_data) {
 | 
				
			||||||
		dist_base_btf = btf_new(secs.btf_base_data->d_buf, secs.btf_base_data->d_size,
 | 
							dist_base_btf = btf_new(secs.btf_base_data->d_buf, secs.btf_base_data->d_size,
 | 
				
			||||||
					NULL);
 | 
										NULL, false);
 | 
				
			||||||
		if (IS_ERR(dist_base_btf)) {
 | 
							if (IS_ERR(dist_base_btf)) {
 | 
				
			||||||
			err = PTR_ERR(dist_base_btf);
 | 
								err = PTR_ERR(dist_base_btf);
 | 
				
			||||||
			dist_base_btf = NULL;
 | 
								dist_base_btf = NULL;
 | 
				
			||||||
| 
						 | 
					@ -1218,7 +1239,7 @@ static struct btf *btf_parse_elf(const char *path, struct btf *base_btf,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	btf = btf_new(secs.btf_data->d_buf, secs.btf_data->d_size,
 | 
						btf = btf_new(secs.btf_data->d_buf, secs.btf_data->d_size,
 | 
				
			||||||
		      dist_base_btf ?: base_btf);
 | 
							      dist_base_btf ?: base_btf, false);
 | 
				
			||||||
	if (IS_ERR(btf)) {
 | 
						if (IS_ERR(btf)) {
 | 
				
			||||||
		err = PTR_ERR(btf);
 | 
							err = PTR_ERR(btf);
 | 
				
			||||||
		goto done;
 | 
							goto done;
 | 
				
			||||||
| 
						 | 
					@ -1335,7 +1356,7 @@ static struct btf *btf_parse_raw(const char *path, struct btf *base_btf)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* finally parse BTF data */
 | 
						/* finally parse BTF data */
 | 
				
			||||||
	btf = btf_new(data, sz, base_btf);
 | 
						btf = btf_new(data, sz, base_btf, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
err_out:
 | 
					err_out:
 | 
				
			||||||
	free(data);
 | 
						free(data);
 | 
				
			||||||
| 
						 | 
					@ -1354,6 +1375,37 @@ struct btf *btf__parse_raw_split(const char *path, struct btf *base_btf)
 | 
				
			||||||
	return libbpf_ptr(btf_parse_raw(path, base_btf));
 | 
						return libbpf_ptr(btf_parse_raw(path, base_btf));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct btf *btf_parse_raw_mmap(const char *path, struct btf *base_btf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct stat st;
 | 
				
			||||||
 | 
						void *data;
 | 
				
			||||||
 | 
						struct btf *btf;
 | 
				
			||||||
 | 
						int fd, err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fd = open(path, O_RDONLY);
 | 
				
			||||||
 | 
						if (fd < 0)
 | 
				
			||||||
 | 
							return libbpf_err_ptr(-errno);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (fstat(fd, &st) < 0) {
 | 
				
			||||||
 | 
							err = -errno;
 | 
				
			||||||
 | 
							close(fd);
 | 
				
			||||||
 | 
							return libbpf_err_ptr(err);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
 | 
				
			||||||
 | 
						err = -errno;
 | 
				
			||||||
 | 
						close(fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (data == MAP_FAILED)
 | 
				
			||||||
 | 
							return libbpf_err_ptr(err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						btf = btf_new(data, st.st_size, base_btf, true);
 | 
				
			||||||
 | 
						if (IS_ERR(btf))
 | 
				
			||||||
 | 
							munmap(data, st.st_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return btf;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct btf *btf_parse(const char *path, struct btf *base_btf, struct btf_ext **btf_ext)
 | 
					static struct btf *btf_parse(const char *path, struct btf *base_btf, struct btf_ext **btf_ext)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct btf *btf;
 | 
						struct btf *btf;
 | 
				
			||||||
| 
						 | 
					@ -1618,7 +1670,7 @@ struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf)
 | 
				
			||||||
		goto exit_free;
 | 
							goto exit_free;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	btf = btf_new(ptr, btf_info.btf_size, base_btf);
 | 
						btf = btf_new(ptr, btf_info.btf_size, base_btf, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
exit_free:
 | 
					exit_free:
 | 
				
			||||||
	free(ptr);
 | 
						free(ptr);
 | 
				
			||||||
| 
						 | 
					@ -1658,10 +1710,8 @@ struct btf *btf__load_from_kernel_by_id(__u32 id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void btf_invalidate_raw_data(struct btf *btf)
 | 
					static void btf_invalidate_raw_data(struct btf *btf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (btf->raw_data) {
 | 
						if (btf->raw_data)
 | 
				
			||||||
		free(btf->raw_data);
 | 
							btf_free_raw_data(btf);
 | 
				
			||||||
		btf->raw_data = NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (btf->raw_data_swapped) {
 | 
						if (btf->raw_data_swapped) {
 | 
				
			||||||
		free(btf->raw_data_swapped);
 | 
							free(btf->raw_data_swapped);
 | 
				
			||||||
		btf->raw_data_swapped = NULL;
 | 
							btf->raw_data_swapped = NULL;
 | 
				
			||||||
| 
						 | 
					@ -5331,7 +5381,10 @@ struct btf *btf__load_vmlinux_btf(void)
 | 
				
			||||||
		pr_warn("kernel BTF is missing at '%s', was CONFIG_DEBUG_INFO_BTF enabled?\n",
 | 
							pr_warn("kernel BTF is missing at '%s', was CONFIG_DEBUG_INFO_BTF enabled?\n",
 | 
				
			||||||
			sysfs_btf_path);
 | 
								sysfs_btf_path);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
 | 
							btf = btf_parse_raw_mmap(sysfs_btf_path, NULL);
 | 
				
			||||||
 | 
							if (IS_ERR(btf))
 | 
				
			||||||
			btf = btf__parse(sysfs_btf_path, NULL);
 | 
								btf = btf__parse(sysfs_btf_path, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!btf) {
 | 
							if (!btf) {
 | 
				
			||||||
			err = -errno;
 | 
								err = -errno;
 | 
				
			||||||
			pr_warn("failed to read kernel BTF from '%s': %s\n",
 | 
								pr_warn("failed to read kernel BTF from '%s': %s\n",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue