Skip to content

Commit 1e27097

Browse files
iamkafaidavem330
authored andcommitted
bpf: Add BPF_OBJ_GET_INFO_BY_FD
A single BPF_OBJ_GET_INFO_BY_FD cmd is used to obtain the info for both bpf_prog and bpf_map. The kernel can figure out the fd is associated with a bpf_prog or bpf_map. The suggested struct bpf_prog_info and struct bpf_map_info are not meant to be a complete list and it is not the goal of this patch. New fields can be added in the future patch. The focus of this patch is to create the interface, BPF_OBJ_GET_INFO_BY_FD cmd for exposing the bpf_prog's and bpf_map's info. The obj's info, which will be extended (and get bigger) over time, is separated from the bpf_attr to avoid bloating the bpf_attr. Signed-off-by: Martin KaFai Lau <kafai@fb.com> Acked-by: Alexei Starovoitov <ast@fb.com> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 783d28d commit 1e27097

File tree

3 files changed

+174
-19
lines changed

3 files changed

+174
-19
lines changed

include/linux/filter.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,6 @@ struct bpf_prog_aux;
6969
/* BPF program can access up to 512 bytes of stack space. */
7070
#define MAX_BPF_STACK 512
7171

72-
#define BPF_TAG_SIZE 8
73-
7472
/* Helper macros for filter block array initializers. */
7573

7674
/* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */

include/uapi/linux/bpf.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ enum bpf_cmd {
8686
BPF_MAP_GET_NEXT_ID,
8787
BPF_PROG_GET_FD_BY_ID,
8888
BPF_MAP_GET_FD_BY_ID,
89+
BPF_OBJ_GET_INFO_BY_FD,
8990
};
9091

9192
enum bpf_map_type {
@@ -222,6 +223,12 @@ union bpf_attr {
222223
};
223224
__u32 next_id;
224225
};
226+
227+
struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */
228+
__u32 bpf_fd;
229+
__u32 info_len;
230+
__aligned_u64 info;
231+
} info;
225232
} __attribute__((aligned(8)));
226233

227234
/* BPF helper function descriptions:
@@ -686,4 +693,25 @@ struct xdp_md {
686693
__u32 data_end;
687694
};
688695

696+
#define BPF_TAG_SIZE 8
697+
698+
struct bpf_prog_info {
699+
__u32 type;
700+
__u32 id;
701+
__u8 tag[BPF_TAG_SIZE];
702+
__u32 jited_prog_len;
703+
__u32 xlated_prog_len;
704+
__aligned_u64 jited_prog_insns;
705+
__aligned_u64 xlated_prog_insns;
706+
} __attribute__((aligned(8)));
707+
708+
struct bpf_map_info {
709+
__u32 type;
710+
__u32 id;
711+
__u32 key_size;
712+
__u32 value_size;
713+
__u32 max_entries;
714+
__u32 map_flags;
715+
} __attribute__((aligned(8)));
716+
689717
#endif /* _UAPI__LINUX_BPF_H__ */

kernel/bpf/syscall.c

Lines changed: 146 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,6 +1239,145 @@ static int bpf_map_get_fd_by_id(const union bpf_attr *attr)
12391239
return fd;
12401240
}
12411241

