The Linux Kernel Mailing List
 help / color / mirror / Atom feed
From: Jani Nikula <jani.nikula@linux.intel.com>
To: Kees Cook <kees@kernel.org>, Nathan Chancellor <nathan@kernel.org>
Cc: Kees Cook <kees@kernel.org>,
	Nicolas Schier <nicolas.schier@linux.dev>,
	Jonathan Corbet <corbet@lwn.net>,
	Masahiro Yamada <masahiroy@kernel.org>,
	Randy Dunlap <rdunlap@infradead.org>,
	Arnd Bergmann <arnd@arndb.de>,
	Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>,
	linux-kbuild@vger.kernel.org, linux-doc@vger.kernel.org,
	Miguel Ojeda <ojeda@kernel.org>,
	Stephen Brennan <stephen.s.brennan@oracle.com>,
	Marco Bonelli <marco@mebeim.net>, Petr Vorel <pvorel@suse.cz>,
	linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org
Subject: Re: [PATCH v2] kconfig: Add transitional symbol attribute for migration support
Date: Mon, 01 Sep 2025 12:09:14 +0300	[thread overview]
Message-ID: <7bca36d46dab04667aa595623fd0966385ee4658@intel.com> (raw)
In-Reply-To: <20250830020109.it.598-kees@kernel.org>

