Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ba05fd3

Browse files
kkdwivediAlexei Starovoitov
authored andcommitted
libbpf: Perform map fd cleanup for gen_loader in case of error
Alexei reported a fd leak issue in gen loader (when invoked from bpftool) [0]. When adding ksym support, map fd allocation was moved from stack to loader map, however I missed closing these fds (relevant when cleanup label is jumped to on error). For the success case, the allocated fd is returned in loader ctx, hence this problem is not noticed. Make three changes, first MAX_USED_MAPS in MAX_FD_ARRAY_SZ instead of MAX_USED_PROGS, the braino was not a problem until now for this case as we didn't try to close map fds (otherwise use of it would have tried closing 32 additional fds in ksym btf fd range). Then, do a cleanup for all nr_maps fds in cleanup label code, so that in case of error all temporary map fds from bpf_gen__map_create are closed. Then, adjust the cleanup label to only generate code for the required number of program and map fds. To trim code for remaining program fds, lay out prog_fd array in stack in the end, so that we can directly skip the remaining instances. Still stack size remains same, since changing that would require changes in a lot of places (including adjustment of stack_off macro), so nr_progs_sz variable is only used to track required number of iterations (and jump over cleanup size calculated from that), stack offset calculation remains unaffected. The difference for test_ksyms_module.o is as follows: libbpf: //prog cleanup iterations: before = 34, after = 5 libbpf: //maps cleanup iterations: before = 64, after = 2 Also, move allocation of gen->fd_array offset to bpf_gen__init. Since offset can now be 0, and we already continue even if add_data returns 0 in case of failure, we do not need to distinguish between 0 offset and failure case 0, as we rely on bpf_gen__finish to check errors. We can also skip check for gen->fd_array in add_*_fd functions, since bpf_gen__init will take care of it. [0]: https://lore.kernel.org/bpf/CAADnVQJ6jSitKSNKyxOrUzwY2qDRX0sPkJ=VLGHuCLVJ=qOt9g@mail.gmail.com Fixes: 18f4fcc ("libbpf: Update gen_loader to emit BTF_KIND_FUNC relocations") Reported-by: Alexei Starovoitov <[email protected]> Signed-off-by: Kumar Kartikeya Dwivedi <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 2453afe commit ba05fd3

File tree

3 files changed

+34
-21
lines changed

3 files changed

+34
-21
lines changed

tools/lib/bpf/bpf_gen_internal.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ struct bpf_gen {
4545
int nr_fd_array;
4646
};
4747

48-
void bpf_gen__init(struct bpf_gen *gen, int log_level);
49-
int bpf_gen__finish(struct bpf_gen *gen);
48+
void bpf_gen__init(struct bpf_gen *gen, int log_level, int nr_progs, int nr_maps);
49+
int bpf_gen__finish(struct bpf_gen *gen, int nr_progs, int nr_maps);
5050
void bpf_gen__free(struct bpf_gen *gen);
5151
void bpf_gen__load_btf(struct bpf_gen *gen, const void *raw_data, __u32 raw_size);
5252
void bpf_gen__map_create(struct bpf_gen *gen, struct bpf_create_map_params *map_attr, int map_idx);

tools/lib/bpf/gen_loader.c

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
#define MAX_USED_MAPS 64
1919
#define MAX_USED_PROGS 32
2020
#define MAX_KFUNC_DESCS 256
21-
#define MAX_FD_ARRAY_SZ (MAX_USED_PROGS + MAX_KFUNC_DESCS)
21+
#define MAX_FD_ARRAY_SZ (MAX_USED_MAPS + MAX_KFUNC_DESCS)
2222

2323
/* The following structure describes the stack layout of the loader program.
2424
* In addition R6 contains the pointer to context.
@@ -33,15 +33,20 @@
3333
*/
3434
struct loader_stack {
3535
__u32 btf_fd;
36-
__u32 prog_fd[MAX_USED_PROGS];
3736
__u32 inner_map_fd;
37+
__u32 prog_fd[MAX_USED_PROGS];
3838
};
3939

4040
#define stack_off(field) \
4141
(__s16)(-sizeof(struct loader_stack) + offsetof(struct loader_stack, field))
4242

4343
#define attr_field(attr, field) (attr + offsetof(union bpf_attr, field))
4444

45+
static int blob_fd_array_off(struct bpf_gen *gen, int index)
46+
{
47+
return gen->fd_array + index * sizeof(int);
48+
}
49+
4550
static int realloc_insn_buf(struct bpf_gen *gen, __u32 size)
4651
{
4752
size_t off = gen->insn_cur - gen->insn_start;
@@ -102,11 +107,15 @@ static void emit2(struct bpf_gen *gen, struct bpf_insn insn1, struct bpf_insn in
102107
emit(gen, insn2);
103108
}
104109

105-
void bpf_gen__init(struct bpf_gen *gen, int log_level)
110+
static int add_data(struct bpf_gen *gen, const void *data, __u32 size);
111+
static void emit_sys_close_blob(struct bpf_gen *gen, int blob_off);
112+
113+
void bpf_gen__init(struct bpf_gen *gen, int log_level, int nr_progs, int nr_maps)
106114
{
107-
size_t stack_sz = sizeof(struct loader_stack);
115+
size_t stack_sz = sizeof(struct loader_stack), nr_progs_sz;
108116
int i;
109117

118+
gen->fd_array = add_data(gen, NULL, MAX_FD_ARRAY_SZ * sizeof(int));
110119
gen->log_level = log_level;
111120
/* save ctx pointer into R6 */
112121
emit(gen, BPF_MOV64_REG(BPF_REG_6, BPF_REG_1));
@@ -118,19 +127,27 @@ void bpf_gen__init(struct bpf_gen *gen, int log_level)
118127
emit(gen, BPF_MOV64_IMM(BPF_REG_3, 0));
119128
emit(gen, BPF_EMIT_CALL(BPF_FUNC_probe_read_kernel));
120129

130+
/* amount of stack actually used, only used to calculate iterations, not stack offset */
131+
nr_progs_sz = offsetof(struct loader_stack, prog_fd[nr_progs]);
121132
/* jump over cleanup code */
122133
emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0,
123-
/* size of cleanup code below */
124-
(stack_sz / 4) * 3 + 2));
134+
/* size of cleanup code below (including map fd cleanup) */
135+
(nr_progs_sz / 4) * 3 + 2 +
136+
/* 6 insns for emit_sys_close_blob,
137+
* 6 insns for debug_regs in emit_sys_close_blob
138+
*/
139+
nr_maps * (6 + (gen->log_level ? 6 : 0))));
125140

