Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ipt_DF: Fix for upstream replacement of skb_make_writable with skb_ensure_writable #1

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

lcrestez-dn
Copy link

No description provided.

@lcrestez-dn
Copy link
Author

@@ -10,6 +13,12 @@ MODULE_AUTHOR("Semyon Verchenko");
MODULE_DESCRIPTION("Netfilter module to set/reset DF flag");
MODULE_LICENSE("Dual BSD/GPL");

#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0))
# skb_make_writable was removed in this commit:
# https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=2cf6bffc49dae26edd12af6b57c8c780590380bf
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments should begin with /* :-)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also... i see skb_ensure_writeable is present in 4.15. Is this needed ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fpopescu-dn Using skb_ensure_writeable() was actually a bug, and so it appears we need to use skb_make_writable() drivenets/dontfragment@38e1b4d
+ @oshamash might have more info

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember now @oshamash pinged me about this some time ago (spending days to find this). So why it would work now in the 5.2+

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, it was this drivenets/dontfragment@94d2273

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments should begin with /* :-)

Fixed

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made a dumb compat fix assuming code is already correct. Seeing how it doesn't even compile on 5.4 it might be unused.

@@ -23,7 +32,7 @@ static unsigned int df_tg(struct sk_buff *skb, const struct xt_action_param *par
__u16 old_frag_off, new_frag_off;

/* make_writable might invoke copy-on-write, so fetch iph afterwards */
if (!skb_make_writable(skb, sizeof(struct iphdr))){
if (skb_ensure_writable(skb, sizeof(struct iphdr))){
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO it will be more readable to have the #if (LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0)) here, instead of making skb_ensure_writable a macro (if someone casually goes over the code he will be surprised that skb_ensure_writable() is a macro).

#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0))
    if (!skb_make_writable(skb, sizeof(struct iphdr))){
#else
    if (skb_ensure_writable(skb, sizeof(struct iphdr))){
#endif

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using only the new version in code means that there is a single place where you can drop support for old versions.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree w/ @lschlesinger-dn here - it's mainly about readability,
if you assume macro == function in some versions, it's malpractice

instead you can go with

#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0))
    #define DN_ENSURE_WRITABLE(skb, len) (!skb_make_writable((skb), (len)))
#else
    #define DN_ENSURE_WRITABLE(skb, len) (skb_ensure_writable((skb), (len))
#endif
....

if (DN_ENSURE_WRITABLE(skb, sizeof(struct iphdr))) {

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as for why - the issue is that sometimes skb needs to be reallocated to allow writing changes, this makes the previously fetched header-pointer a UAF bug ("use-after-free")

Copy link

@oshamash oshamash Sep 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another note per what @fpopescu-dn mentioned, I do remember trying to initially use ensure_writable and it failed on older kernel - it would just not fix the IP packet and would avoid the patch altogether as it was required to forcefully make the SKB writable

So honestly not sure if we can really use this in new kernel - QA don't even have a proper scenario to test patch

EDIT: thinking back again, I think initially I changed to https://www.kernel.org/doc/htmldocs/networking/API-skb-clone-writable.html then when it kept failing - I kept it as make_writable

now going over kernel code - there is no reason to distinguish the KERNEL version, as the skb_ensure_writable is coming from SKB_CORE code, while skb_make_writable comes from NETFILTER_CORE, it was a development hindsight that they missed this duplication, while they do operate a little differently, they both guarantee same thing

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also think it's probably safe to just stick with skb_ensure_writable, but given that QA indeed can't test it then my paranoid side says we shouldn't touch the old code which we know works 😛

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i vote to keep the old version skb_make_writable but also for kernel 5.4 which we already use and we know that it works. For versions > 5.4 we can go with the skb_ensure_writable and pray it does the same thing (the code is a little different, but in the end the result should be the same).

@lcrestez-dn
Copy link
Author

The skb_make_writable function doesn't even exist in linux 5.4, this means that this module is only used for linux 4.15?!?!

I will just skip it for building because it seems to me to be unused.

@lschlesinger-dn
Copy link
Collaborator

lschlesinger-dn commented Sep 7, 2022

The skb_make_writable function doesn't even exist in linux 5.4, this means that this module is only used for linux 4.15?!?!

I will just skip it for building because it seems to me to be unused.

$ nm image/iptables_extensions/5.4.0-73-generic/ipt_DF.ko | grep skb_
                 U skb_ensure_writable

nice
@lcrestez-dn @oshamash @fpopescu-dn

@oshamash
Copy link

oshamash commented Sep 7, 2022

The skb_make_writable function doesn't even exist in linux 5.4, this means that this module is only used for linux 4.15?!?!

I will just skip it for building because it seems to me to be unused.

this module is needed for iptables to allow -j DF target, see containers/golden_image/scripts/replace_vxlan.sh

# Note: host_ns exist here due to being created prior in entrypoint
if ! ${NETNS_VXLAN_EXEC} /sbin/ip link show dev ${VXLAN_DEV} 2>/dev/null; then
  wait_for_ctrl_bond
  ...
  log_debug "Adding rule for iptables-df"
  ${NETNS_VXLAN_EXEC} /sbin/iptables -t mangle -A FORWARD -j DF --reset
  ${NETNS_VXLAN_EXEC} /sbin/iptables -t mangle -A POSTROUTING -j DF --reset

@oshamash
Copy link

oshamash commented Sep 7, 2022

@lcrestez-dn also, the skb_ensure_writable is available both on 4.15 and 5.4,
so the entire MACRO thing is not good if we want to make older version !

skb_make_writable was removed in newer kernels since it was a duplicate logic of skb_ensure_writable

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants