mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-18 02:46:06 +00:00
net: netfilter: Add kfuncs to set and change CT status
Introduce bpf_ct_set_status and bpf_ct_change_status kfunc helpers in order to set nf_conn field of allocated entry or update nf_conn status field of existing inserted entry. Use nf_ct_change_status_common to share the permitted status field changes between netlink and BPF side by refactoring ctnetlink_change_status. It is required to introduce two kfuncs taking nf_conn___init and nf_conn instead of sharing one because KF_TRUSTED_ARGS flag causes strict type checking. This would disallow passing nf_conn___init to kfunc taking nf_conn, and vice versa. We cannot remove the KF_TRUSTED_ARGS flag as we only want to accept refcounted pointers and not e.g. ct->master. Hence, bpf_ct_set_* kfuncs are meant to be used on allocated CT, and bpf_ct_change_* kfuncs are meant to be used on inserted or looked up CT entry. Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org> Co-developed-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Link: https://lore.kernel.org/r/20220721134245.2450-10-memxor@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
parent
0b38923644
commit
ef69aa3a98
@ -98,6 +98,8 @@ static inline void __nf_ct_set_timeout(struct nf_conn *ct, u64 timeout)
|
||||
}
|
||||
|
||||
int __nf_ct_change_timeout(struct nf_conn *ct, u64 cta_timeout);
|
||||
void __nf_ct_change_status(struct nf_conn *ct, unsigned long on, unsigned long off);
|
||||
int nf_ct_change_status_common(struct nf_conn *ct, unsigned int status);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -394,6 +394,36 @@ int bpf_ct_change_timeout(struct nf_conn *nfct, u32 timeout)
|
||||
return __nf_ct_change_timeout(nfct, msecs_to_jiffies(timeout));
|
||||
}
|
||||
|
||||
/* bpf_ct_set_status - Set status field of allocated nf_conn
|
||||
*
|
||||
* Set the status field of the newly allocated nf_conn before insertion.
|
||||
* This must be invoked for referenced PTR_TO_BTF_ID to nf_conn___init.
|
||||
*
|
||||
* Parameters:
|
||||
* @nfct - Pointer to referenced nf_conn object, obtained using
|
||||
* bpf_xdp_ct_alloc or bpf_skb_ct_alloc.
|
||||
* @status - New status value.
|
||||
*/
|
||||
int bpf_ct_set_status(const struct nf_conn___init *nfct, u32 status)
|
||||
{
|
||||
return nf_ct_change_status_common((struct nf_conn *)nfct, status);
|
||||
}
|
||||
|
||||
/* bpf_ct_change_status - Change status of inserted nf_conn
|
||||
*
|
||||
* Change the status field of the provided connection tracking entry.
|
||||
* This must be invoked for referenced PTR_TO_BTF_ID to nf_conn.
|
||||
*
|
||||
* Parameters:
|
||||
* @nfct - Pointer to referenced nf_conn object, obtained using
|
||||
* bpf_ct_insert_entry, bpf_xdp_ct_lookup or bpf_skb_ct_lookup.
|
||||
* @status - New status value.
|
||||
*/
|
||||
int bpf_ct_change_status(struct nf_conn *nfct, u32 status)
|
||||
{
|
||||
return nf_ct_change_status_common(nfct, status);
|
||||
}
|
||||
|
||||
__diag_pop()
|
||||
|
||||
BTF_SET8_START(nf_ct_kfunc_set)
|
||||
@ -405,6 +435,8 @@ BTF_ID_FLAGS(func, bpf_ct_insert_entry, KF_ACQUIRE | KF_RET_NULL | KF_RELEASE)
|
||||
BTF_ID_FLAGS(func, bpf_ct_release, KF_RELEASE)
|
||||
BTF_ID_FLAGS(func, bpf_ct_set_timeout, KF_TRUSTED_ARGS)
|
||||
BTF_ID_FLAGS(func, bpf_ct_change_timeout, KF_TRUSTED_ARGS)
|
||||
BTF_ID_FLAGS(func, bpf_ct_set_status, KF_TRUSTED_ARGS)
|
||||
BTF_ID_FLAGS(func, bpf_ct_change_status, KF_TRUSTED_ARGS)
|
||||
BTF_SET8_END(nf_ct_kfunc_set)
|
||||
|
||||
static const struct btf_kfunc_id_set nf_conntrack_kfunc_set = {
|
||||
|
@ -2807,4 +2807,44 @@ int __nf_ct_change_timeout(struct nf_conn *ct, u64 timeout)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__nf_ct_change_timeout);
|
||||
|
||||
void __nf_ct_change_status(struct nf_conn *ct, unsigned long on, unsigned long off)
|
||||
{
|
||||
unsigned int bit;
|
||||
|
||||
/* Ignore these unchangable bits */
|
||||
on &= ~IPS_UNCHANGEABLE_MASK;
|
||||
off &= ~IPS_UNCHANGEABLE_MASK;
|
||||
|
||||
for (bit = 0; bit < __IPS_MAX_BIT; bit++) {
|
||||
if (on & (1 << bit))
|
||||
set_bit(bit, &ct->status);
|
||||
else if (off & (1 << bit))
|
||||
clear_bit(bit, &ct->status);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__nf_ct_change_status);
|
||||
|
||||
int nf_ct_change_status_common(struct nf_conn *ct, unsigned int status)
|
||||
{
|
||||
unsigned long d;
|
||||
|
||||
d = ct->status ^ status;
|
||||
|
||||
if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING))
|
||||
/* unchangeable */
|
||||
return -EBUSY;
|
||||
|
||||
if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY))
|
||||
/* SEEN_REPLY bit can only be set */
|
||||
return -EBUSY;
|
||||
|
||||
if (d & IPS_ASSURED && !(status & IPS_ASSURED))
|
||||
/* ASSURED bit can only be set */
|
||||
return -EBUSY;
|
||||
|
||||
__nf_ct_change_status(ct, status, 0);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_ct_change_status_common);
|
||||
|
||||
#endif
|
||||
|
@ -1890,45 +1890,10 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct,
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
__ctnetlink_change_status(struct nf_conn *ct, unsigned long on,
|
||||
unsigned long off)
|
||||
{
|
||||
unsigned int bit;
|
||||
|
||||
/* Ignore these unchangable bits */
|
||||
on &= ~IPS_UNCHANGEABLE_MASK;
|
||||
off &= ~IPS_UNCHANGEABLE_MASK;
|
||||
|
||||
for (bit = 0; bit < __IPS_MAX_BIT; bit++) {
|
||||
if (on & (1 << bit))
|
||||
set_bit(bit, &ct->status);
|
||||
else if (off & (1 << bit))
|
||||
clear_bit(bit, &ct->status);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ctnetlink_change_status(struct nf_conn *ct, const struct nlattr * const cda[])
|
||||
{
|
||||
unsigned long d;
|
||||
unsigned int status = ntohl(nla_get_be32(cda[CTA_STATUS]));
|
||||
d = ct->status ^ status;
|
||||
|
||||
if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING))
|
||||
/* unchangeable */
|
||||
return -EBUSY;
|
||||
|
||||
if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY))
|
||||
/* SEEN_REPLY bit can only be set */
|
||||
return -EBUSY;
|
||||
|
||||
if (d & IPS_ASSURED && !(status & IPS_ASSURED))
|
||||
/* ASSURED bit can only be set */
|
||||
return -EBUSY;
|
||||
|
||||
__ctnetlink_change_status(ct, status, 0);
|
||||
return 0;
|
||||
return nf_ct_change_status_common(ct, ntohl(nla_get_be32(cda[CTA_STATUS])));
|
||||
}
|
||||
|
||||
static int
|
||||
@ -2825,7 +2790,7 @@ ctnetlink_update_status(struct nf_conn *ct, const struct nlattr * const cda[])
|
||||
* unchangeable bits but do not error out. Also user programs
|
||||
* are allowed to clear the bits that they are allowed to change.
|
||||
*/
|
||||
__ctnetlink_change_status(ct, status, ~status);
|
||||
__nf_ct_change_status(ct, status, ~status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user