126141
/* remember the label where all error branches will jump to */
127142
gen->cleanup_label = gen->insn_cur - gen->insn_start;
128143
/* emit cleanup code: close all temp FDs */
129-
for (i = 0; i < stack_sz; i += 4) {
144+
for (i = 0; i < nr_progs_sz; i += 4) {
130145
emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_10, -stack_sz + i));
131146
emit(gen, BPF_JMP_IMM(BPF_JSLE, BPF_REG_1, 0, 1));
132147
emit(gen, BPF_EMIT_CALL(BPF_FUNC_sys_close));
133148
}
149+
for (i = 0; i < nr_maps; i++)
150+
emit_sys_close_blob(gen, blob_fd_array_off(gen, i));
134151
/* R7 contains the error code from sys_bpf. Copy it into R0 and exit. */
135152
emit(gen, BPF_MOV64_REG(BPF_REG_0, BPF_REG_7));
136153
emit(gen, BPF_EXIT_INSN());
@@ -160,8 +177,6 @@ static int add_data(struct bpf_gen *gen, const void *data, __u32 size)
160177
*/
161178
static int add_map_fd(struct bpf_gen *gen)
162179
{
163-
if (!gen->fd_array)
164-
gen->fd_array = add_data(gen, NULL, MAX_FD_ARRAY_SZ * sizeof(int));
165180
if (gen->nr_maps == MAX_USED_MAPS) {
166181
pr_warn("Total maps exceeds %d\n", MAX_USED_MAPS);
167182
gen->error = -E2BIG;
@@ -174,20 +189,13 @@ static int add_kfunc_btf_fd(struct bpf_gen *gen)
174189
{
175190
int cur;
176191

177-
if (!gen->fd_array)
178-
gen->fd_array = add_data(gen, NULL, MAX_FD_ARRAY_SZ * sizeof(int));
179192
if (gen->nr_fd_array == MAX_KFUNC_DESCS) {
180193
cur = add_data(gen, NULL, sizeof(int));
181194
return (cur - gen->fd_array) / sizeof(int);
182195
}
183196
return MAX_USED_MAPS + gen->nr_fd_array++;
184197
}
185198

186-
static int blob_fd_array_off(struct bpf_gen *gen, int index)
187-
{
188-
return gen->fd_array + index * sizeof(int);
189-
}
190-
191199
static int insn_bytes_to_bpf_size(__u32 sz)
192200
{
193201
switch (sz) {
@@ -359,10 +367,15 @@ static void emit_sys_close_blob(struct bpf_gen *gen, int blob_off)
359367
__emit_sys_close(gen);
360368
}
361369

362-
int bpf_gen__finish(struct bpf_gen *gen)
370+
int bpf_gen__finish(struct bpf_gen *gen, int nr_progs, int nr_maps)
363371
{
364372
int i;
365373

374+
if (nr_progs != gen->nr_progs || nr_maps != gen->nr_maps) {
375+
pr_warn("progs/maps mismatch\n");
376+
gen->error = -EFAULT;
377+
return gen->error;
378+
}
366379
emit_sys_close_stack(gen, stack_off(btf_fd));
367380
for (i = 0; i < gen->nr_progs; i++)
368381
move_stack2ctx(gen,

tools/lib/bpf/libbpf.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7258,7 +7258,7 @@ int bpf_object__load_xattr(struct bpf_object_load_attr *attr)
72587258
}
72597259

72607260
if (obj->gen_loader)
7261-
bpf_gen__init(obj->gen_loader, attr->log_level);
7261+
bpf_gen__init(obj->gen_loader, attr->log_level, obj->nr_programs, obj->nr_maps);
72627262

72637263
err = bpf_object__probe_loading(obj);
72647264
err = err ? : bpf_object__load_vmlinux_btf(obj, false);
@@ -7277,7 +7277,7 @@ int bpf_object__load_xattr(struct bpf_object_load_attr *attr)
72777277
for (i = 0; i < obj->nr_maps; i++)
72787278
obj->maps[i].fd = -1;
72797279
if (!err)
7280-
err = bpf_gen__finish(obj->gen_loader);
7280+
err = bpf_gen__finish(obj->gen_loader, obj->nr_programs, obj->nr_maps);
72817281
}
72827282

72837283
/* clean up fd_array */

0 commit comments

Comments
 (0)