public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH v2] [RISC-V] Add support for TLS stack protector canary access
@ 2020-07-13  8:15 cooper
  2020-07-20  2:03 ` cooper
  0 siblings, 1 reply; 7+ messages in thread
From: cooper @ 2020-07-13  8:15 UTC (permalink / raw)
  To: gcc-patches, jimw; +Cc: guoren, cooper

gcc/
	* config/riscv/riscv-opts.h (stack_protector_guard): New enum.
	* config/riscv/riscv.c (riscv_option_override): Handle
	the new options.
	* config/riscv/riscv.md (stack_protect_set): New pattern to handle
	flexible stack protector guard settings.
	(stack_protect_set_<mode>): Ditto.
	(stack_protect_test): Ditto.
	(stack_protect_test_<mode>): Ditto.
	* config/riscv/riscv.opt (mstack-protector-guard=,
	mstack-protector-guard-reg=, mstack-protector-guard-offset=): New
	options.
	* doc/invoke.texi (Option Summary) [RISC-V Options]:
	Add -mstack-protector-guard=, -mstack-protector-guard-reg=, and
	-mstack-protector-guard-offset=.
	(RISC-V Options): Ditto.

Signed-off-by: cooper <cooper.qu@linux.alibaba.com>
Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
---
 gcc/config/riscv/riscv-opts.h |  6 +++
 gcc/config/riscv/riscv.c      | 47 ++++++++++++++++++++
 gcc/config/riscv/riscv.md     | 80 +++++++++++++++++++++++++++++++++++
 gcc/config/riscv/riscv.opt    | 28 ++++++++++++
 gcc/doc/invoke.texi           | 22 +++++++++-
 5 files changed, 182 insertions(+), 1 deletion(-)

diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h
index 8f12e50b9f1..2a3f9d9eef5 100644
--- a/gcc/config/riscv/riscv-opts.h
+++ b/gcc/config/riscv/riscv-opts.h
@@ -51,4 +51,10 @@ enum riscv_align_data {
   riscv_align_data_type_natural
 };
 
+/* Where to get the canary for the stack protector.  */
+enum stack_protector_guard {
+  SSP_TLS,			/* per-thread canary in TLS block */
+  SSP_GLOBAL			/* global canary */
+};
+
 #endif /* ! GCC_RISCV_OPTS_H */
diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c
index bfb3885ed08..63b0c3877b0 100644
--- a/gcc/config/riscv/riscv.c
+++ b/gcc/config/riscv/riscv.c
@@ -4775,6 +4775,53 @@ riscv_option_override (void)
 	   " [%<-mriscv-attribute%>]");
 #endif
 
+  if (riscv_stack_protector_guard == SSP_GLOBAL
+      && global_options_set.x_riscv_stack_protector_guard_offset_str)
+    {
+      error ("incompatible options %<-mstack-protector-guard=global%> and "
+	     "%<-mstack-protector-guard-offset=%s%>",
+	     riscv_stack_protector_guard_offset_str);
+    }
+
+  if (riscv_stack_protector_guard == SSP_TLS
+      && !(global_options_set.x_riscv_stack_protector_guard_offset_str
+	   && global_options_set.x_riscv_stack_protector_guard_reg_str))
+    {
+      error ("both %<-mstack-protector-guard-offset%> and "
+	     "%<-mstack-protector-guard-reg%> must be used "
+	     "with %<-mstack-protector-guard=sysreg%>");
+    }
+
+  if (global_options_set.x_riscv_stack_protector_guard_reg_str)
+    {
+      const char *str = riscv_stack_protector_guard_reg_str;
+      int reg = decode_reg_name (str);
+
+      if (!IN_RANGE (reg, GP_REG_FIRST + 1, GP_REG_LAST))
+	error ("%qs is not a valid base register in %qs", str,
+	       "-mstack-protector-guard-reg=");
+
+      riscv_stack_protector_guard_reg = reg;
+    }
+
+  if (global_options_set.x_riscv_stack_protector_guard_offset_str)
+    {
+      char *end;
+      const char *str = riscv_stack_protector_guard_offset_str;
+      errno = 0;
+      long offs = strtol (riscv_stack_protector_guard_offset_str, &end, 0);
+
+      if (!*str || *end || errno)
+	error ("%qs is not a valid number in %qs", str,
+	       "-mstack-protector-guard-offset=");
+
+      if (!SMALL_OPERAND (offs))
+	error ("%qs is not a valid offset in %qs", str,
+	       "-mstack-protector-guard-offset=");
+
+      riscv_stack_protector_guard_offset = offs;
+    }
+
 }
 
 /* Implement TARGET_CONDITIONAL_REGISTER_USAGE.  */
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 95a02ecaa34..f15bad3b29e 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -65,6 +65,10 @@
   UNSPECV_BLOCKAGE
   UNSPECV_FENCE
   UNSPECV_FENCE_I
+
+  ;; Stack Smash Protector
+  UNSPEC_SSP_SET
+  UNSPEC_SSP_TEST
 ])
 
 (define_constants
@@ -2523,6 +2527,82 @@
   ""
 {})
 
+;; Named patterns for stack smashing protection.
+
+(define_expand "stack_protect_set"
+  [(match_operand 0 "memory_operand")
+   (match_operand 1 "memory_operand")]
+  ""
+{
+  machine_mode mode = GET_MODE (operands[0]);
+  if (riscv_stack_protector_guard == SSP_TLS)
+  {
+    rtx reg = gen_rtx_REG (Pmode, riscv_stack_protector_guard_reg);
+    rtx offset = GEN_INT (riscv_stack_protector_guard_offset);
+    rtx addr = gen_rtx_PLUS (Pmode, reg, offset);
+    operands[1] = gen_rtx_MEM (Pmode, addr);
+  }
+
+  emit_insn ((mode == DImode
+	      ? gen_stack_protect_set_di
+	      : gen_stack_protect_set_si) (operands[0], operands[1]));
+  DONE;
+})
+
+;; DO NOT SPLIT THIS PATTERN.  It is important for security reasons that the
+;; canary value does not live beyond the life of this sequence.
+(define_insn "stack_protect_set_<mode>"
+  [(set (match_operand:GPR 0 "memory_operand" "=m")
+	(unspec:GPR [(match_operand:GPR 1 "memory_operand" "m")]
+	 UNSPEC_SSP_SET))
+   (set (match_scratch:GPR 2 "=&r") (const_int 0))]
+  ""
+  "<load>\\t%2, %1\;<store>\\t%2, %0\;li\t%2, 0"
+  [(set_attr "length" "12")])
+
+(define_expand "stack_protect_test"
+  [(match_operand 0 "memory_operand")
+   (match_operand 1 "memory_operand")
+   (match_operand 2)]
+  ""
+{
+  rtx result;
+  machine_mode mode = GET_MODE (operands[0]);
+
+  result = gen_reg_rtx(mode);
+  if (riscv_stack_protector_guard == SSP_TLS)
+  {
+      rtx reg = gen_rtx_REG (Pmode, riscv_stack_protector_guard_reg);
+      rtx offset = GEN_INT (riscv_stack_protector_guard_offset);
+      rtx addr = gen_rtx_PLUS (Pmode, reg, offset);
+      operands[1] = gen_rtx_MEM (Pmode, addr);
+  }
+  emit_insn ((mode == DImode
+		  ? gen_stack_protect_test_di
+		  : gen_stack_protect_test_si) (result,
+					        operands[0],
+					        operands[1]));
+
+  if (mode == DImode)
+    emit_jump_insn (gen_cbranchdi4 (gen_rtx_EQ (VOIDmode, result, const0_rtx),
+				    result, const0_rtx, operands[2]));
+  else
+    emit_jump_insn (gen_cbranchsi4 (gen_rtx_EQ (VOIDmode, result, const0_rtx),
+				    result, const0_rtx, operands[2]));
+
+  DONE;
+})
+
+(define_insn "stack_protect_test_<mode>"
+  [(set (match_operand:GPR 0 "register_operand" "=r")
+	(unspec:GPR [(match_operand:GPR 1 "memory_operand" "m")
+		     (match_operand:GPR 2 "memory_operand" "m")]
+	 UNSPEC_SSP_TEST))
+   (clobber (match_scratch:GPR 3 "=&r"))]
+  ""
+  "<load>\t%3, %1\;<load>\t%0, %2\;xor\t%0, %3, %0\;li\t%3, 0"
+  [(set_attr "length" "12")])
+
 (include "sync.md")
 (include "peephole.md")
 (include "pic.md")
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index e4bfcb86f51..f01d3ab79c3 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -151,3 +151,31 @@ Enum(riscv_align_data) String(xlen) Value(riscv_align_data_type_xlen)
 
 EnumValue
 Enum(riscv_align_data) String(natural) Value(riscv_align_data_type_natural)
+
+mstack-protector-guard=
+Target RejectNegative Joined Enum(stack_protector_guard) Var(riscv_stack_protector_guard) Init(SSP_GLOBAL)
+Use given stack-protector guard.
+
+Enum
+Name(stack_protector_guard) Type(enum stack_protector_guard)
+Valid arguments to -mstack-protector-guard=:
+
+EnumValue
+Enum(stack_protector_guard) String(tls) Value(SSP_TLS)
+
+EnumValue
+Enum(stack_protector_guard) String(global) Value(SSP_GLOBAL)
+
+mstack-protector-guard-reg=
+Target RejectNegative Joined Var(riscv_stack_protector_guard_reg_str)
+Use the given base register for addressing the stack-protector guard.
+
+TargetVariable
+int riscv_stack_protector_guard_reg = 0
+
+mstack-protector-guard-offset=
+Target RejectNegative Joined Integer Var(riscv_stack_protector_guard_offset_str)
+Use the given offset for addressing the stack-protector guard.
+
+TargetVariable
+long riscv_stack_protector_guard_offset = 0
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 09bcc5b0f78..3bb124ae6ed 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -1138,7 +1138,9 @@ See RS/6000 and PowerPC Options.
 -mexplicit-relocs  -mno-explicit-relocs @gol
 -mrelax  -mno-relax @gol
 -mriscv-attribute  -mmo-riscv-attribute @gol
--malign-data=@var{type}}
+-malign-data=@var{type} @gol
++-mstack-protector-guard=@var{guard} -mstack-protector-guard-reg=@var{reg} @gol
++-mstack-protector-guard-offset=@var{offset}}
 
 @emph{RL78 Options}
 @gccoptlist{-msim  -mmul=none  -mmul=g13  -mmul=g14  -mallregs @gol
@@ -25723,6 +25725,24 @@ Control how GCC aligns variables and constants of array, structure, or union
 types.  Supported values for @var{type} are @samp{xlen} which uses x register
 width as the alignment value, and @samp{natural} which uses natural alignment.
 @samp{xlen} is the default.
+
+@item -mstack-protector-guard=@var{guard}
+@itemx -mstack-protector-guard-reg=@var{reg}
+@itemx -mstack-protector-guard-offset=@var{offset}
+@opindex mstack-protector-guard
+@opindex mstack-protector-guard-reg
+@opindex mstack-protector-guard-offset
+Generate stack protection code using canary at @var{guard}.  Supported
+locations are @samp{global} for a global canary or @samp{tls} for per-thread
+canary in the TLS block.
+
+With the latter choice the options
+@option{-mstack-protector-guard-reg=@var{reg}} and
+@option{-mstack-protector-guard-offset=@var{offset}} furthermore specify
+which register to use as base register for reading the canary,
+and from what offset from that base register. There is no default
+register or offset as this is entirely for use within the Linux
+kernel.
 @end table
 
 @node RL78 Options
-- 
2.26.2


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] [RISC-V] Add support for TLS stack protector canary access
  2020-07-13  8:15 [PATCH v2] [RISC-V] Add support for TLS stack protector canary access cooper
@ 2020-07-20  2:03 ` cooper
  2020-07-21  8:14   ` Kito Cheng
  2020-07-27 22:54   ` Jim Wilson
  0 siblings, 2 replies; 7+ messages in thread
From: cooper @ 2020-07-20  2:03 UTC (permalink / raw)
  To: gcc-patches, jimw; +Cc: guoren

Ping

On 2020/7/13 下午4:15, cooper wrote:
> gcc/
> 	* config/riscv/riscv-opts.h (stack_protector_guard): New enum.
> 	* config/riscv/riscv.c (riscv_option_override): Handle
> 	the new options.
> 	* config/riscv/riscv.md (stack_protect_set): New pattern to handle
> 	flexible stack protector guard settings.
> 	(stack_protect_set_<mode>): Ditto.
> 	(stack_protect_test): Ditto.
> 	(stack_protect_test_<mode>): Ditto.
> 	* config/riscv/riscv.opt (mstack-protector-guard=,
> 	mstack-protector-guard-reg=, mstack-protector-guard-offset=): New
> 	options.
> 	* doc/invoke.texi (Option Summary) [RISC-V Options]:
> 	Add -mstack-protector-guard=, -mstack-protector-guard-reg=, and
> 	-mstack-protector-guard-offset=.
> 	(RISC-V Options): Ditto.
>
> Signed-off-by: cooper <cooper.qu@linux.alibaba.com>
> Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
> ---
>   gcc/config/riscv/riscv-opts.h |  6 +++
>   gcc/config/riscv/riscv.c      | 47 ++++++++++++++++++++
>   gcc/config/riscv/riscv.md     | 80 +++++++++++++++++++++++++++++++++++
>   gcc/config/riscv/riscv.opt    | 28 ++++++++++++
>   gcc/doc/invoke.texi           | 22 +++++++++-
>   5 files changed, 182 insertions(+), 1 deletion(-)
>
> diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h
> index 8f12e50b9f1..2a3f9d9eef5 100644
> --- a/gcc/config/riscv/riscv-opts.h
> +++ b/gcc/config/riscv/riscv-opts.h
> @@ -51,4 +51,10 @@ enum riscv_align_data {
>     riscv_align_data_type_natural
>   };
>   
> +/* Where to get the canary for the stack protector.  */
> +enum stack_protector_guard {
> +  SSP_TLS,			/* per-thread canary in TLS block */
> +  SSP_GLOBAL			/* global canary */
> +};
> +
>   #endif /* ! GCC_RISCV_OPTS_H */
> diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c
> index bfb3885ed08..63b0c3877b0 100644
> --- a/gcc/config/riscv/riscv.c
> +++ b/gcc/config/riscv/riscv.c
> @@ -4775,6 +4775,53 @@ riscv_option_override (void)
>   	   " [%<-mriscv-attribute%>]");
>   #endif
>   
> +  if (riscv_stack_protector_guard == SSP_GLOBAL
> +      && global_options_set.x_riscv_stack_protector_guard_offset_str)
> +    {
> +      error ("incompatible options %<-mstack-protector-guard=global%> and "
> +	     "%<-mstack-protector-guard-offset=%s%>",
> +	     riscv_stack_protector_guard_offset_str);
> +    }
> +
> +  if (riscv_stack_protector_guard == SSP_TLS
> +      && !(global_options_set.x_riscv_stack_protector_guard_offset_str
> +	   && global_options_set.x_riscv_stack_protector_guard_reg_str))
> +    {
> +      error ("both %<-mstack-protector-guard-offset%> and "
> +	     "%<-mstack-protector-guard-reg%> must be used "
> +	     "with %<-mstack-protector-guard=sysreg%>");
> +    }
> +
> +  if (global_options_set.x_riscv_stack_protector_guard_reg_str)
> +    {
> +      const char *str = riscv_stack_protector_guard_reg_str;
> +      int reg = decode_reg_name (str);
> +
> +      if (!IN_RANGE (reg, GP_REG_FIRST + 1, GP_REG_LAST))
> +	error ("%qs is not a valid base register in %qs", str,
> +	       "-mstack-protector-guard-reg=");
> +
> +      riscv_stack_protector_guard_reg = reg;
> +    }
> +
> +  if (global_options_set.x_riscv_stack_protector_guard_offset_str)
> +    {
> +      char *end;
> +      const char *str = riscv_stack_protector_guard_offset_str;
> +      errno = 0;
> +      long offs = strtol (riscv_stack_protector_guard_offset_str, &end, 0);
> +
> +      if (!*str || *end || errno)
> +	error ("%qs is not a valid number in %qs", str,
> +	       "-mstack-protector-guard-offset=");
> +
> +      if (!SMALL_OPERAND (offs))
> +	error ("%qs is not a valid offset in %qs", str,
> +	       "-mstack-protector-guard-offset=");
> +
> +      riscv_stack_protector_guard_offset = offs;
> +    }
> +
>   }
>   
>   /* Implement TARGET_CONDITIONAL_REGISTER_USAGE.  */
> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> index 95a02ecaa34..f15bad3b29e 100644
> --- a/gcc/config/riscv/riscv.md
> +++ b/gcc/config/riscv/riscv.md
> @@ -65,6 +65,10 @@
>     UNSPECV_BLOCKAGE
>     UNSPECV_FENCE
>     UNSPECV_FENCE_I
> +
> +  ;; Stack Smash Protector
> +  UNSPEC_SSP_SET
> +  UNSPEC_SSP_TEST
>   ])
>   
>   (define_constants
> @@ -2523,6 +2527,82 @@
>     ""
>   {})
>   
> +;; Named patterns for stack smashing protection.
> +
> +(define_expand "stack_protect_set"
> +  [(match_operand 0 "memory_operand")
> +   (match_operand 1 "memory_operand")]
> +  ""
> +{
> +  machine_mode mode = GET_MODE (operands[0]);
> +  if (riscv_stack_protector_guard == SSP_TLS)
> +  {
> +    rtx reg = gen_rtx_REG (Pmode, riscv_stack_protector_guard_reg);
> +    rtx offset = GEN_INT (riscv_stack_protector_guard_offset);
> +    rtx addr = gen_rtx_PLUS (Pmode, reg, offset);
> +    operands[1] = gen_rtx_MEM (Pmode, addr);
> +  }
> +
> +  emit_insn ((mode == DImode
> +	      ? gen_stack_protect_set_di
> +	      : gen_stack_protect_set_si) (operands[0], operands[1]));
> +  DONE;
> +})
> +
> +;; DO NOT SPLIT THIS PATTERN.  It is important for security reasons that the
> +;; canary value does not live beyond the life of this sequence.
> +(define_insn "stack_protect_set_<mode>"
> +  [(set (match_operand:GPR 0 "memory_operand" "=m")
> +	(unspec:GPR [(match_operand:GPR 1 "memory_operand" "m")]
> +	 UNSPEC_SSP_SET))
> +   (set (match_scratch:GPR 2 "=&r") (const_int 0))]
> +  ""
> +  "<load>\\t%2, %1\;<store>\\t%2, %0\;li\t%2, 0"
> +  [(set_attr "length" "12")])
> +
> +(define_expand "stack_protect_test"
> +  [(match_operand 0 "memory_operand")
> +   (match_operand 1 "memory_operand")
> +   (match_operand 2)]
> +  ""
> +{
> +  rtx result;
> +  machine_mode mode = GET_MODE (operands[0]);
> +
> +  result = gen_reg_rtx(mode);
> +  if (riscv_stack_protector_guard == SSP_TLS)
> +  {
> +      rtx reg = gen_rtx_REG (Pmode, riscv_stack_protector_guard_reg);
> +      rtx offset = GEN_INT (riscv_stack_protector_guard_offset);
> +      rtx addr = gen_rtx_PLUS (Pmode, reg, offset);
> +      operands[1] = gen_rtx_MEM (Pmode, addr);
> +  }
> +  emit_insn ((mode == DImode
> +		  ? gen_stack_protect_test_di
> +		  : gen_stack_protect_test_si) (result,
> +					        operands[0],
> +					        operands[1]));
> +
> +  if (mode == DImode)
> +    emit_jump_insn (gen_cbranchdi4 (gen_rtx_EQ (VOIDmode, result, const0_rtx),
> +				    result, const0_rtx, operands[2]));
> +  else
> +    emit_jump_insn (gen_cbranchsi4 (gen_rtx_EQ (VOIDmode, result, const0_rtx),
> +				    result, const0_rtx, operands[2]));
> +
> +  DONE;
> +})
> +
> +(define_insn "stack_protect_test_<mode>"
> +  [(set (match_operand:GPR 0 "register_operand" "=r")
> +	(unspec:GPR [(match_operand:GPR 1 "memory_operand" "m")
> +		     (match_operand:GPR 2 "memory_operand" "m")]
> +	 UNSPEC_SSP_TEST))
> +   (clobber (match_scratch:GPR 3 "=&r"))]
> +  ""
> +  "<load>\t%3, %1\;<load>\t%0, %2\;xor\t%0, %3, %0\;li\t%3, 0"
> +  [(set_attr "length" "12")])
> +
>   (include "sync.md")
>   (include "peephole.md")
>   (include "pic.md")
> diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
> index e4bfcb86f51..f01d3ab79c3 100644
> --- a/gcc/config/riscv/riscv.opt
> +++ b/gcc/config/riscv/riscv.opt
> @@ -151,3 +151,31 @@ Enum(riscv_align_data) String(xlen) Value(riscv_align_data_type_xlen)
>   
>   EnumValue
>   Enum(riscv_align_data) String(natural) Value(riscv_align_data_type_natural)
> +
> +mstack-protector-guard=
> +Target RejectNegative Joined Enum(stack_protector_guard) Var(riscv_stack_protector_guard) Init(SSP_GLOBAL)
> +Use given stack-protector guard.
> +
> +Enum
> +Name(stack_protector_guard) Type(enum stack_protector_guard)
> +Valid arguments to -mstack-protector-guard=:
> +
> +EnumValue
> +Enum(stack_protector_guard) String(tls) Value(SSP_TLS)
> +
> +EnumValue
> +Enum(stack_protector_guard) String(global) Value(SSP_GLOBAL)
> +
> +mstack-protector-guard-reg=
> +Target RejectNegative Joined Var(riscv_stack_protector_guard_reg_str)
> +Use the given base register for addressing the stack-protector guard.
> +
> +TargetVariable
> +int riscv_stack_protector_guard_reg = 0
> +
> +mstack-protector-guard-offset=
> +Target RejectNegative Joined Integer Var(riscv_stack_protector_guard_offset_str)
> +Use the given offset for addressing the stack-protector guard.
> +
> +TargetVariable
> +long riscv_stack_protector_guard_offset = 0
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 09bcc5b0f78..3bb124ae6ed 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -1138,7 +1138,9 @@ See RS/6000 and PowerPC Options.
>   -mexplicit-relocs  -mno-explicit-relocs @gol
>   -mrelax  -mno-relax @gol
>   -mriscv-attribute  -mmo-riscv-attribute @gol
> --malign-data=@var{type}}
> +-malign-data=@var{type} @gol
> ++-mstack-protector-guard=@var{guard} -mstack-protector-guard-reg=@var{reg} @gol
> ++-mstack-protector-guard-offset=@var{offset}}
>   
>   @emph{RL78 Options}
>   @gccoptlist{-msim  -mmul=none  -mmul=g13  -mmul=g14  -mallregs @gol
> @@ -25723,6 +25725,24 @@ Control how GCC aligns variables and constants of array, structure, or union
>   types.  Supported values for @var{type} are @samp{xlen} which uses x register
>   width as the alignment value, and @samp{natural} which uses natural alignment.
>   @samp{xlen} is the default.
> +
> +@item -mstack-protector-guard=@var{guard}
> +@itemx -mstack-protector-guard-reg=@var{reg}
> +@itemx -mstack-protector-guard-offset=@var{offset}
> +@opindex mstack-protector-guard
> +@opindex mstack-protector-guard-reg
> +@opindex mstack-protector-guard-offset
> +Generate stack protection code using canary at @var{guard}.  Supported
> +locations are @samp{global} for a global canary or @samp{tls} for per-thread
> +canary in the TLS block.
> +
> +With the latter choice the options
> +@option{-mstack-protector-guard-reg=@var{reg}} and
> +@option{-mstack-protector-guard-offset=@var{offset}} furthermore specify
> +which register to use as base register for reading the canary,
> +and from what offset from that base register. There is no default
> +register or offset as this is entirely for use within the Linux
> +kernel.
>   @end table
>   
>   @node RL78 Options

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] [RISC-V] Add support for TLS stack protector canary access
  2020-07-20  2:03 ` cooper
@ 2020-07-21  8:14   ` Kito Cheng
  2020-07-27 22:54   ` Jim Wilson
  1 sibling, 0 replies; 7+ messages in thread
From: Kito Cheng @ 2020-07-21  8:14 UTC (permalink / raw)
  To: cooper; +Cc: GCC Patches, Jim Wilson, guoren

Hi Cooper:

Could you add testcases like ppc[3-4]?

[3] https://github.com/gcc-mirror/gcc/blob/master/gcc/testsuite/gcc.target/powerpc/ssp-1.c
[4] https://github.com/gcc-mirror/gcc/blob/master/gcc/testsuite/gcc.target/powerpc/ssp-2.c

On Mon, Jul 20, 2020 at 10:04 AM cooper via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> Ping
>
> On 2020/7/13 下午4:15, cooper wrote:
> > gcc/
> >       * config/riscv/riscv-opts.h (stack_protector_guard): New enum.
> >       * config/riscv/riscv.c (riscv_option_override): Handle
> >       the new options.
> >       * config/riscv/riscv.md (stack_protect_set): New pattern to handle
> >       flexible stack protector guard settings.
> >       (stack_protect_set_<mode>): Ditto.
> >       (stack_protect_test): Ditto.
> >       (stack_protect_test_<mode>): Ditto.
> >       * config/riscv/riscv.opt (mstack-protector-guard=,
> >       mstack-protector-guard-reg=, mstack-protector-guard-offset=): New
> >       options.
> >       * doc/invoke.texi (Option Summary) [RISC-V Options]:
> >       Add -mstack-protector-guard=, -mstack-protector-guard-reg=, and
> >       -mstack-protector-guard-offset=.
> >       (RISC-V Options): Ditto.
> >
> > Signed-off-by: cooper <cooper.qu@linux.alibaba.com>
> > Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
> > ---
> >   gcc/config/riscv/riscv-opts.h |  6 +++
> >   gcc/config/riscv/riscv.c      | 47 ++++++++++++++++++++
> >   gcc/config/riscv/riscv.md     | 80 +++++++++++++++++++++++++++++++++++
> >   gcc/config/riscv/riscv.opt    | 28 ++++++++++++
> >   gcc/doc/invoke.texi           | 22 +++++++++-
> >   5 files changed, 182 insertions(+), 1 deletion(-)
> >
> > diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h
> > index 8f12e50b9f1..2a3f9d9eef5 100644
> > --- a/gcc/config/riscv/riscv-opts.h
> > +++ b/gcc/config/riscv/riscv-opts.h
> > @@ -51,4 +51,10 @@ enum riscv_align_data {
> >     riscv_align_data_type_natural
> >   };
> >
> > +/* Where to get the canary for the stack protector.  */
> > +enum stack_protector_guard {
> > +  SSP_TLS,                   /* per-thread canary in TLS block */
> > +  SSP_GLOBAL                 /* global canary */
> > +};
> > +
> >   #endif /* ! GCC_RISCV_OPTS_H */
> > diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c
> > index bfb3885ed08..63b0c3877b0 100644
> > --- a/gcc/config/riscv/riscv.c
> > +++ b/gcc/config/riscv/riscv.c
> > @@ -4775,6 +4775,53 @@ riscv_option_override (void)
> >          " [%<-mriscv-attribute%>]");
> >   #endif
> >
> > +  if (riscv_stack_protector_guard == SSP_GLOBAL
> > +      && global_options_set.x_riscv_stack_protector_guard_offset_str)
> > +    {
> > +      error ("incompatible options %<-mstack-protector-guard=global%> and "
> > +          "%<-mstack-protector-guard-offset=%s%>",
> > +          riscv_stack_protector_guard_offset_str);
> > +    }
> > +
> > +  if (riscv_stack_protector_guard == SSP_TLS
> > +      && !(global_options_set.x_riscv_stack_protector_guard_offset_str
> > +        && global_options_set.x_riscv_stack_protector_guard_reg_str))
> > +    {
> > +      error ("both %<-mstack-protector-guard-offset%> and "
> > +          "%<-mstack-protector-guard-reg%> must be used "
> > +          "with %<-mstack-protector-guard=sysreg%>");
> > +    }
> > +
> > +  if (global_options_set.x_riscv_stack_protector_guard_reg_str)
> > +    {
> > +      const char *str = riscv_stack_protector_guard_reg_str;
> > +      int reg = decode_reg_name (str);
> > +
> > +      if (!IN_RANGE (reg, GP_REG_FIRST + 1, GP_REG_LAST))
> > +     error ("%qs is not a valid base register in %qs", str,
> > +            "-mstack-protector-guard-reg=");
> > +
> > +      riscv_stack_protector_guard_reg = reg;
> > +    }
> > +
> > +  if (global_options_set.x_riscv_stack_protector_guard_offset_str)
> > +    {
> > +      char *end;
> > +      const char *str = riscv_stack_protector_guard_offset_str;
> > +      errno = 0;
> > +      long offs = strtol (riscv_stack_protector_guard_offset_str, &end, 0);
> > +
> > +      if (!*str || *end || errno)
> > +     error ("%qs is not a valid number in %qs", str,
> > +            "-mstack-protector-guard-offset=");
> > +
> > +      if (!SMALL_OPERAND (offs))
> > +     error ("%qs is not a valid offset in %qs", str,
> > +            "-mstack-protector-guard-offset=");
> > +
> > +      riscv_stack_protector_guard_offset = offs;
> > +    }
> > +
> >   }
> >
> >   /* Implement TARGET_CONDITIONAL_REGISTER_USAGE.  */
> > diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> > index 95a02ecaa34..f15bad3b29e 100644
> > --- a/gcc/config/riscv/riscv.md
> > +++ b/gcc/config/riscv/riscv.md
> > @@ -65,6 +65,10 @@
> >     UNSPECV_BLOCKAGE
> >     UNSPECV_FENCE
> >     UNSPECV_FENCE_I
> > +
> > +  ;; Stack Smash Protector
> > +  UNSPEC_SSP_SET
> > +  UNSPEC_SSP_TEST
> >   ])
> >
> >   (define_constants
> > @@ -2523,6 +2527,82 @@
> >     ""
> >   {})
> >
> > +;; Named patterns for stack smashing protection.
> > +
> > +(define_expand "stack_protect_set"
> > +  [(match_operand 0 "memory_operand")
> > +   (match_operand 1 "memory_operand")]
> > +  ""
> > +{
> > +  machine_mode mode = GET_MODE (operands[0]);
> > +  if (riscv_stack_protector_guard == SSP_TLS)
> > +  {
> > +    rtx reg = gen_rtx_REG (Pmode, riscv_stack_protector_guard_reg);
> > +    rtx offset = GEN_INT (riscv_stack_protector_guard_offset);
> > +    rtx addr = gen_rtx_PLUS (Pmode, reg, offset);
> > +    operands[1] = gen_rtx_MEM (Pmode, addr);
> > +  }
> > +
> > +  emit_insn ((mode == DImode
> > +           ? gen_stack_protect_set_di
> > +           : gen_stack_protect_set_si) (operands[0], operands[1]));
> > +  DONE;
> > +})
> > +
> > +;; DO NOT SPLIT THIS PATTERN.  It is important for security reasons that the
> > +;; canary value does not live beyond the life of this sequence.
> > +(define_insn "stack_protect_set_<mode>"
> > +  [(set (match_operand:GPR 0 "memory_operand" "=m")
> > +     (unspec:GPR [(match_operand:GPR 1 "memory_operand" "m")]
> > +      UNSPEC_SSP_SET))
> > +   (set (match_scratch:GPR 2 "=&r") (const_int 0))]
> > +  ""
> > +  "<load>\\t%2, %1\;<store>\\t%2, %0\;li\t%2, 0"
> > +  [(set_attr "length" "12")])
> > +
> > +(define_expand "stack_protect_test"
> > +  [(match_operand 0 "memory_operand")
> > +   (match_operand 1 "memory_operand")
> > +   (match_operand 2)]
> > +  ""
> > +{
> > +  rtx result;
> > +  machine_mode mode = GET_MODE (operands[0]);
> > +
> > +  result = gen_reg_rtx(mode);
> > +  if (riscv_stack_protector_guard == SSP_TLS)
> > +  {
> > +      rtx reg = gen_rtx_REG (Pmode, riscv_stack_protector_guard_reg);
> > +      rtx offset = GEN_INT (riscv_stack_protector_guard_offset);
> > +      rtx addr = gen_rtx_PLUS (Pmode, reg, offset);
> > +      operands[1] = gen_rtx_MEM (Pmode, addr);
> > +  }
> > +  emit_insn ((mode == DImode
> > +               ? gen_stack_protect_test_di
> > +               : gen_stack_protect_test_si) (result,
> > +                                             operands[0],
> > +                                             operands[1]));
> > +
> > +  if (mode == DImode)
> > +    emit_jump_insn (gen_cbranchdi4 (gen_rtx_EQ (VOIDmode, result, const0_rtx),
> > +                                 result, const0_rtx, operands[2]));
> > +  else
> > +    emit_jump_insn (gen_cbranchsi4 (gen_rtx_EQ (VOIDmode, result, const0_rtx),
> > +                                 result, const0_rtx, operands[2]));
> > +
> > +  DONE;
> > +})
> > +
> > +(define_insn "stack_protect_test_<mode>"
> > +  [(set (match_operand:GPR 0 "register_operand" "=r")
> > +     (unspec:GPR [(match_operand:GPR 1 "memory_operand" "m")
> > +                  (match_operand:GPR 2 "memory_operand" "m")]
> > +      UNSPEC_SSP_TEST))
> > +   (clobber (match_scratch:GPR 3 "=&r"))]
> > +  ""
> > +  "<load>\t%3, %1\;<load>\t%0, %2\;xor\t%0, %3, %0\;li\t%3, 0"
> > +  [(set_attr "length" "12")])
> > +
> >   (include "sync.md")
> >   (include "peephole.md")
> >   (include "pic.md")
> > diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
> > index e4bfcb86f51..f01d3ab79c3 100644
> > --- a/gcc/config/riscv/riscv.opt
> > +++ b/gcc/config/riscv/riscv.opt
> > @@ -151,3 +151,31 @@ Enum(riscv_align_data) String(xlen) Value(riscv_align_data_type_xlen)
> >
> >   EnumValue
> >   Enum(riscv_align_data) String(natural) Value(riscv_align_data_type_natural)
> > +
> > +mstack-protector-guard=
> > +Target RejectNegative Joined Enum(stack_protector_guard) Var(riscv_stack_protector_guard) Init(SSP_GLOBAL)
> > +Use given stack-protector guard.
> > +
> > +Enum
> > +Name(stack_protector_guard) Type(enum stack_protector_guard)
> > +Valid arguments to -mstack-protector-guard=:
> > +
> > +EnumValue
> > +Enum(stack_protector_guard) String(tls) Value(SSP_TLS)
> > +
> > +EnumValue
> > +Enum(stack_protector_guard) String(global) Value(SSP_GLOBAL)
> > +
> > +mstack-protector-guard-reg=
> > +Target RejectNegative Joined Var(riscv_stack_protector_guard_reg_str)
> > +Use the given base register for addressing the stack-protector guard.
> > +
> > +TargetVariable
> > +int riscv_stack_protector_guard_reg = 0
> > +
> > +mstack-protector-guard-offset=
> > +Target RejectNegative Joined Integer Var(riscv_stack_protector_guard_offset_str)
> > +Use the given offset for addressing the stack-protector guard.
> > +
> > +TargetVariable
> > +long riscv_stack_protector_guard_offset = 0
> > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> > index 09bcc5b0f78..3bb124ae6ed 100644
> > --- a/gcc/doc/invoke.texi
> > +++ b/gcc/doc/invoke.texi
> > @@ -1138,7 +1138,9 @@ See RS/6000 and PowerPC Options.
> >   -mexplicit-relocs  -mno-explicit-relocs @gol
> >   -mrelax  -mno-relax @gol
> >   -mriscv-attribute  -mmo-riscv-attribute @gol
> > --malign-data=@var{type}}
> > +-malign-data=@var{type} @gol
> > ++-mstack-protector-guard=@var{guard} -mstack-protector-guard-reg=@var{reg} @gol
> > ++-mstack-protector-guard-offset=@var{offset}}
> >
> >   @emph{RL78 Options}
> >   @gccoptlist{-msim  -mmul=none  -mmul=g13  -mmul=g14  -mallregs @gol
> > @@ -25723,6 +25725,24 @@ Control how GCC aligns variables and constants of array, structure, or union
> >   types.  Supported values for @var{type} are @samp{xlen} which uses x register
> >   width as the alignment value, and @samp{natural} which uses natural alignment.
> >   @samp{xlen} is the default.
> > +
> > +@item -mstack-protector-guard=@var{guard}
> > +@itemx -mstack-protector-guard-reg=@var{reg}
> > +@itemx -mstack-protector-guard-offset=@var{offset}
> > +@opindex mstack-protector-guard
> > +@opindex mstack-protector-guard-reg
> > +@opindex mstack-protector-guard-offset
> > +Generate stack protection code using canary at @var{guard}.  Supported
> > +locations are @samp{global} for a global canary or @samp{tls} for per-thread
> > +canary in the TLS block.
> > +
> > +With the latter choice the options
> > +@option{-mstack-protector-guard-reg=@var{reg}} and
> > +@option{-mstack-protector-guard-offset=@var{offset}} furthermore specify
> > +which register to use as base register for reading the canary,
> > +and from what offset from that base register. There is no default
> > +register or offset as this is entirely for use within the Linux
> > +kernel.
> >   @end table
> >
> >   @node RL78 Options

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] [RISC-V] Add support for TLS stack protector canary access
  2020-07-20  2:03 ` cooper
  2020-07-21  8:14   ` Kito Cheng
@ 2020-07-27 22:54   ` Jim Wilson
  2020-07-28  1:23     ` Kito Cheng
  1 sibling, 1 reply; 7+ messages in thread
From: Jim Wilson @ 2020-07-27 22:54 UTC (permalink / raw)
  To: cooper, Kito Cheng; +Cc: GCC Patches, guoren

On Sun, Jul 19, 2020 at 7:04 PM cooper <cooper.qu@linux.alibaba.com> wrote:
> Ping
>
> On 2020/7/13 下午4:15, cooper wrote:
> > gcc/
> >       * config/riscv/riscv-opts.h (stack_protector_guard): New enum.
> >       * config/riscv/riscv.c (riscv_option_override): Handle
> >       the new options.
> >       * config/riscv/riscv.md (stack_protect_set): New pattern to handle
> >       flexible stack protector guard settings.
> >       (stack_protect_set_<mode>): Ditto.
> >       (stack_protect_test): Ditto.
> >       (stack_protect_test_<mode>): Ditto.
> >       * config/riscv/riscv.opt (mstack-protector-guard=,
> >       mstack-protector-guard-reg=, mstack-protector-guard-offset=): New
> >       options.
> >       * doc/invoke.texi (Option Summary) [RISC-V Options]:
> >       Add -mstack-protector-guard=, -mstack-protector-guard-reg=, and
> >       -mstack-protector-guard-offset=.
> >       (RISC-V Options): Ditto.

The v2 patch looks fine to me.  Meanwhile, Kito asked for testcases
which would be nice to have but I don't think is critical considering
that this has already been tested with a kernel build.  Maybe the
testcases can be a follow on patch?  I'd like to see forward movement
on this, even if we accept a patch without the testcases.

Jim

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] [RISC-V] Add support for TLS stack protector canary access
  2020-07-27 22:54   ` Jim Wilson
