Skip to content

[CBR 7.9] netfilter: nf_tables: Reject tables of unsupported family #448

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

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

Conversation

pvts-mat
Copy link
Contributor

[CBR 7.9]
CVE-2023-6040
VULN-7622

Problem

https://www.openwall.com/lists/oss-security/2024/01/12/1

An out-of-bounds access vulnerability involving netfilter was reported
and fixed as:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f1082dd31fe461d482d69da2a8eccfeb7bf07ac2

While creating a new netfilter table, lack of a safeguard against
invalid nf_tables family (pf) values within `nf_tables_newtable`
function enables an attacker to achieve out-of-bounds access.

This out-of-bounds access can occur in two locations:

  1. `xt_find_target` function in `x_tables.c` can dereference the `xt`
    array without a boundary check. This allows an attacker to fake an
    `xt_af` data and achieve further ends.

  2. `nf_logger_find_get` function in `nf_log.c` uses `pf` as an index on
    `loggers` global which consists of `struct nf_logger` members. An
    attacker can find a suitable global data to fake as `struct nf_logger`
    and use the invalid `pf` to dereference adjacent global data.

Disabling unprivileged user namespaces mitigates the issue.

This issue was reported to Ubuntu Security directly by Lin Ma from Ant
Security Light-Year Lab and has been assigned CVE-2023-6040.

It affects upstream stable 5.4.y, 5.10.y, 5.15.y. Those require the fix
to be applied. Any upstream kernel newer than 5.18-rc1 should be safe.

Applicability: yes

The nf_tables module is enabled in CBR 7.9:

$ grep 'CONFIG_NF_TABLES\b' configs/*.config

configs/kernel-3.10.0-x86_64-debug.config:CONFIG_NF_TABLES=m
configs/kernel-3.10.0-x86_64.config:CONFIG_NF_TABLES=m

The fixing commit f1082dd is not present in the affected file's net/netfilter/nf_tables_api.c history for ciqcbr7_9, nor was it backported.

The bug can't be blamed on a single commit - there is no "fixes" commit indicated in f1082dd to check whether it exists in ciqcbr7_9 history or not. However, without replicating Ant Security Lab's analysis it can be reasonably assumed that the bug is present in CBR 7.9 based on the following arguments:

  1. The xt_find_target function exists in net/netfilter/x_tables.c and it does dereference the xt array a couple of times without boundary checking:
    mutex_lock(&xt[af].mutex);

    list_for_each_entry(t, &xt[af].target, list) {

    mutex_unlock(&xt[af].mutex);

    mutex_unlock(&xt[af].mutex);
  2. The nf_logger_find_get function exists in net/netfilter/nf_log.c and the global loggers variable is dereferenced with pf
    logger = loggers[pf][type];

    logger = rcu_dereference(loggers[pf][type]);

    logger = rcu_dereference(loggers[pf][type]);

Solution

Naively cherry-picking the f1082dd commit leads to many conflicts but they aren't indicative of any semantic mismatches between the patch and net/netfilter/nf_tables_api.c file under ciqcbr7_9 revision. The changes were applied manually as they appear in the diff. Two changes compared to mainline were made:

  1. The CONFIG_NF_TABLES_NETDEV case was removed because that option is not even available in ciqcbr7_9 yet.
  2. All table type CONFIGs were wrapped in IS_ENABLED(...) macro instead of just CONFIG_NF_TABLES_BRIDGE because all of them are of type "tristate" in ciqcbr7_9, unlike in the newer kernels where they are "bool" and a simple #ifdef is sufficient:
    tristate "Netfilter nf_tables mixed IPv4/IPv6 tables support"

    tristate "IPv4 nf_tables support"

    tristate "ARP nf_tables support"

    tristate "Ethernet Bridge nf_tables support"

    tristate "IPv6 nf_tables support"

    Compare with ciqlts9_2, for example:
    bool "Netfilter nf_tables mixed IPv4/IPv6 tables support"

    bool "IPv4 nf_tables support"

    bool "ARP nf_tables support"

    bool "Netfilter nf_tables netdev tables support"

    tristate "Ethernet Bridge nf_tables support"

    bool "IPv6 nf_tables support"

kABI check: passed

[root@ciqcbr-7-9 pvts]# python /mnt/code/kernel-dist-git-el-7.9/SOURCES/check-kabi -k /mnt/code/kernel-dist-git-el-7.9/SOURCES/Module.kabi_x86_64 -s /mnt/build_files/kernel-src-tree-ciqcbr7_9-CVE-2023-6040/Module.symvers
[root@ciqcbr-7-9 pvts]# echo $? 
0

Boot test: passed

See implied boot test passing in the Specific tests section.

Selftests: skipped

It was attempted to use the netfilter:* selftests from Rocky LTS 8.6 version to test the nf tables module in CBR 7.9, as most of them are just bash scripts juggling ip, nft, nc and conntrack calls to create network setups. Unfortunately, the nft version available in CBR 7.9 didn't recognize the call syntax of reading from stdin

nft -f -

used extensively in the scripts. Where the more explicit form was used

nft -f /dev/stdin

it could not understand the provided configuration, like

nft -f /dev/stdin <<EOF
table $family nat {
	chain output {
		type nat hook output priority 0; policy accept;
		ip6 daddr dead:1::99 dnat $IPF to dead:2:i:99
	}
}
EOF

In short, the nft tool was too old.

Specific tests: passed

The modified function nf_tables_newtable can be quite easily reached from the userspace with the nft add table… command. With config options mapping to the third arguments as

Config option X: nft add table X
CONFIG_NF_TABLES_INET inet
CONFIG_NF_TABLES_IPV4 ip
CONFIG_NF_TABLES_IPV6 ip6
CONFIG_NF_TABLES_ARP arp
CONFIG_NF_TABLES_BRIDGE bridge

all of supported table types are accepted in the patched kernel, just as they are in the reference kernel:

[root@ciqcbr-7-9 pvts]# nft add table inet table_inet
[root@ciqcbr-7-9 pvts]# echo $? 
0
[root@ciqcbr-7-9 pvts]# nft add table ip table_ip
[root@ciqcbr-7-9 pvts]# echo $? 
0
[root@ciqcbr-7-9 pvts]# nft add table ip6 table_ip6
[root@ciqcbr-7-9 pvts]# echo $? 
0
[root@ciqcbr-7-9 pvts]# nft add table arp table_arp
[root@ciqcbr-7-9 pvts]# echo $? 
0
[root@ciqcbr-7-9 pvts]# nft add table bridge table_bridge
[root@ciqcbr-7-9 pvts]# echo $? 
0
[root@ciqcbr-7-9 pvts]# nft list tables
nft list tables
table ip table_ip
table ip6 table_ip6
table inet table_inet
table arp table_arp
table bridge table_bridge

specific-test-reference.log
specific-test-patch.log

A test version of the kernel for both the reference and the patch was prepared, with the CONFIG_NF_TABLES_ARP option disabled

CONFIG_NF_TABLES_ARP=n

to gauge nft's reaction for creating the unsupported arp table.

  • Patch:

    [root@ciqcbr-7-9 pvts]# nft add table arp table_arp
    Error: Could not process rule: Operation not supported
    add table arp table_arp
    ^^^^^^^^^^^^^^^^^^^^^^^^
    [root@ciqcbr-7-9 pvts]# echo $? 
    1
    

    The "Operation not supported" message aligns with the -EOPNOTSUPP value returned in the branch added to nf_tables_newtable function:

    if (!nft_supported_family(family))
      	return -EOPNOTSUPP;
    

    specific-test-patch-no-arp.log

  • Reference:

    [root@ciqcbr-7-9 pvts]# nft add table arp table_arp
    Error: Could not process rule: Address family not supported by protocol
    add table arp table_arp
    ^^^^^^^^^^^^^^^^^^^^^^^^
    [root@ciqcbr-7-9 pvts]#
    

    The arp argument is likewise rejected, as expected, although with a different message implying a later point in the code path, where the problems indicated in the CVE may manifest.

    specific-test-reference-no-arp.log

Commentary

Technically this bug may not be applicable to Rocky CBR 7.9, as no table type is unsupported - all of NF_TABLES_INET, NF_TABLES_IPV4, NF_TABLES_ARP, NF_TABLES_BRIDGE, NF_TABLES_NETDEV, NF_TABLES_IPV6 options are enabled in configs/kernel-3.10.0-x86_64.config and the nft_supported_family(family) call may just as well always evaluate to true (same applies to #440 and #438). However, this would require showing that family variable won't ever assume any other value than NFPROTO_INET, NFPROTO_IPV4, NFPROTO_ARP, NFPROTO_BRIDGE, NFPROTO_IPV6, which the nft calls given previously suggest, but which would nevertheless need to be proved by kernel code investigation. Considering that this was realized after the patch was already made and tested it's now cheaper to include it instead of pursuing this analysis.

jira VULN-7622
cve CVE-2023-6040
commit-author Phil Sutter <[email protected]>
commit f1082dd
upstream-diff  |
  1. The `CONFIG_NF_TABLES_NETDEV' case removed because that option is
     not even available in the `ciqcbr7_9' yet.
  2. All table type CONFIGs wrapped in `IS_ENABLED(...)' macro instead
     of just `CONFIG_NF_TABLES_BRIDGE' because all of them are of type
     "tristate" in `ciqcbr7_9', unlike in the newer kernels where they
     are "bool" and a simple #ifdef is sufficient.

An nftables family is merely a hollow container, its family just a
number and such not reliant on compile-time options other than nftables
support itself. Add an artificial check so attempts at using a family
the kernel can't support fail as early as possible. This helps user
space detect kernels which lack e.g. NFPROTO_INET.

	Signed-off-by: Phil Sutter <[email protected]>
	Signed-off-by: Pablo Neira Ayuso <[email protected]>
(cherry picked from commit f1082dd)
	Signed-off-by: Marcin Wcisło <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

1 participant