linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [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:31 [PATCH] kdb: Fix race condition and improve keyboard handling Fidal
  -- strict thread matches above, loose matches on Subject: below --
2025-09-03 14:01 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).