1242+
static int check_uarg_tail_zero(void __user *uaddr,
1243+
size_t expected_size,
1244+
size_t actual_size)
1245+
{
1246+
unsigned char __user *addr;
1247+
unsigned char __user *end;
1248+
unsigned char val;
1249+
int err;
1250+
1251+
if (actual_size <= expected_size)
1252+
return 0;
1253+
1254+
addr = uaddr + expected_size;
1255+
end = uaddr + actual_size;
1256+
1257+
for (; addr < end; addr++) {
1258+
err = get_user(val, addr);
1259+
if (err)
1260+
return err;
1261+
if (val)
1262+
return -E2BIG;
1263+
}
1264+
1265+
return 0;
1266+
}
1267+
1268+
static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
1269+
const union bpf_attr *attr,
1270+
union bpf_attr __user *uattr)
1271+
{
1272+
struct bpf_prog_info __user *uinfo = u64_to_user_ptr(attr->info.info);
1273+
struct bpf_prog_info info = {};
1274+
u32 info_len = attr->info.info_len;
1275+
char __user *uinsns;
1276+
u32 ulen;
1277+
int err;
1278+
1279+
err = check_uarg_tail_zero(uinfo, sizeof(info), info_len);
1280+
if (err)
1281+
return err;
1282+
info_len = min_t(u32, sizeof(info), info_len);
1283+
1284+
if (copy_from_user(&info, uinfo, info_len))
1285+
return err;
1286+
1287+
info.type = prog->type;
1288+
info.id = prog->aux->id;
1289+
1290+
memcpy(info.tag, prog->tag, sizeof(prog->tag));
1291+
1292+
if (!capable(CAP_SYS_ADMIN)) {
1293+
info.jited_prog_len = 0;
1294+
info.xlated_prog_len = 0;
1295+
goto done;
1296+
}
1297+
1298+
ulen = info.jited_prog_len;
1299+
info.jited_prog_len = prog->jited_len;
1300+
if (info.jited_prog_len && ulen) {
1301+
uinsns = u64_to_user_ptr(info.jited_prog_insns);
1302+
ulen = min_t(u32, info.jited_prog_len, ulen);
1303+
if (copy_to_user(uinsns, prog->bpf_func, ulen))
1304+
return -EFAULT;
1305+
}
1306+
1307+
ulen = info.xlated_prog_len;
1308+
info.xlated_prog_len = bpf_prog_size(prog->len);
1309+
if (info.xlated_prog_len && ulen) {
1310+
uinsns = u64_to_user_ptr(info.xlated_prog_insns);
1311+
ulen = min_t(u32, info.xlated_prog_len, ulen);
1312+
if (copy_to_user(uinsns, prog->insnsi, ulen))
1313+
return -EFAULT;
1314+
}
1315+
1316+
done:
1317+
if (copy_to_user(uinfo, &info, info_len) ||
1318+
put_user(info_len, &uattr->info.info_len))
1319+
return -EFAULT;
1320+
1321+
return 0;
1322+
}
1323+
1324+
static int bpf_map_get_info_by_fd(struct bpf_map *map,
1325+
const union bpf_attr *attr,
1326+
union bpf_attr __user *uattr)
1327+
{
1328+
struct bpf_map_info __user *uinfo = u64_to_user_ptr(attr->info.info);
1329+
struct bpf_map_info info = {};
1330+
u32 info_len = attr->info.info_len;
1331+
int err;
1332+
1333+
err = check_uarg_tail_zero(uinfo, sizeof(info), info_len);
1334+
if (err)
1335+
return err;
1336+
info_len = min_t(u32, sizeof(info), info_len);
1337+
1338+
info.type = map->map_type;
1339+
info.id = map->id;
1340+
info.key_size = map->key_size;
1341+
info.value_size = map->value_size;
1342+
info.max_entries = map->max_entries;
1343+
info.map_flags = map->map_flags;
1344+
1345+
if (copy_to_user(uinfo, &info, info_len) ||
1346+
put_user(info_len, &uattr->info.info_len))
1347+
return -EFAULT;
1348+
1349+
return 0;
1350+
}
1351+
1352+
#define BPF_OBJ_GET_INFO_BY_FD_LAST_FIELD info.info
1353+
1354+
static int bpf_obj_get_info_by_fd(const union bpf_attr *attr,
1355+
union bpf_attr __user *uattr)
1356+
{
1357+
int ufd = attr->info.bpf_fd;
1358+
struct fd f;
1359+
int err;
1360+
1361+
if (CHECK_ATTR(BPF_OBJ_GET_INFO_BY_FD))
1362+
return -EINVAL;
1363+
1364+
f = fdget(ufd);
1365+
if (!f.file)
1366+
return -EBADFD;
1367+
1368+
if (f.file->f_op == &bpf_prog_fops)
1369+
err = bpf_prog_get_info_by_fd(f.file->private_data, attr,
1370+
uattr);
1371+
else if (f.file->f_op == &bpf_map_fops)
1372+
err = bpf_map_get_info_by_fd(f.file->private_data, attr,
1373+
uattr);
1374+
else
1375+
err = -EINVAL;
1376+
1377+
fdput(f);
1378+
return err;
1379+
}
1380+
12421381
SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
12431382
{
12441383
union bpf_attr attr = {};
@@ -1258,23 +1397,10 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz
12581397
* user-space does not rely on any kernel feature
12591398
* extensions we dont know about yet.
12601399
*/
1261-
if (size > sizeof(attr)) {
1262-
unsigned char __user *addr;
1263-
unsigned char __user *end;
1264-
unsigned char val;
1265-
1266-
addr = (void __user *)uattr + sizeof(attr);
1267-
end = (void __user *)uattr + size;
1268-
1269-
for (; addr < end; addr++) {
1270-
err = get_user(val, addr);
1271-
if (err)
1272-
return err;
1273-
if (val)
1274-
return -E2BIG;
1275-
}
1276-
size = sizeof(attr);
1277-
}
1400+
err = check_uarg_tail_zero(uattr, sizeof(attr), size);
1401+
if (err)
1402+
return err;
1403+
size = min_t(u32, size, sizeof(attr));
12781404

12791405
/* copy attributes from user space, may be less than sizeof(bpf_attr) */
12801406
if (copy_from_user(&attr, uattr, size) != 0)
@@ -1330,6 +1456,9 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz
13301456
case BPF_MAP_GET_FD_BY_ID:
13311457
err = bpf_map_get_fd_by_id(&attr);
13321458
break;
1459+
case BPF_OBJ_GET_INFO_BY_FD:
1460+
err = bpf_obj_get_info_by_fd(&attr, uattr);
1461+
break;
13331462
default:
13341463
err = -EINVAL;
13351464
break;

0 commit comments

Comments
 (0)