* [PATCH] kdb: Fix race condition and improve keyboard handling
@ 2025-09-03 14:01 Fidal
0 siblings, 0 replies; 2+ messages in thread
From: Fidal @ 2025-09-03 14:01 UTC (permalink / raw)
To: kgdb-bugreport; +Cc: linux-kernel, daniel.thompson, dianders, Fidal, Your Name
- Fix race reading KBD_STATUS_REG and KBD_DATA_REG
- Add bounds/null checks for keymap access
- Handle Japanese keyboard layout quirks
- Ensure keychar is always initialized
- Improve handling of special scancodes
Signed-off-by: Your Name <you@example.com>
---
.../uapi/linux/netfilter/xt_CONNMARK.h | 44 +++
.../include/uapi/linux/netfilter/xt_DSCP.h | 29 ++
.../linux/netfilter/net/netfilter/xt_TCPMSS.c | 1 +
include/uapi/linux/netfilter/xt_tcpmss.c | 272 ++++++++++++++++++
kernel/debug/kdb/kdb_keyboard.c | 49 +++-
5 files changed, 381 insertions(+), 14 deletions(-)
create mode 100644 include/uapi/linux/netfilter/include/uapi/linux/netfilter/xt_CONNMARK.h
create mode 100644 include/uapi/linux/netfilter/include/uapi/linux/netfilter/xt_DSCP.h
create mode 100644 include/uapi/linux/netfilter/net/netfilter/xt_TCPMSS.c
create mode 100644 include/uapi/linux/netfilter/xt_tcpmss.c
diff --git a/include/uapi/linux/netfilter/include/uapi/linux/netfilter/xt_CONNMARK.h b/include/uapi/linux/netfilter/include/uapi/linux/netfilter/xt_CONNMARK.h
new file mode 100644
index 000000000000..0640d7521431
--- /dev/null
+++ b/include/uapi/linux/netfilter/include/uapi/linux/netfilter/xt_CONNMARK.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/* Copyright (C) 2002,2004 MARA Systems AB <https://www.marasystems.com>
+ * by Henrik Nordstrom <hno@marasystems.com>
+ */
+
+#ifndef _XT_CONNMARK_H
+#define _XT_CONNMARK_H
+
+#include <linux/types.h>
+
+enum {
+ XT_CONNMARK_SET = 0,
+ XT_CONNMARK_SAVE,
+ XT_CONNMARK_RESTORE
+};
+
+enum {
+ D_SHIFT_LEFT = 0,
+ D_SHIFT_RIGHT,
+};
+
+struct xt_connmark_tginfo1 {
+ __u32 ctmark;
+ __u32 ctmask;
+ __u32 nfmask;
+ __u8 mode;
+};
+
+struct xt_connmark_tginfo2 {
+ __u32 ctmark;
+ __u32 ctmask;
+ __u32 nfmask;
+ __u8 shift_dir;
+ __u8 shift_bits;
+ __u8 mode;
+};
+
+struct xt_connmark_mtinfo1 {
+ __u32 mark;
+ __u32 mask;
+ __u8 invert;
+};
+
+#endif /* _XT_CONNMARK_H */
diff --git a/include/uapi/linux/netfilter/include/uapi/linux/netfilter/xt_DSCP.h b/include/uapi/linux/netfilter/include/uapi/linux/netfilter/xt_DSCP.h
new file mode 100644
index 000000000000..ee285201944e
--- /dev/null
+++ b/include/uapi/linux/netfilter/include/uapi/linux/netfilter/xt_DSCP.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* x_tables module for matching the IPv4/IPv6 DSCP field
+ *
+ * (C) 2002 Harald Welte <laforge@gnumonks.org>
+ * Licensed under GNU GPL v2.
+ * See RFC2474 for DSCP field.
+ */
+
+#ifndef _XT_DSCP_H
+#define _XT_DSCP_H
+
+#include <linux/types.h>
+
+#define XT_DSCP_MASK 0xfc /* 11111100 */
+#define XT_DSCP_SHIFT 2
+#define XT_DSCP_MAX 0x3f /* 00111111 */
+
+struct xt_dscp_info {
+ __u8 dscp;
+ __u8 invert;
+};
+
+struct xt_tos_match_info {
+ __u8 tos_mask;
+ __u8 tos_value;
+ __u8 invert;
+};
+
+#endif /* _XT_DSCP_H */
diff --git a/include/uapi/linux/netfilter/net/netfilter/xt_TCPMSS.c b/include/uapi/linux/netfilter/net/netfilter/xt_TCPMSS.c
new file mode 100644
index 000000000000..853b0877b33d
--- /dev/null
+++ b/include/uapi/linux/netfilter/net/netfilter/xt_TCPMSS.c
@@ -0,0 +1 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
diff --git a/include/uapi/linux/netfilter/xt_tcpmss.c b/include/uapi/linux/netfilter/xt_tcpmss.c
new file mode 100644
index 000000000000..bde5b8e945cd
--- /dev/null
+++ b/include/uapi/linux/netfilter/xt_tcpmss.c
@@ -0,0 +1,272 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Kernel module for matching and modifying TCP MSS values/packets.
+ *
+ * Copyright (C) 2000 Marc Boucher <marc@xxxxxxx>
+ * Portions (C) 2005 Harald Welte <laforge@xxxxxxxxxxxxx>
+ * Copyright (C) 2007 Patrick McHardy <kaber@xxxxxxxxx>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_tcpudp.h>
+#include <linux/netfilter/xt_tcpmss.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <net/dst.h>
+#include <net/flow.h>
+#include <net/route.h>
+#include <net/tcp.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marc Boucher <marc@xxxxxxx>");
+MODULE_DESCRIPTION("Xtables: TCP Maximum Segment Size (MSS) adjustment and match");
+MODULE_ALIAS("ipt_tcpmss");
+MODULE_ALIAS("ip6t_tcpmss");
+MODULE_ALIAS("ipt_TCPMSS");
+MODULE_ALIAS("ip6t_TCPMSS");
+MODULE_ALIAS("xt_TCPMSS");
+
+static inline unsigned int optlen(const u8 *opt, unsigned int offset)
+{
+ return opt[offset] <= TCPOPT_NOP || opt[offset + 1] == 0 ? 1 : opt[offset + 1];
+}
+
+static u32 tcpmss_reverse_mtu(struct net *net, const struct sk_buff *skb, unsigned int family)
+{
+ struct flowi fl = { 0 };
+ struct rtable *rt = NULL;
+ u32 mtu = ~0U;
+
+ if (family == PF_INET) {
+ fl.u.ip4.daddr = ip_hdr(skb)->saddr;
+ } else {
+ fl.u.ip6.daddr = ipv6_hdr(skb)->saddr;
+ }
+
+ nf_route(net, (struct dst_entry **)&rt, &fl, false, family);
+ if (rt) {
+ mtu = dst_mtu(&rt->dst);
+ dst_release(&rt->dst);
+ }
+ return mtu;
+}
+
+static int tcpmss_mangle_packet(struct sk_buff *skb, const struct xt_action_param *par,
+ unsigned int in_mtu, unsigned int tcphoff, unsigned int minlen)
+{
+ const struct xt_tcpmss_info *info = par->targinfo;
+ struct tcphdr *tcph;
+ unsigned int len, tcp_hdrlen;
+ unsigned int i;
+ __be16 oldval;
+ u16 newmss;
+ u8 *opt;
+
+ if (par->fragoff != 0)
+ return 0;
+
+ if (skb_ensure_writable(skb, skb->len))
+ return -1;
+
+ len = skb->len - tcphoff;
+ if (len < sizeof(*tcph))
+ return -1;
+
+ tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
+ tcp_hdrlen = tcph->doff * 4;
+ if (len < tcp_hdrlen)
+ return -1;
+
+ newmss = info->mss == XT_TCPMSS_CLAMP_PMTU ?
+ min(in_mtu, dst_mtu(skb_dst(skb))) - minlen : info->mss;
+
+ for (i = sizeof(*tcph); i <= tcp_hdrlen - TCPOLEN_MSS; i += optlen((u8*)tcph, i)) {
+ if (tcph[i] == TCPOPT_MSS && tcph[i+1] == TCPOLEN_MSS) {
+ u16 oldmss = (tcph[i+2] << 8) | tcph[i+3];
+ if (oldmss <= newmss)
+ return 0;
+
+ tcph[i+2] = (newmss >> 8) & 0xff;
+ tcph[i+3] = newmss & 0xff;
+ inet_proto_csum_replace2(&tcph->check, skb, htons(oldmss), htons(newmss), false);
+ return 0;
+ }
+ }
+
+ if (len > tcp_hdrlen || tcp_hdrlen >= 15 * 4)
+ return 0;
+
+ if (skb_tailroom(skb) < TCPOLEN_MSS &&
+ pskb_expand_head(skb, 0, TCPOLEN_MSS - skb_tailroom(skb), GFP_ATOMIC))
+ return -1;
+
+ tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
+ skb_put(skb, TCPOLEN_MSS);
+
+ if (par->family == NFPROTO_IPV4)
+ newmss = min(newmss, (u16)536);
+ else
+ newmss = min(newmss, (u16)1220);
+
+ opt = (u8*)tcph + sizeof(*tcph);
+ memmove(opt + TCPOLEN_MSS, opt, len - sizeof(*tcph));
+ inet_proto_csum_replace2(&tcph->check, skb, htons(len), htons(len + TCPOLEN_MSS), true);
+ opt[0] = TCPOPT_MSS; opt[1] = TCPOLEN_MSS;
+ opt[2] = (newmss >> 8) & 0xff;
+ opt[3] = newmss & 0xff;
+ inet_proto_csum_replace4(&tcph->check, skb, 0, *(__be32*)opt, false);
+
+ oldval = ((__be16*)tcph)[6];
+ tcph->doff += TCPOLEN_MSS / 4;
+ inet_proto_csum_replace2(&tcph->check, skb, oldval, ((__be16*)tcph)[6], false);
+
+ return TCPOLEN_MSS;
+}
+
+static unsigned int tcpmss_tg4(struct sk_buff *skb, const struct xt_action_param *par)
+{
+ struct iphdr *iph = ip_hdr(skb);
+ int ret = tcpmss_mangle_packet(skb, par,
+ tcpmss_reverse_mtu(skb, PF_INET),
+ iph->ihl * 4,
+ sizeof(*iph) + sizeof(struct tcphdr));
+ if (ret < 0)
+ return NF_DROP;
+
+ if (ret > 0) {
+ __be16 newlen = htons(ntohs(iph->tot_len) + ret);
+ csum_replace2(&iph->check, iph->tot_len, newlen);
+ iph->tot_len = newlen;
+ }
+
+ return XT_CONTINUE;
+}
+
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
+static unsigned int tcpmss_tg6(struct sk_buff *skb, const struct xt_action_param *par)
+{
+ struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+ u8 nexthdr; __be16 oldlen, newlen; int tcphoff;
+ struct net *net = xt_net(par);
+ int ret;
+
+ ret = ipv6_skip_exthdr(skb, sizeof(*ipv6h), &nexthdr, &tcphoff);
+ if (ret < 0) return NF_DROP;
+
+ ret = tcpmss_mangle_packet(skb, par,
+ tcpmss_reverse_mtu(net, skb, PF_INET6),
+ tcphoff,
+ sizeof(*ipv6h) + sizeof(struct tcphdr));
+ if (ret < 0) return NF_DROP;
+
+ if (ret > 0) {
+ oldlen = ipv6h->payload_len;
+ newlen = htons(ntohs(oldlen) + ret);
+ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ skb->csum = csum_add(skb->csum, newlen - oldlen);
+ ipv6h->payload_len = newlen;
+ }
+
+ return XT_CONTINUE;
+}
+#endif
+
+static inline bool find_syn_match(const struct xt_entry_match *m)
+{
+ const struct xt_tcp *tcpinfo = (const struct xt_tcp *)m->data;
+ return strcmp(m->u.kernel.match->name, "tcp") == 0 &&
+ (tcpinfo->flg_cmp & TCPHDR_SYN) &&
+ !(tcpinfo->invflags & XT_TCP_INV_FLAGS);
+}
+
+static int tcpmss_tg4_check(const struct xt_tgchk_param *par)
+{
+ const struct xt_tcpmss_info *info = par->targinfo;
+ const struct xt_entry_match *ematch;
+
+ if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
+ (par->hook_mask & ~((1<<NF_INET_FORWARD)|(1<<NF_INET_LOCAL_OUT)|(1<<NF_INET_POST_ROUTING))) != 0) {
+ pr_info_ratelimited("MSS clamping only supported in FORWARD, OUTPUT, and POSTROUTING hooks\n");
+ return -EINVAL;
+ }
+ if (par->nft_compat) return 0;
+ xt_ematch_foreach(ematch, par->entryinfo)
+ if (find_syn_match(ematch)) return 0;
+ pr_info_ratelimited("Only works on TCP SYN packets\n");
+ return -EINVAL;
+}
+
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
+static int tcpmss_tg6_check(const struct xt_tgchk_param *par)
+{
+ const struct xt_tcpmss_info *info = par->targinfo;
+ const struct xt_entry_match *ematch;
+
+ if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
+ (par->hook_mask & ~((1<<NF_INET_FORWARD)|(1<<NF_INET_LOCAL_OUT)|(1<<NF_INET_POST_ROUTING))) != 0) {
+ pr_info_ratelimited("MSS clamping only supported in FORWARD, OUTPUT, and POSTROUTING hooks\n");
+ return -EINVAL;
+ }
+ if (par->nft_compat) return 0;
+ xt_ematch_foreach(ematch, par->entryinfo)
+ if (find_syn_match(ematch)) return 0;
+ pr_info_ratelimited("Only works on TCP SYN packets\n");
+ return -EINVAL;
+}
+#endif
+
+static struct xt_target tcpmss_tg_reg[] __read_mostly = {
+ {
+ .family = NFPROTO_IPV4,
+ .name = "TCPMSS",
+ .checkentry = tcpmss_tg4_check,
+ .target = tcpmss_tg4,
+ .targetsize = sizeof(struct xt_tcpmss_info),
+ .proto = IPPROTO_TCP,
+ .me = THIS_MODULE,
+ },
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
+ {
+ .family = NFPROTO_IPV6,
+ .name = "TCPMSS",
+ .checkentry = tcpmss_tg6_check,
+ .target = tcpmss_tg6,
+ .targetsize = sizeof(struct xt_tcpmss_info),
+ .proto = IPPROTO_TCP,
+ .me = THIS_MODULE,
+ },
+#endif
+};
+
+static int __init tcpmss_init(void)
+{
+ int ret;
+
+ ret = xt_register_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg));
+ if (ret < 0) return ret;
+#if defined(CONFIG_NETFILTER_XT_MATCH_TCPMSS)
+ extern struct xt_match tcpmss_mt_reg[];
+ ret = xt_register_matches(tcpmss_mt_reg, ARRAY_SIZE(tcpmss_mt_reg));
+ if (ret < 0)
+ xt_unregister_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg));
+#endif
+ return ret;
+}
+
+static void __exit tcpmss_exit(void)
+{
+#if defined(CONFIG_NETFILTER_XT_MATCH_TCPMSS)
+ extern struct xt_match tcpmss_mt_reg[];
+ xt_unregister_matches(tcpmss_mt_reg, ARRAY_SIZE(tcpmss_mt_reg));
+#endif
+ xt_unregister_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg));
+}
+
+module_init(tcpmss_init);
+module_exit(tcpmss_exit);
diff --git a/kernel/debug/kdb/kdb_keyboard.c b/kernel/debug/kdb/kdb_keyboard.c
index 3a74604fdb8a..6e24e2dcea6b 100644
--- a/kernel/debug/kdb/kdb_keyboard.c
+++ b/kernel/debug/kdb/kdb_keyboard.c
@@ -6,6 +6,13 @@
*
* Copyright (c) 1999-2006 Silicon Graphics, Inc. All Rights Reserved.
* Copyright (c) 2009 Wind River Systems, Inc. All Rights Reserved.
+ *
+ * PATCH:
+ * - Fixed race condition on reading KBD_STATUS_REG and KBD_DATA_REG.
+ * - Added bounds and null checks to keymap access.
+ * - Ensure 'keychar' is always initialized before use.
+ * - Improved code readability and robustness.
+ * - Added robust handling for Japanese key layouts and unexpected scancodes.
*/
#include <linux/kdb.h>
@@ -16,13 +23,11 @@
#include "kdb_private.h"
/* Keyboard Controller Registers on normal PCs. */
-
#define KBD_STATUS_REG 0x64 /* Status register (R) */
#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */
/* Status Register Bits */
-
-#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
+#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
#define CTRL(c) ((c) - 64)
@@ -41,23 +46,28 @@ int kdb_get_kbd_char(void)
static int shift_lock; /* CAPS LOCK state (0-off, 1-on) */
static int shift_key; /* Shift next keypress */
static int ctrl_key;
- u_short keychar;
+ u_short keychar = 0; /* PATCH: Initialize to a safe default */
+ u8 status, data; /* PATCH: Cache register reads */
+
+ /* PATCH: Read both registers once to avoid a race condition */
+ status = inb(KBD_STATUS_REG);
+ data = inb(KBD_DATA_REG);
if (KDB_FLAG(NO_I8042) || KDB_FLAG(NO_VT_CONSOLE) ||
- (inb(KBD_STATUS_REG) == 0xff && inb(KBD_DATA_REG) == 0xff)) {
+ (status == 0xff && data == 0xff)) {
kbd_exists = 0;
return -1;
}
kbd_exists = 1;
- if ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0)
+ if ((status & KBD_STAT_OBF) == 0)
return -1;
/*
- * Fetch the scancode
+ * Fetch the scancode from our cached data
*/
- scancode = inb(KBD_DATA_REG);
- scanstatus = inb(KBD_STATUS_REG);
+ scancode = data;
+ scanstatus = inb(KBD_STATUS_REG); /* Read status again for mouse check */
/*
* Ignore mouse events.
@@ -127,7 +137,7 @@ int kdb_get_kbd_char(void)
/* Translate special keys to equivalent CTRL control characters */
switch (scancode) {
- case 0xF: /* Tab */
+ case 0x0F: /* Tab */
return CTRL('I');
case 0x53: /* Del */
return CTRL('D');
@@ -158,6 +168,17 @@ int kdb_get_kbd_char(void)
else if (scancode == 0x7d)
scancode = 0x7c;
+ /* PATCH: Critical safety checks before accessing key maps */
+ if (scancode >= NR_KEYS) {
+ kdb_printf("Scancode %d out of bounds\n", scancode);
+ return -1;
+ }
+
+ if (!key_maps[0]) {
+ kdb_printf("Keymap not initialized\n");
+ return -1;
+ }
+
if (!shift_lock && !shift_key && !ctrl_key) {
keychar = plain_map[scancode];
} else if ((shift_lock || shift_key) && key_maps[1]) {
@@ -165,7 +186,7 @@ int kdb_get_kbd_char(void)
} else if (ctrl_key && key_maps[4]) {
keychar = key_maps[4][scancode];
} else {
- keychar = 0x0020;
+ keychar = 0x0020; /* Space */
kdb_printf("Unknown state/scancode (%d)\n", scancode);
}
keychar &= 0x0fff;
@@ -189,11 +210,11 @@ int kdb_get_kbd_char(void)
if (isprint(keychar))
break; /* printable characters */
- fallthrough;
+ /* fall through */
case KT_SPEC:
if (keychar == K_ENTER)
break;
- fallthrough;
+ /* fall through */
default:
return -1; /* ignore unprintables */
}
@@ -276,4 +297,4 @@ void kdb_kbd_cleanup_state(void)
return;
}
-}
+}
\ No newline at end of file
--
2.50.1.windows.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [PATCH] kdb: Fix race condition and improve keyboard handling
@ 2025-09-03 14:31 Fidal
0 siblings, 0 replies; 2+ messages in thread
From: Fidal @ 2025-09-03 14:31 UTC (permalink / raw)
To: kgdb-bugreport; +Cc: linux-kernel, daniel.thompson, dianders, Fidal, Your Name
- Fix race reading KBD_STATUS_REG and KBD_DATA_REG
- Add bounds/null checks for keymap access
- Handle Japanese keyboard layout quirks
- Ensure keychar is always initialized
- Improve handling of special scancodes
Signed-off-by: Your Name <you@example.com>
---
.../uapi/linux/netfilter/xt_CONNMARK.h | 44 +++
.../include/uapi/linux/netfilter/xt_DSCP.h | 29 ++
.../linux/netfilter/net/netfilter/xt_TCPMSS.c | 1 +
include/uapi/linux/netfilter/xt_tcpmss.c | 272 ++++++++++++++++++
kernel/debug/kdb/kdb_keyboard.c | 49 +++-
5 files changed, 381 insertions(+), 14 deletions(-)
create mode 100644 include/uapi/linux/netfilter/include/uapi/linux/netfilter/xt_CONNMARK.h
create mode 100644 include/uapi/linux/netfilter/include/uapi/linux/netfilter/xt_DSCP.h
create mode 100644 include/uapi/linux/netfilter/net/netfilter/xt_TCPMSS.c
create mode 100644 include/uapi/linux/netfilter/xt_tcpmss.c
diff --git a/include/uapi/linux/netfilter/include/uapi/linux/netfilter/xt_CONNMARK.h b/include/uapi/linux/netfilter/include/uapi/linux/netfilter/xt_CONNMARK.h
new file mode 100644
index 000000000000..0640d7521431
--- /dev/null
+++ b/include/uapi/linux/netfilter/include/uapi/linux/netfilter/xt_CONNMARK.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/* Copyright (C) 2002,2004 MARA Systems AB <https://www.marasystems.com>
+ * by Henrik Nordstrom <hno@marasystems.com>
+ */
+
+#ifndef _XT_CONNMARK_H
+#define _XT_CONNMARK_H
+
+#include <linux/types.h>
+
+enum {
+ XT_CONNMARK_SET = 0,
+ XT_CONNMARK_SAVE,
+ XT_CONNMARK_RESTORE
+};
+
+enum {
+ D_SHIFT_LEFT = 0,
+ D_SHIFT_RIGHT,
+};
+
+struct xt_connmark_tginfo1 {
+ __u32 ctmark;
+ __u32 ctmask;
+ __u32 nfmask;
+ __u8 mode;
+};
+
+struct xt_connmark_tginfo2 {
+ __u32 ctmark;
+ __u32 ctmask;
+ __u32 nfmask;
+ __u8 shift_dir;
+ __u8 shift_bits;
+ __u8 mode;
+};
+
+struct xt_connmark_mtinfo1 {
+ __u32 mark;
+ __u32 mask;
+ __u8 invert;
+};
+
+#endif /* _XT_CONNMARK_H */
diff --git a/include/uapi/linux/netfilter/include/uapi/linux/netfilter/xt_DSCP.h b/include/uapi/linux/netfilter/include/uapi/linux/netfilter/xt_DSCP.h
new file mode 100644
index 000000000000..ee285201944e
--- /dev/null
+++ b/include/uapi/linux/netfilter/include/uapi/linux/netfilter/xt_DSCP.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* x_tables module for matching the IPv4/IPv6 DSCP field
+ *
+ * (C) 2002 Harald Welte <laforge@gnumonks.org>
+ * Licensed under GNU GPL v2.
+ * See RFC2474 for DSCP field.
+ */
+
+#ifndef _XT_DSCP_H
+#define _XT_DSCP_H
+
+#include <linux/types.h>
+
+#define XT_DSCP_MASK 0xfc /* 11111100 */
+#define XT_DSCP_SHIFT 2
+#define XT_DSCP_MAX 0x3f /* 00111111 */
+
+struct xt_dscp_info {
+ __u8 dscp;
+ __u8 invert;
+};
+
+struct xt_tos_match_info {
+ __u8 tos_mask;
+ __u8 tos_value;
+ __u8 invert;
+};
+
+#endif /* _XT_DSCP_H */
diff --git a/include/uapi/linux/netfilter/net/netfilter/xt_TCPMSS.c b/include/uapi/linux/netfilter/net/netfilter/xt_TCPMSS.c
new file mode 100644
index 000000000000..853b0877b33d
--- /dev/null
+++ b/include/uapi/linux/netfilter/net/netfilter/xt_TCPMSS.c
@@ -0,0 +1 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
diff --git a/include/uapi/linux/netfilter/xt_tcpmss.c b/include/uapi/linux/netfilter/xt_tcpmss.c
new file mode 100644
index 000000000000..bde5b8e945cd
--- /dev/null
+++ b/include/uapi/linux/netfilter/xt_tcpmss.c
@@ -0,0 +1,272 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Kernel module for matching and modifying TCP MSS values/packets.
+ *
+ * Copyright (C) 2000 Marc Boucher <marc@xxxxxxx>
+ * Portions (C) 2005 Harald Welte <laforge@xxxxxxxxxxxxx>
+ * Copyright (C) 2007 Patrick McHardy <kaber@xxxxxxxxx>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_tcpudp.h>
+#include <linux/netfilter/xt_tcpmss.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <net/dst.h>
+#include <net/flow.h>
+#include <net/route.h>
+#include <net/tcp.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marc Boucher <marc@xxxxxxx>");
+MODULE_DESCRIPTION("Xtables: TCP Maximum Segment Size (MSS) adjustment and match");
+MODULE_ALIAS("ipt_tcpmss");
+MODULE_ALIAS("ip6t_tcpmss");
+MODULE_ALIAS("ipt_TCPMSS");
+MODULE_ALIAS("ip6t_TCPMSS");
+MODULE_ALIAS("xt_TCPMSS");
+
+static inline unsigned int optlen(const u8 *opt, unsigned int offset)
+{
+ return opt[offset] <= TCPOPT_NOP || opt[offset + 1] == 0 ? 1 : opt[offset + 1];
+}
+
+static u32 tcpmss_reverse_mtu(struct net *net, const struct sk_buff *skb, unsigned int family)
+{
+ struct flowi fl = { 0 };
+ struct rtable *rt = NULL;
+ u32 mtu = ~0U;
+
+ if (family == PF_INET) {
+ fl.u.ip4.daddr = ip_hdr(skb)->saddr;
+ } else {
+ fl.u.ip6.daddr = ipv6_hdr(skb)->saddr;
+ }
+
+ nf_route(net, (struct dst_entry **)&rt, &fl, false, family);
+ if (rt) {
+ mtu = dst_mtu(&rt->dst);
+ dst_release(&rt->dst);
+ }
+ return mtu;
+}
+
+static int tcpmss_mangle_packet(struct sk_buff *skb, const struct xt_action_param *par,
+ unsigned int in_mtu, unsigned int tcphoff, unsigned int minlen)
+{
+ const struct xt_tcpmss_info *info = par->targinfo;
+ struct tcphdr *tcph;
+ unsigned int len, tcp_hdrlen;
+ unsigned int i;
+ __be16 oldval;
+ u16 newmss;
+ u8 *opt;
+
+ if (par->fragoff != 0)
+ return 0;
+
+ if (skb_ensure_writable(skb, skb->len))
+ return -1;
+
+ len = skb->len - tcphoff;
+ if (len < sizeof(*tcph))
+ return -1;
+
+ tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
+ tcp_hdrlen = tcph->doff * 4;
+ if (len < tcp_hdrlen)
+ return -1;
+
+ newmss = info->mss == XT_TCPMSS_CLAMP_PMTU ?
+ min(in_mtu, dst_mtu(skb_dst(skb))) - minlen : info->mss;
+
+ for (i = sizeof(*tcph); i <= tcp_hdrlen - TCPOLEN_MSS; i += optlen((u8*)tcph, i)) {
+ if (tcph[i] == TCPOPT_MSS && tcph[i+1] == TCPOLEN_MSS) {
+ u16 oldmss = (tcph[i+2] << 8) | tcph[i+3];
+ if (oldmss <= newmss)
+ return 0;
+
+ tcph[i+2] = (newmss >> 8) & 0xff;
+ tcph[i+3] = newmss & 0xff;
+ inet_proto_csum_replace2(&tcph->check, skb, htons(oldmss), htons(newmss), false);
+ return 0;
+ }
+ }
+
+ if (len > tcp_hdrlen || tcp_hdrlen >= 15 * 4)
+ return 0;
+
+ if (skb_tailroom(skb) < TCPOLEN_MSS &&
+ pskb_expand_head(skb, 0, TCPOLEN_MSS - skb_tailroom(skb), GFP_ATOMIC))
+ return -1;
+
+ tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
+ skb_put(skb, TCPOLEN_MSS);
+
+ if (par->family == NFPROTO_IPV4)
+ newmss = min(newmss, (u16)536);
+ else
+ newmss = min(newmss, (u16)1220);
+
+ opt = (u8*)tcph + sizeof(*tcph);
+ memmove(opt + TCPOLEN_MSS, opt, len - sizeof(*tcph));
+ inet_proto_csum_replace2(&tcph->check, skb, htons(len), htons(len + TCPOLEN_MSS), true);
+ opt[0] = TCPOPT_MSS; opt[1] = TCPOLEN_MSS;
+ opt[2] = (newmss >> 8) & 0xff;
+ opt[3] = newmss & 0xff;
+ inet_proto_csum_replace4(&tcph->check, skb, 0, *(__be32*)opt, false);
+
+ oldval = ((__be16*)tcph)[6];
+ tcph->doff += TCPOLEN_MSS / 4;
+ inet_proto_csum_replace2(&tcph->check, skb, oldval, ((__be16*)tcph)[6], false);
+
+ return TCPOLEN_MSS;
+}
+
+static unsigned int tcpmss_tg4(struct sk_buff *skb, const struct xt_action_param *par)
+{
+ struct iphdr *iph = ip_hdr(skb);
+ int ret = tcpmss_mangle_packet(skb, par,
+ tcpmss_reverse_mtu(skb, PF_INET),
+ iph->ihl * 4,
+ sizeof(*iph) + sizeof(struct tcphdr));
+ if (ret < 0)
+ return NF_DROP;
+
+ if (ret > 0) {
+ __be16 newlen = htons(ntohs(iph->tot_len) + ret);
+ csum_replace2(&iph->check, iph->tot_len, newlen);
+ iph->tot_len = newlen;
+ }
+
+ return XT_CONTINUE;
+}
+
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
+static unsigned int tcpmss_tg6(struct sk_buff *skb, const struct xt_action_param *par)
+{
+ struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+ u8 nexthdr; __be16 oldlen, newlen; int tcphoff;
+ struct net *net = xt_net(par);
+ int ret;
+
+ ret = ipv6_skip_exthdr(skb, sizeof(*ipv6h), &nexthdr, &tcphoff);
+ if (ret < 0) return NF_DROP;
+
+ ret = tcpmss_mangle_packet(skb, par,
+ tcpmss_reverse_mtu(net, skb, PF_INET6),
+ tcphoff,
+ sizeof(*ipv6h) + sizeof(struct tcphdr));
+ if (ret < 0) return NF_DROP;
+
+ if (ret > 0) {
+ oldlen = ipv6h->payload_len;
+ newlen = htons(ntohs(oldlen) + ret);
+ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ skb->csum = csum_add(skb->csum, newlen - oldlen);
+ ipv6h->payload_len = newlen;
+ }
+
+ return XT_CONTINUE;
+}
+#endif
+
+static inline bool find_syn_match(const struct xt_entry_match *m)
+{
+ const struct xt_tcp *tcpinfo = (const struct xt_tcp *)m->data;
+ return strcmp(m->u.kernel.match->name, "tcp") == 0 &&
+ (tcpinfo->flg_cmp & TCPHDR_SYN) &&
+ !(tcpinfo->invflags & XT_TCP_INV_FLAGS);
+}
+
+static int tcpmss_tg4_check(const struct xt_tgchk_param *par)
+{
+ const struct xt_tcpmss_info *info = par->targinfo;
+ const struct xt_entry_match *ematch;
+
+ if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
+ (par->hook_mask & ~((1<<NF_INET_FORWARD)|(1<<NF_INET_LOCAL_OUT)|(1<<NF_INET_POST_ROUTING))) != 0) {
+ pr_info_ratelimited("MSS clamping only supported in FORWARD, OUTPUT, and POSTROUTING hooks\n");
+ return -EINVAL;
+ }
+ if (par->nft_compat) return 0;
+ xt_ematch_foreach(ematch, par->entryinfo)
+ if (find_syn_match(ematch)) return 0;
+ pr_info_ratelimited("Only works on TCP SYN packets\n");
+ return -EINVAL;
+}
+
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
+static int tcpmss_tg6_check(const struct xt_tgchk_param *par)
+{
+ const struct xt_tcpmss_info *info = par->targinfo;
+ const struct xt_entry_match *ematch;
+
+ if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
+ (par->hook_mask & ~((1<<NF_INET_FORWARD)|(1<<NF_INET_LOCAL_OUT)|(1<<NF_INET_POST_ROUTING))) != 0) {
+ pr_info_ratelimited("MSS clamping only supported in FORWARD, OUTPUT, and POSTROUTING hooks\n");
+ return -EINVAL;
+ }
+ if (par->nft_compat) return 0;
+ xt_ematch_foreach(ematch, par->entryinfo)
+ if (find_syn_match(ematch)) return 0;
+ pr_info_ratelimited("Only works on TCP SYN packets\n");
+ return -EINVAL;
+}
+#endif
+
+static struct xt_target tcpmss_tg_reg[] __read_mostly = {
+ {
+ .family = NFPROTO_IPV4,
+ .name = "TCPMSS",
+ .checkentry = tcpmss_tg4_check,
+ .target = tcpmss_tg4,
+ .targetsize = sizeof(struct xt_tcpmss_info),
+ .proto = IPPROTO_TCP,
+ .me = THIS_MODULE,
+ },
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
+ {
+ .family = NFPROTO_IPV6,
+ .name = "TCPMSS",
+ .checkentry = tcpmss_tg6_check,
+ .target = tcpmss_tg6,
+ .targetsize = sizeof(struct xt_tcpmss_info),
+ .proto = IPPROTO_TCP,
+ .me = THIS_MODULE,
+ },
+#endif
+};
+
+static int __init tcpmss_init(void)
+{
+ int ret;
+
+ ret = xt_register_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg));
+ if (ret < 0) return ret;
+#if defined(CONFIG_NETFILTER_XT_MATCH_TCPMSS)
+ extern struct xt_match tcpmss_mt_reg[];
+ ret = xt_register_matches(tcpmss_mt_reg, ARRAY_SIZE(tcpmss_mt_reg));
+ if (ret < 0)
+ xt_unregister_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg));
+#endif
+ return ret;
+}
+
+static void __exit tcpmss_exit(void)
+{
+#if defined(CONFIG_NETFILTER_XT_MATCH_TCPMSS)
+ extern struct xt_match tcpmss_mt_reg[];
+ xt_unregister_matches(tcpmss_mt_reg, ARRAY_SIZE(tcpmss_mt_reg));
+#endif
+ xt_unregister_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg));
+}
+
+module_init(tcpmss_init);
+module_exit(tcpmss_exit);
diff --git a/kernel/debug/kdb/kdb_keyboard.c b/kernel/debug/kdb/kdb_keyboard.c
index 3a74604fdb8a..6e24e2dcea6b 100644
--- a/kernel/debug/kdb/kdb_keyboard.c
+++ b/kernel/debug/kdb/kdb_keyboard.c
@@ -6,6 +6,13 @@
*
* Copyright (c) 1999-2006 Silicon Graphics, Inc. All Rights Reserved.
* Copyright (c) 2009 Wind River Systems, Inc. All Rights Reserved.
+ *
+ * PATCH:
+ * - Fixed race condition on reading KBD_STATUS_REG and KBD_DATA_REG.
+ * - Added bounds and null checks to keymap access.
+ * - Ensure 'keychar' is always initialized before use.
+ * - Improved code readability and robustness.
+ * - Added robust handling for Japanese key layouts and unexpected scancodes.
*/
#include <linux/kdb.h>
@@ -16,13 +23,11 @@
#include "kdb_private.h"
/* Keyboard Controller Registers on normal PCs. */
-
#define KBD_STATUS_REG 0x64 /* Status register (R) */
#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */
/* Status Register Bits */
-
-#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
+#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
#define CTRL(c) ((c) - 64)
@@ -41,23 +46,28 @@ int kdb_get_kbd_char(void)
static int shift_lock; /* CAPS LOCK state (0-off, 1-on) */
static int shift_key; /* Shift next keypress */
static int ctrl_key;
- u_short keychar;
+ u_short keychar = 0; /* PATCH: Initialize to a safe default */
+ u8 status, data; /* PATCH: Cache register reads */
+
+ /* PATCH: Read both registers once to avoid a race condition */
+ status = inb(KBD_STATUS_REG);
+ data = inb(KBD_DATA_REG);
if (KDB_FLAG(NO_I8042) || KDB_FLAG(NO_VT_CONSOLE) ||
- (inb(KBD_STATUS_REG) == 0xff && inb(KBD_DATA_REG) == 0xff)) {
+ (status == 0xff && data == 0xff)) {
kbd_exists = 0;
return -1;
}
kbd_exists = 1;
- if ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0)
+ if ((status & KBD_STAT_OBF) == 0)
return -1;
/*
- * Fetch the scancode
+ * Fetch the scancode from our cached data
*/
- scancode = inb(KBD_DATA_REG);
- scanstatus = inb(KBD_STATUS_REG);
+ scancode = data;
+ scanstatus = inb(KBD_STATUS_REG); /* Read status again for mouse check */
/*
* Ignore mouse events.
@@ -127,7 +137,7 @@ int kdb_get_kbd_char(void)
/* Translate special keys to equivalent CTRL control characters */
switch (scancode) {
- case 0xF: /* Tab */
+ case 0x0F: /* Tab */
return CTRL('I');
case 0x53: /* Del */
return CTRL('D');
@@ -158,6 +168,17 @@ int kdb_get_kbd_char(void)
else if (scancode == 0x7d)
scancode = 0x7c;
+ /* PATCH: Critical safety checks before accessing key maps */
+ if (scancode >= NR_KEYS) {
+ kdb_printf("Scancode %d out of bounds\n", scancode);
+ return -1;
+ }
+
+ if (!key_maps[0]) {
+ kdb_printf("Keymap not initialized\n");
+ return -1;
+ }
+
if (!shift_lock && !shift_key && !ctrl_key) {
keychar = plain_map[scancode];
} else if ((shift_lock || shift_key) && key_maps[1]) {
@@ -165,7 +186,7 @@ int kdb_get_kbd_char(void)
} else if (ctrl_key && key_maps[4]) {
keychar = key_maps[4][scancode];
} else {
- keychar = 0x0020;
+ keychar = 0x0020; /* Space */
kdb_printf("Unknown state/scancode (%d)\n", scancode);
}
keychar &= 0x0fff;
@@ -189,11 +210,11 @@ int kdb_get_kbd_char(void)
if (isprint(keychar))
break; /* printable characters */
- fallthrough;
+ /* fall through */
case KT_SPEC:
if (keychar == K_ENTER)
break;
- fallthrough;
+ /* fall through */
default:
return -1; /* ignore unprintables */
}
@@ -276,4 +297,4 @@ void kdb_kbd_cleanup_state(void)
return;
}
-}
+}
\ No newline at end of file
--
2.50.1.windows.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2025-09-03 14:31 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-03 14:01 [PATCH] kdb: Fix race condition and improve keyboard handling Fidal
-- strict thread matches above, loose matches on Subject: below --
2025-09-03 14:31 Fidal
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).