@@ -1239,6 +1239,145 @@ static int bpf_map_get_fd_by_id(const union bpf_attr *attr)
1239
1239
return fd ;
1240
1240
}
1241
1241
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
+
1242
1381
SYSCALL_DEFINE3 (bpf , int , cmd , union bpf_attr __user * , uattr , unsigned int , size )
1243
1382
{
1244
1383
union bpf_attr attr = {};
@@ -1258,23 +1397,10 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz
1258
1397
* user-space does not rely on any kernel feature
1259
1398
* extensions we dont know about yet.
1260
1399
*/
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 ));
1278
1404
1279
1405
/* copy attributes from user space, may be less than sizeof(bpf_attr) */
1280
1406
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
1330
1456
case BPF_MAP_GET_FD_BY_ID :
1331
1457
err = bpf_map_get_fd_by_id (& attr );
1332
1458
break ;
1459
+ case BPF_OBJ_GET_INFO_BY_FD :
1460
+ err = bpf_obj_get_info_by_fd (& attr , uattr );
1461
+ break ;
1333
1462
default :
1334
1463
err = - EINVAL ;
1335
1464
break ;
0 commit comments