On Fri, 29 Aug 2025, Kees Cook <kees@kernel.org> wrote:
> During kernel option migrations (e.g. CONFIG_CFI_CLANG to CONFIG_CFI),
> existing .config files need to maintain backward compatibility while
> preventing deprecated options from appearing in newly generated
> configurations. This is challenging with existing Kconfig mechanisms
> because:
>
> 1. Simply removing old options breaks existing .config files.
> 2. Manually listing an option as "deprecated" leaves it needlessly
>    visible and still writes them to new .config files.
> 3. Using any method to remove visibility (.e.g no 'prompt', 'if n',
>    etc) prevents the option from being processed at all.
>
> Add a "transitional" attribute that creates symbols which are:
> - Processed during configuration (can influence other symbols' defaults)
> - Hidden from user menus (no prompts appear)
> - Omitted from newly written .config files (gets migrated)
> - Restricted to only having help sections (no defaults, selects, etc)
>   making it truly just a "prior value pass-through" option.
>
> The transitional syntax requires a type argument and prevents type
> redefinition:
>
>     config OLD_OPTION
>         transitional bool
>         help
>           Transitional config for OLD_OPTION migration.

How long do you think we'll need to keep the transitional config options
around? Forever?

BR,
Jani.

>     config NEW_OPTION
>         bool "New option"
>         default OLD_OPTION
>
> This allows seamless migration: olddefconfig processes existing
> CONFIG_OLD_OPTION=y settings to enable CONFIG_NEW_OPTION=y, while
> CONFIG_OLD_OPTION is omitted from newly generated .config files.
>
> Implementation details:
> - Parser validates transitional symbols can only have help sections
> - Symbol visibility logic updated: usable = (visible != no || transitional)
> - Transitional symbols preserve user values during configuration
> - Type safety enforced to prevent redefinition after transitional declaration
> - Used distinct struct members instead of new flags for readability
> - Documentation added to show the usage
>
> Signed-off-by: Kees Cook <kees@kernel.org>
> ---
> With help from Claude Code to show me how to navigate the kconfig parser.
>
>  v2: fixed human-introduced errors
>  v1: https://lore.kernel.org/all/20250830014438.work.682-kees@kernel.org/
>
> Cc: Nathan Chancellor <nathan@kernel.org>
> Cc: Nicolas Schier <nicolas.schier@linux.dev>
> Cc: Jonathan Corbet <corbet@lwn.net>
> Cc: Masahiro Yamada <masahiroy@kernel.org>
> Cc: Randy Dunlap <rdunlap@infradead.org>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
> Cc: <linux-kbuild@vger.kernel.org>
> Cc: <linux-doc@vger.kernel.org>
> ---
>  scripts/kconfig/expr.h                    | 15 +++++++
>  scripts/kconfig/lexer.l                   |  1 +
>  scripts/kconfig/parser.y                  | 51 +++++++++++++++++++++++
>  scripts/kconfig/symbol.c                  | 11 +++--
>  Documentation/kbuild/kconfig-language.rst | 31 ++++++++++++++
>  5 files changed, 106 insertions(+), 3 deletions(-)
>
> diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
> index fe2231e0e6a4..be51574d6c77 100644
> --- a/scripts/kconfig/expr.h
> +++ b/scripts/kconfig/expr.h
> @@ -127,6 +127,21 @@ struct symbol {
>  	/* SYMBOL_* flags */
>  	int flags;
>  
> +	/*
> +	 * Transitional symbol - processed during configuration but hidden from
> +	 * user in menus and omitted from newly written .config files. Used for
> +	 * backward compatibility during config option migrations (e.g.,
> +	 * CFI_CLANG → CFI). Transitional symbols can still influence default
> +	 * expressions of other symbols.
> +	 */
> +	bool transitional:1;
> +
> +	/*
> +	 * Symbol usability - calculated as (visible != no || transitional).
> +	 * Determines if symbol can be used in expressions.
> +	 */
> +	bool usable:1;
> +
>  	/* List of properties. See prop_type. */
>  	struct property *prop;
>  
> diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l
> index 9c2cdfc33c6f..6d2c92c6095d 100644
> --- a/scripts/kconfig/lexer.l
> +++ b/scripts/kconfig/lexer.l
> @@ -126,6 +126,7 @@ n	[A-Za-z0-9_-]
>  "select"		return T_SELECT;
>  "source"		return T_SOURCE;
>  "string"		return T_STRING;
> +"transitional"		return T_TRANSITIONAL;
>  "tristate"		return T_TRISTATE;
>  "visible"		return T_VISIBLE;
>  "||"			return T_OR;
> diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y
> index e9c3c664e925..01d2d0f720ce 100644
> --- a/scripts/kconfig/parser.y
> +++ b/scripts/kconfig/parser.y
> @@ -75,6 +75,7 @@ struct menu *current_menu, *current_entry, *current_choice;
>  %token T_SELECT
>  %token T_SOURCE
>  %token T_STRING
> +%token T_TRANSITIONAL
>  %token T_TRISTATE
>  %token T_VISIBLE
>  %token T_EOL
> @@ -205,6 +206,16 @@ config_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL
>  	printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno);
>  };
>  
> +config_option: T_TRANSITIONAL type T_EOL
> +{
> +	if (current_entry->sym->type != S_UNKNOWN)
> +		yyerror("transitional type cannot be set after symbol type is already defined");
> +	menu_set_type($2);
> +	current_entry->sym->transitional = true;
> +	printd(DEBUG_PARSE, "%s:%d:transitional(%u)\n", cur_filename, cur_lineno,
> +		$2);
> +};
> +
>  config_option: default expr if_expr T_EOL
>  {
>  	menu_add_expr(P_DEFAULT, $2, $3);
> @@ -482,6 +493,43 @@ assign_val:
>  
>  %%
>  
> +/**
> + * transitional_check_sanity - check transitional symbols have no other
> + *			       properties
> + *
> + * @menu: menu of the potentially transitional symbol
> + *
> + * Return: -1 if an error is found, 0 otherwise.
> + */
> +static int transitional_check_sanity(const struct menu *menu)
> +{
> +	struct property *prop;
> +
> +	if (!menu->sym || !menu->sym->transitional)
> +		return 0;
> +
> +	/* Check for depends and visible conditions. */
> +	if ((menu->dep && !expr_is_yes(menu->dep)) ||
> +	    (menu->visibility && !expr_is_yes(menu->visibility))) {
> +		fprintf(stderr, "%s:%d: error: %s",
> +			menu->filename, menu->lineno,
> +			"transitional symbols can only have help sections\n");
> +		return -1;
> +	}
> +
> +	/* Check for any property other than "help". */
> +	for (prop = menu->sym->prop; prop; prop = prop->next) {
> +		if (prop->type != P_COMMENT) {
> +			fprintf(stderr, "%s:%d: error: %s",
> +				prop->filename, prop->lineno,
> +				"transitional symbols can only have help sections\n");
> +			return -1;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
>  /**
>   * choice_check_sanity - check sanity of a choice member
>   *
> @@ -558,6 +606,9 @@ void conf_parse(const char *name)
>  		if (menu->sym && sym_check_deps(menu->sym))
>  			yynerrs++;
>  
> +		if (transitional_check_sanity(menu))
> +			yynerrs++;
> +
>  		if (menu->sym && sym_is_choice(menu->sym)) {
>  			menu_for_each_sub_entry(child, menu)
>  				if (child->sym && choice_check_sanity(child))
> diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
> index 26ab10c0fd76..b822c0c897e5 100644
> --- a/scripts/kconfig/symbol.c
> +++ b/scripts/kconfig/symbol.c
> @@ -447,6 +447,9 @@ void sym_calc_value(struct symbol *sym)
>  	if (sym->visible != no)
>  		sym->flags |= SYMBOL_WRITE;
>  
> +	/* Calculate usable flag */
> +	sym->usable = (sym->visible != no || sym->transitional);
> +
>  	/* set default if recursively called */
>  	sym->curr = newval;
>  
> @@ -459,13 +462,15 @@ void sym_calc_value(struct symbol *sym)
>  			sym_calc_choice(choice_menu);
>  			newval.tri = sym->curr.tri;
>  		} else {
> -			if (sym->visible != no) {
> +			if (sym->usable) {
>  				/* if the symbol is visible use the user value
>  				 * if available, otherwise try the default value
>  				 */
>  				if (sym_has_value(sym)) {
> +					tristate value = sym->transitional ?
> +						sym->def[S_DEF_USER].tri : sym->visible;
>  					newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,
> -							      sym->visible);
> +							      value);
>  					goto calc_newval;
>  				}
>  			}
> @@ -497,7 +502,7 @@ void sym_calc_value(struct symbol *sym)
>  	case S_STRING:
>  	case S_HEX:
>  	case S_INT:
> -		if (sym->visible != no && sym_has_value(sym)) {
> +		if (sym->usable && sym_has_value(sym)) {
>  			newval.val = sym->def[S_DEF_USER].val;
>  			break;
>  		}
> diff --git a/Documentation/kbuild/kconfig-language.rst b/Documentation/kbuild/kconfig-language.rst
> index a91abb8f6840..345c334ce680 100644
> --- a/Documentation/kbuild/kconfig-language.rst
> +++ b/Documentation/kbuild/kconfig-language.rst
> @@ -232,6 +232,37 @@ applicable everywhere (see syntax).
>    enables the third modular state for all config symbols.
>    At most one symbol may have the "modules" option set.
>  
> +- transitional attribute: "transitional"
> +  This declares the symbol as transitional, meaning it should be processed
> +  during configuration but omitted from newly written .config files.
> +  Transitional symbols are useful for backward compatibility during config
> +  option migrations - they allow olddefconfig to process existing .config
> +  files while ensuring the old option doesn't appear in new configurations.
> +
> +  A transitional symbol:
> +  - Has no prompt (is not visible to users in menus)
> +  - Is processed normally during configuration (values are read and used)
> +  - Can be referenced in default expressions of other symbols
> +  - Is not written to new .config files
> +  - Cannot have any other properties (it is a pass-through option)
> +
> +  Example migration from OLD_NAME to NEW_NAME::
> +
> +    config NEW_NAME
> +	bool "New option name"
> +	default OLD_NAME
> +	help
> +	  This replaces the old CONFIG_OLD_NAME option.
> +
> +    config OLD_NAME
> +	transitional bool
> +	help
> +	  Transitional config for OLD_NAME to NEW_NAME migration.
> +
> +  With this setup, existing .config files with "CONFIG_OLD_NAME=y" will
> +  result in "CONFIG_NEW_NAME=y" being set, while CONFIG_OLD_NAME will be
> +  omitted from newly written .config files.
> +
>  Menu dependencies
>  -----------------

-- 
Jani Nikula, Intel

  parent reply	other threads:[~2025-09-01  9:09 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-08-30  2:01 [PATCH v2] kconfig: Add transitional symbol attribute for migration support Kees Cook
2025-09-01  8:34 ` Vegard Nossum
2025-09-01 16:56   ` Kees Cook
2025-09-01 18:20     ` Vegard Nossum
2025-09-01 18:31       ` Kees Cook
2025-09-01 18:44         ` Vegard Nossum
2025-09-04  2:51           ` Kees Cook
2025-09-04 17:03             ` Vegard Nossum
2025-09-04 17:10               ` Vegard Nossum
2025-09-05  9:41                 ` Vegard Nossum
2025-09-05 16:24                   ` Kees Cook
2025-09-05 16:23               ` Kees Cook
2025-09-23 21:36                 ` Kees Cook
2025-09-01  9:09 ` Jani Nikula [this message]
2025-09-01 16:48   ` Kees Cook
2025-09-01 16:39 ` Randy Dunlap
2025-09-01 16:45   ` Kees Cook
2025-09-01 16:54     ` Randy Dunlap

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=7bca36d46dab04667aa595623fd0966385ee4658@intel.com \
    --to=jani.nikula@linux.intel.com \
    --cc=arnd@arndb.de \
    --cc=corbet@lwn.net \
    --cc=kees@kernel.org \
    --cc=krzysztof.kozlowski@linaro.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-hardening@vger.kernel.org \
    --cc=linux-kbuild@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=marco@mebeim.net \
    --cc=masahiroy@kernel.org \
    --cc=nathan@kernel.org \
    --cc=nicolas.schier@linux.dev \
    --cc=ojeda@kernel.org \
    --cc=pvorel@suse.cz \
    --cc=rdunlap@infradead.org \
    --cc=stephen.s.brennan@oracle.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox