| @@ -1447,6 +1447,277 @@ int __weak arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags, · 1446 unmodified lines |
| 1447 | 1447 | return -ENOTSUPP; |
| 1448 | 1448 | } |
| 1449 | 1449 | |
| 1450 | +#if defined(CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS) && \ |
| 1451 | + defined(CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS) && \ |
| 1452 | + defined(CONFIG_BPF_SYSCALL) |
| 1453 | + |
| 1454 | +static void trampoline_lock_all(void) |
| 1455 | +{ |
| 1456 | + int i; |
| 1457 | + |
| 1458 | + for (i = 0; i < TRAMPOLINE_LOCKS_TABLE_SIZE; i++) |
| 1459 | + mutex_lock(&trampoline_locks[i].mutex); |
| 1460 | +} |
| 1461 | + |
| 1462 | +static void trampoline_unlock_all(void) |
| 1463 | +{ |
| 1464 | + int i; |
| 1465 | + |
| 1466 | + for (i = 0; i < TRAMPOLINE_LOCKS_TABLE_SIZE; i++) |
| 1467 | + mutex_unlock(&trampoline_locks[i].mutex); |
| 1468 | +} |
| 1469 | + |
| 1470 | +static void remove_tracing_multi_data(struct bpf_tracing_multi_data *data) |
| 1471 | +{ |
| 1472 | + ftrace_hash_remove(data->reg); |
| 1473 | + ftrace_hash_remove(data->unreg); |
| 1474 | + ftrace_hash_remove(data->modify); |
| 1475 | +} |
| 1476 | + |
| 1477 | +static void clear_tracing_multi_data(struct bpf_tracing_multi_data *data) |
| 1478 | +{ |
| 1479 | + remove_tracing_multi_data(data); |
| 1480 | + |
| 1481 | + free_ftrace_hash(data->reg); |
| 1482 | + free_ftrace_hash(data->unreg); |
| 1483 | + free_ftrace_hash(data->modify); |
| 1484 | +} |
| 1485 | + |
| 1486 | +static int init_tracing_multi_data(struct bpf_tracing_multi_data *data) |
| 1487 | +{ |
| 1488 | + data->reg = alloc_ftrace_hash(FTRACE_HASH_DEFAULT_BITS); |
| 1489 | + data->unreg = alloc_ftrace_hash(FTRACE_HASH_DEFAULT_BITS); |
| 1490 | + data->modify = alloc_ftrace_hash(FTRACE_HASH_DEFAULT_BITS); |
| 1491 | + |
| 1492 | + if (!data->reg || !data->unreg || !data->modify) { |
| 1493 | + clear_tracing_multi_data(data); |
| 1494 | + return -ENOMEM; |
| 1495 | + } |
| 1496 | + return 0; |
| 1497 | +} |
| 1498 | + |
| 1499 | +static void ftrace_hash_add(struct ftrace_hash *hash, struct ftrace_func_entry *entry, |
| 1500 | + unsigned long ip, unsigned long direct) |
| 1501 | +{ |
| 1502 | + entry->ip = ip; |
| 1503 | + entry->direct = direct; |
| 1504 | + add_ftrace_hash_entry(hash, entry); |
| 1505 | +} |
| 1506 | + |
| 1507 | +static int register_fentry_multi(struct bpf_trampoline *tr, struct bpf_tramp_image *im, void *ptr) |
| 1508 | +{ |
| 1509 | + unsigned long addr = (unsigned long) im->image; |
| 1510 | + unsigned long ip = ftrace_location(tr->ip); |
| 1511 | + struct bpf_tracing_multi_data *data = ptr; |
| 1512 | + |
| 1513 | + if (bpf_trampoline_use_jmp(tr->flags)) |
| 1514 | + addr = ftrace_jmp_set(addr); |
| 1515 | + |
| 1516 | + ftrace_hash_add(data->reg, data->entry, ip, addr); |
| 1517 | + tr->cur_image = im; |
| 1518 | + return 0; |
| 1519 | +} |
| 1520 | + |
| 1521 | +static int unregister_fentry_multi(struct bpf_trampoline *tr, u32 orig_flags, void *ptr) |
| 1522 | +{ |
| 1523 | + unsigned long addr = (unsigned long) tr->cur_image->image; |
| 1524 | + unsigned long ip = ftrace_location(tr->ip); |
| 1525 | + struct bpf_tracing_multi_data *data = ptr; |
| 1526 | + |
| 1527 | + if (bpf_trampoline_use_jmp(tr->flags)) |
| 1528 | + addr = ftrace_jmp_set(addr); |
| 1529 | + |
| 1530 | + ftrace_hash_add(data->unreg, data->entry, ip, addr); |
| 1531 | + tr->cur_image = NULL; |
| 1532 | + return 0; |
| 1533 | +} |
| 1534 | + |
| 1535 | +static int modify_fentry_multi(struct bpf_trampoline *tr, u32 orig_flags, struct bpf_tramp_image *im, |
| 1536 | + bool lock_direct_mutex, void *ptr) |
| 1537 | +{ |
| 1538 | + unsigned long addr = (unsigned long) im->image; |
| 1539 | + unsigned long ip = ftrace_location(tr->ip); |
| 1540 | + struct bpf_tracing_multi_data *data = ptr; |
| 1541 | + |
| 1542 | + if (bpf_trampoline_use_jmp(tr->flags)) |
| 1543 | + addr = ftrace_jmp_set(addr); |
| 1544 | + |
| 1545 | + ftrace_hash_add(data->modify, data->entry, ip, addr); |
| 1546 | + tr->cur_image = im; |
| 1547 | + return 0; |
| 1548 | +} |
| 1549 | + |
| 1550 | +static const struct bpf_trampoline_ops trampoline_multi_ops = { |
| 1551 | + .register_fentry = register_fentry_multi, |
| 1552 | + .unregister_fentry = unregister_fentry_multi, |
| 1553 | + .modify_fentry = modify_fentry_multi, |
| 1554 | +}; |
| 1555 | + |
| 1556 | +static void bpf_trampoline_multi_attach_init(struct bpf_trampoline *tr) |
| 1557 | +{ |
| 1558 | + tr->multi_attach.old_image = tr->cur_image; |
| 1559 | + tr->multi_attach.old_flags = tr->flags; |
| 1560 | +} |
| 1561 | + |
| 1562 | +static void bpf_trampoline_multi_attach_free(struct bpf_trampoline *tr) |
| 1563 | +{ |
| 1564 | + if (tr->multi_attach.old_image) |
| 1565 | + bpf_tramp_image_put(tr->multi_attach.old_image); |
| 1566 | + |
| 1567 | + tr->multi_attach.old_image = NULL; |
| 1568 | + tr->multi_attach.old_flags = 0; |
| 1569 | +} |
| 1570 | + |
| 1571 | +static void bpf_trampoline_multi_attach_rollback(struct bpf_trampoline *tr) |
| 1572 | +{ |
| 1573 | + if (tr->cur_image) |
| 1574 | + bpf_tramp_image_put(tr->cur_image); |
| 1575 | + tr->cur_image = tr->multi_attach.old_image; |
| 1576 | + tr->flags = tr->multi_attach.old_flags; |
| 1577 | + |
| 1578 | + tr->multi_attach.old_image = NULL; |
| 1579 | + tr->multi_attach.old_flags = 0; |
| 1580 | +} |
| 1581 | + |
| 1582 | +#define for_each_mnode_cnt(mnode, link, cnt) \ |
| 1583 | + for (i = 0, mnode = &link->nodes[i]; i < cnt; i++, mnode = &link->nodes[i]) |
| 1584 | + |
| 1585 | +#define for_each_mnode(mnode, link) \ |
| 1586 | + for_each_mnode_cnt(mnode, link, link->nodes_cnt) |
| 1587 | + |
| 1588 | +int bpf_trampoline_multi_attach(struct bpf_prog *prog, u32 *ids, |
| 1589 | + struct bpf_tracing_multi_link *link) |
| 1590 | +{ |
| 1591 | + struct bpf_tracing_multi_data *data = &link->data; |
| 1592 | + struct bpf_attach_target_info tgt_info = {}; |
| 1593 | + struct btf *btf = prog->aux->attach_btf; |
| 1594 | + struct bpf_tracing_multi_node *mnode; |
| 1595 | + struct bpf_trampoline *tr; |
| 1596 | + int i, err, rollback_cnt; |
| 1597 | + u64 key; |
| 1598 | + |
| 1599 | + for_each_mnode(mnode, link) { |
| 1600 | + rollback_cnt = i; |
| 1601 | + |
| 1602 | + err = bpf_check_attach_btf_id_multi(btf, prog, ids[i], &tgt_info); |
| 1603 | + if (err) |
| 1604 | + goto rollback_put; |
| 1605 | + |
| 1606 | + key = bpf_trampoline_compute_key(NULL, btf, ids[i]); |
| 1607 | + |
| 1608 | + tr = bpf_trampoline_get(key, &tgt_info); |
| 1609 | + if (!tr) { |
| 1610 | + err = -ENOMEM; |
| 1611 | + goto rollback_put; |
| 1612 | + } |
| 1613 | + |
| 1614 | + mnode->trampoline = tr; |
| 1615 | + mnode->node.link = &link->link; |
| 1616 | + |
| 1617 | + cond_resched(); |
| 1618 | + } |
| 1619 | + |
| 1620 | + err = init_tracing_multi_data(data); |
| 1621 | + if (err) { |
| 1622 | + rollback_cnt = link->nodes_cnt; |
| 1623 | + goto rollback_put; |
| 1624 | + } |
| 1625 | + |
| 1626 | + trampoline_lock_all(); |
| 1627 | + |
| 1628 | + for_each_mnode(mnode, link) { |
| 1629 | + bpf_trampoline_multi_attach_init(mnode->trampoline); |
| 1630 | + |
| 1631 | + data->entry = &mnode->entry; |
| 1632 | + err = __bpf_trampoline_link_prog(&mnode->node, mnode->trampoline, NULL, |
| 1633 | + &trampoline_multi_ops, data); |
| 1634 | + if (err) { |
| 1635 | + rollback_cnt = i; |
| 1636 | + goto rollback_unlink; |
| 1637 | + } |
| 1638 | + } |
| 1639 | + |
| 1640 | + rollback_cnt = link->nodes_cnt; |
| 1641 | + if (ftrace_hash_count(data->reg)) { |
| 1642 | + err = update_ftrace_direct_add(&direct_ops, data->reg); |
| 1643 | + if (err) |
| 1644 | + goto rollback_unlink; |
| 1645 | + } |
| 1646 | + |
| 1647 | + if (ftrace_hash_count(data->modify)) { |
| 1648 | + err = update_ftrace_direct_mod(&direct_ops, data->modify, true); |
| 1649 | + if (err) { |
| 1650 | + if (ftrace_hash_count(data->reg)) |
| 1651 | + WARN_ON_ONCE(update_ftrace_direct_del(&direct_ops, data->reg)); |
| 1652 | + goto rollback_unlink; |
| 1653 | + } |
| 1654 | + } |
| 1655 | + |
| 1656 | + for_each_mnode(mnode, link) |
| 1657 | + bpf_trampoline_multi_attach_free(mnode->trampoline); |
| 1658 | + |
| 1659 | + trampoline_unlock_all(); |
| 1660 | + |
| 1661 | + remove_tracing_multi_data(data); |
| 1662 | + return 0; |
| 1663 | + |
| 1664 | +rollback_unlink: |
| 1665 | + for_each_mnode_cnt(mnode, link, rollback_cnt) { |
| 1666 | + bpf_trampoline_remove_prog(mnode->trampoline, &mnode->node); |
| 1667 | + bpf_trampoline_multi_attach_rollback(mnode->trampoline); |
| 1668 | + } |
| 1669 | + |
| 1670 | + trampoline_unlock_all(); |
| 1671 | + |
| 1672 | + clear_tracing_multi_data(data); |
| 1673 | + rollback_cnt = link->nodes_cnt; |
| 1674 | + |
| 1675 | +rollback_put: |
| 1676 | + for_each_mnode_cnt(mnode, link, rollback_cnt) |
| 1677 | + bpf_trampoline_put(mnode->trampoline); |
| 1678 | + |
| 1679 | + return err; |
| 1680 | +} |
| 1681 | + |
| 1682 | +int bpf_trampoline_multi_detach(struct bpf_prog *prog, struct bpf_tracing_multi_link *link) |
| 1683 | +{ |
| 1684 | + struct bpf_tracing_multi_data *data = &link->data; |
| 1685 | + struct bpf_tracing_multi_node *mnode; |
| 1686 | + int i; |
| 1687 | + |
| 1688 | + trampoline_lock_all(); |
| 1689 | + |
| 1690 | + for_each_mnode(mnode, link) { |
| 1691 | + data->entry = &mnode->entry; |
| 1692 | + bpf_trampoline_multi_attach_init(mnode->trampoline); |
| 1693 | + WARN_ON_ONCE(__bpf_trampoline_unlink_prog(&mnode->node, mnode->trampoline, |
| 1694 | + NULL, &trampoline_multi_ops, data)); |
| 1695 | + } |
| 1696 | + |
| 1697 | + if (ftrace_hash_count(data->unreg)) |
| 1698 | + WARN_ON_ONCE(update_ftrace_direct_del(&direct_ops, data->unreg)); |
| 1699 | + if (ftrace_hash_count(data->modify)) |
| 1700 | + WARN_ON_ONCE(update_ftrace_direct_mod(&direct_ops, data->modify, true)); |
| 1701 | + |
| 1702 | + for_each_mnode(mnode, link) |
| 1703 | + bpf_trampoline_multi_attach_free(mnode->trampoline); |
| 1704 | + |
| 1705 | + trampoline_unlock_all(); |
| 1706 | + |
| 1707 | + for_each_mnode(mnode, link) |
| 1708 | + bpf_trampoline_put(mnode->trampoline); |
| 1709 | + |
| 1710 | + clear_tracing_multi_data(data); |
| 1711 | + return 0; |
| 1712 | +} |
| 1713 | + |
| 1714 | +#undef for_each_mnode_cnt |
| 1715 | +#undef for_each_mnode |
| 1716 | + |
| 1717 | +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS && |
| 1718 | + CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS && |
| 1719 | + CONFIG_BPF_SYSCALL */ |
| 1720 | + |
| 1450 | 1721 | static int __init init_trampolines(void) |
| 1451 | 1722 | { |
| 1452 | 1723 | int i; |