@ 2020-07-28  1:23     ` Kito Cheng
  2020-07-29 12:34       ` Cooper Qu
  0 siblings, 1 reply; 7+ messages in thread
From: Kito Cheng @ 2020-07-28  1:23 UTC (permalink / raw)
  To: Jim Wilson; +Cc: cooper, guoren, GCC Patches

Add testcase later is OK to me.

On Tue, Jul 28, 2020 at 6:55 AM Jim Wilson <jimw@sifive.com> wrote:
>
> On Sun, Jul 19, 2020 at 7:04 PM cooper <cooper.qu@linux.alibaba.com> wrote:
> > Ping
> >
> > On 2020/7/13 下午4:15, cooper wrote:
> > > gcc/
> > >       * config/riscv/riscv-opts.h (stack_protector_guard): New enum.
> > >       * config/riscv/riscv.c (riscv_option_override): Handle
> > >       the new options.
> > >       * config/riscv/riscv.md (stack_protect_set): New pattern to handle
> > >       flexible stack protector guard settings.
> > >       (stack_protect_set_<mode>): Ditto.
> > >       (stack_protect_test): Ditto.
> > >       (stack_protect_test_<mode>): Ditto.
> > >       * config/riscv/riscv.opt (mstack-protector-guard=,
> > >       mstack-protector-guard-reg=, mstack-protector-guard-offset=): New
> > >       options.
> > >       * doc/invoke.texi (Option Summary) [RISC-V Options]:
> > >       Add -mstack-protector-guard=, -mstack-protector-guard-reg=, and
> > >       -mstack-protector-guard-offset=.
> > >       (RISC-V Options): Ditto.
>
> The v2 patch looks fine to me.  Meanwhile, Kito asked for testcases
> which would be nice to have but I don't think is critical considering
> that this has already been tested with a kernel build.  Maybe the
> testcases can be a follow on patch?  I'd like to see forward movement
> on this, even if we accept a patch without the testcases.
>
> Jim

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] [RISC-V] Add support for TLS stack protector canary access
  2020-07-28  1:23     ` Kito Cheng
@ 2020-07-29 12:34       ` Cooper Qu
  2020-07-30 16:40         ` Kito Cheng
  0 siblings, 1 reply; 7+ messages in thread
From: Cooper Qu @ 2020-07-29 12:34 UTC (permalink / raw)
  To: Kito Cheng, Jim Wilson; +Cc: guoren, GCC Patches

Sorry for later replay, I will add testcases on a following patch if the 
patch is accepted.


Regards,

Cooper

On 2020/7/28 上午9:23, Kito Cheng wrote:
> Add testcase later is OK to me.
>
> On Tue, Jul 28, 2020 at 6:55 AM Jim Wilson <jimw@sifive.com> wrote:
>> On Sun, Jul 19, 2020 at 7:04 PM cooper <cooper.qu@linux.alibaba.com> wrote:
>>> Ping
>>>
>>> On 2020/7/13 下午4:15, cooper wrote:
>>>> gcc/
>>>>        * config/riscv/riscv-opts.h (stack_protector_guard): New enum.
>>>>        * config/riscv/riscv.c (riscv_option_override): Handle
>>>>        the new options.
>>>>        * config/riscv/riscv.md (stack_protect_set): New pattern to handle
>>>>        flexible stack protector guard settings.
>>>>        (stack_protect_set_<mode>): Ditto.
>>>>        (stack_protect_test): Ditto.
>>>>        (stack_protect_test_<mode>): Ditto.
>>>>        * config/riscv/riscv.opt (mstack-protector-guard=,
>>>>        mstack-protector-guard-reg=, mstack-protector-guard-offset=): New
>>>>        options.
>>>>        * doc/invoke.texi (Option Summary) [RISC-V Options]:
>>>>        Add -mstack-protector-guard=, -mstack-protector-guard-reg=, and
>>>>        -mstack-protector-guard-offset=.
>>>>        (RISC-V Options): Ditto.
>> The v2 patch looks fine to me.  Meanwhile, Kito asked for testcases
>> which would be nice to have but I don't think is critical considering
>> that this has already been tested with a kernel build.  Maybe the
>> testcases can be a follow on patch?  I'd like to see forward movement
>> on this, even if we accept a patch without the testcases.
>>
>> Jim

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] [RISC-V] Add support for TLS stack protector canary access
  2020-07-29 12:34       ` Cooper Qu
@ 2020-07-30 16:40         ` Kito Cheng
  0 siblings, 0 replies; 7+ messages in thread
From: Kito Cheng @ 2020-07-30 16:40 UTC (permalink / raw)
  To: Cooper Qu; +Cc: Jim Wilson, guoren, GCC Patches

Hi Cooper:

Thanks for your patch! committed to trunk.

https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=c931e8d5a96463427040b0d11f9c4352ac22b2b0

On Wed, Jul 29, 2020 at 8:34 PM Cooper Qu via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> Sorry for later replay, I will add testcases on a following patch if the
> patch is accepted.
>
>
> Regards,
>
> Cooper
>
> On 2020/7/28 上午9:23, Kito Cheng wrote:
> > Add testcase later is OK to me.
> >
> > On Tue, Jul 28, 2020 at 6:55 AM Jim Wilson <jimw@sifive.com> wrote:
> >> On Sun, Jul 19, 2020 at 7:04 PM cooper <cooper.qu@linux.alibaba.com> wrote:
> >>> Ping
> >>>
> >>> On 2020/7/13 下午4:15, cooper wrote:
> >>>> gcc/
> >>>>        * config/riscv/riscv-opts.h (stack_protector_guard): New enum.
> >>>>        * config/riscv/riscv.c (riscv_option_override): Handle
> >>>>        the new options.
> >>>>        * config/riscv/riscv.md (stack_protect_set): New pattern to handle
> >>>>        flexible stack protector guard settings.
> >>>>        (stack_protect_set_<mode>): Ditto.
> >>>>        (stack_protect_test): Ditto.
> >>>>        (stack_protect_test_<mode>): Ditto.
> >>>>        * config/riscv/riscv.opt (mstack-protector-guard=,
> >>>>        mstack-protector-guard-reg=, mstack-protector-guard-offset=): New
> >>>>        options.
> >>>>        * doc/invoke.texi (Option Summary) [RISC-V Options]:
> >>>>        Add -mstack-protector-guard=, -mstack-protector-guard-reg=, and
> >>>>        -mstack-protector-guard-offset=.
> >>>>        (RISC-V Options): Ditto.
> >> The v2 patch looks fine to me.  Meanwhile, Kito asked for testcases
> >> which would be nice to have but I don't think is critical considering
> >> that this has already been tested with a kernel build.  Maybe the
> >> testcases can be a follow on patch?  I'd like to see forward movement
> >> on this, even if we accept a patch without the testcases.
> >>
> >> Jim

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2020-07-30 16:41 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-13  8:15 [PATCH v2] [RISC-V] Add support for TLS stack protector canary access cooper
2020-07-20  2:03 ` cooper
2020-07-21  8:14   ` Kito Cheng
2020-07-27 22:54   ` Jim Wilson
2020-07-28  1:23     ` Kito Cheng
2020-07-29 12:34       ` Cooper Qu
2020-07-30 16:40         ` Kito Cheng

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 read-only IMAP folder(s) and NNTP newsgroup(s).