* Re: [PATCH v2] kconfig: Add transitional symbol attribute for migration support
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 9:09 ` Jani Nikula
2025-09-01 16:39 ` Randy Dunlap
2 siblings, 1 reply; 17+ messages in thread
From: Vegard Nossum @ 2025-09-01 8:34 UTC (permalink / raw)
To: Kees Cook, Nathan Chancellor
Cc: Nicolas Schier, Jonathan Corbet, Masahiro Yamada, Randy Dunlap,
Arnd Bergmann, Krzysztof Kozlowski, linux-kbuild, linux-doc,
Miguel Ojeda, Stephen Brennan, Marco Bonelli, Petr Vorel,
linux-kernel, linux-hardening
Hi,
Drive-by review... consider it more as "here's some stuff that could be
worth looking at" rather than blocking in any way.
On 30/08/2025 04:01, Kees Cook 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.
>
> config NEW_OPTION
> bool "New option"
> default OLD_OPTION
Can you add this to scripts/kconfig/tests/ + both positive and negative
tests? Tests are run with 'make testconfig' but (AFAICT) doesn't
actually recompile config/mconf/etc. before running the tests, so small
gotcha there.
> 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;
> +
It's a bit of a "red flag" to see bitfield bools just after an "int
flags;" member... should these be SYMBOL_ flags?
Speaking of SYMBOL_ flags, there's apparently one that controls whether
a given symbol should be written out to .config:
scripts/kconfig/expr.h:#define SYMBOL_WRITE 0x0200 /* write symbol
to file (KCONFIG_CONFIG) */
This seems like something you'd like to use somehow -- maybe simply
clear it in sym_calc_value() if it's transitional? Similar to how it's
done for choice values:
if (sym_is_choice(sym))
sym->flags &= ~SYMBOL_WRITE;
> /* 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);
> +};
You could also consider making this an attribute similar to the
"modules" flags and simplify:
config_option: T_TRANSITIONAL T_EOL
{
current_entry->sym->transitional = true;
printd(DEBUG_PARSE, "%s:%d:transitional\n", cur_filename,
cur_lineno);
};
...it would mean the config options look this way:
config OLD_OPTION
bool
transitional
(If not, menu_set_type() does already contain a check for whether the
type has already been set.)
> +
> 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);
> +
Is this actually ever used outside of this function? (IOW could this
just be a local variable instead of a sym-> flag/member?) Or do we need
to set it here because sym_calc_value() calls itself recursively? To me
it looks like we only ever access sym->usable for the "sym" that was
passed as an argument to the function.
> /* 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);
This looks a bit odd to me. Just thinking out loud: your new logic is
there to be able to use a value even though it's not visible. In the
case where it's transitional you use the .config value instead of the
condition that makes it visible.
Could you simply change sym_calc_visibility() instead to always return
'yes' when the symbol is transitional? Wouldn't that simplify everything
in sym_calc_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;
> }
Ok.
> 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
> -----------------
>
Vegard
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v2] kconfig: Add transitional symbol attribute for migration support
2025-09-01 8:34 ` Vegard Nossum
@ 2025-09-01 16:56 ` Kees Cook
2025-09-01 18:20 ` Vegard Nossum
0 siblings, 1 reply; 17+ messages in thread
From: Kees Cook @ 2025-09-01 16:56 UTC (permalink / raw)
To: Vegard Nossum
Cc: Nathan Chancellor, Nicolas Schier, Jonathan Corbet,
Masahiro Yamada, Randy Dunlap, Arnd Bergmann, Krzysztof Kozlowski,
linux-kbuild, linux-doc, Miguel Ojeda, Stephen Brennan,
Marco Bonelli, Petr Vorel, linux-kernel, linux-hardening
On Mon, Sep 01, 2025 at 10:34:19AM +0200, Vegard Nossum wrote:
> Drive-by review... consider it more as "here's some stuff that could be
> worth looking at" rather than blocking in any way.
Thanks for looking at it!
>
> On 30/08/2025 04:01, Kees Cook 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.
> >
> > config NEW_OPTION
> > bool "New option"
> > default OLD_OPTION
>
> Can you add this to scripts/kconfig/tests/ + both positive and negative
> tests? Tests are run with 'make testconfig' but (AFAICT) doesn't
> actually recompile config/mconf/etc. before running the tests, so small
> gotcha there.
Yes, I will get that added if people are generally happy with this
feature idea. :)
> > 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;
> > +
>
> It's a bit of a "red flag" to see bitfield bools just after an "int
> flags;" member... should these be SYMBOL_ flags?
>
> Speaking of SYMBOL_ flags, there's apparently one that controls whether
> a given symbol should be written out to .config:
Yeah, I mentioned this in the commit log, and maybe I just have to make
this not as easily readable? But you have a point about "usable" below...
> scripts/kconfig/expr.h:#define SYMBOL_WRITE 0x0200 /* write symbol to
> file (KCONFIG_CONFIG) */
>
> This seems like something you'd like to use somehow -- maybe simply
> clear it in sym_calc_value() if it's transitional? Similar to how it's
> done for choice values:
>
> if (sym_is_choice(sym))
> sym->flags &= ~SYMBOL_WRITE;
This is actually handled naturally as part of this logic:
> > if (sym->visible != no)
> > sym->flags |= SYMBOL_WRITE;
i.e. "usable" doesn't change SYMBOL_WRITE getting set.
> > @@ -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);
> > +};
>
> You could also consider making this an attribute similar to the
> "modules" flags and simplify:
>
> config_option: T_TRANSITIONAL T_EOL
> {
> current_entry->sym->transitional = true;
> printd(DEBUG_PARSE, "%s:%d:transitional\n", cur_filename,
> cur_lineno);
> };
>
> ...it would mean the config options look this way:
>
> config OLD_OPTION
> bool
> transitional
>
> (If not, menu_set_type() does already contain a check for whether the
> type has already been set.)
I went back and forth on how I wanted it to look and ultimately decided
it was awkward to say "use transitional but only with a type that
doesn't have a prompt". Instead it seemed better to have the type
explicitly set.
menu_set_type() does check already, but it's a warning only.
> > @@ -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);
> > +
>
> Is this actually ever used outside of this function? (IOW could this
> just be a local variable instead of a sym-> flag/member?) Or do we need
> to set it here because sym_calc_value() calls itself recursively? To me
> it looks like we only ever access sym->usable for the "sym" that was
> passed as an argument to the function.
Ah! It's not any more, no. I had an earlier version where I was
examining it elsewhere, but yeah, this is only needed here.
>
> > /* 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);
>
> This looks a bit odd to me. Just thinking out loud: your new logic is
> there to be able to use a value even though it's not visible. In the
> case where it's transitional you use the .config value instead of the
> condition that makes it visible.
>
> Could you simply change sym_calc_visibility() instead to always return
> 'yes' when the symbol is transitional? Wouldn't that simplify everything
> in sym_calc_value()?
It's a tristate, so "m" is also possible besides "y". (sym->visible is
also a tristate. :)
I will send a v3 with better bit fields.
-Kees
--
Kees Cook
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v2] kconfig: Add transitional symbol attribute for migration support
2025-09-01 16:56 ` Kees Cook
@ 2025-09-01 18:20 ` Vegard Nossum
2025-09-01 18:31 ` Kees Cook
0 siblings, 1 reply; 17+ messages in thread
From: Vegard Nossum @ 2025-09-01 18:20 UTC (permalink / raw)
To: Kees Cook
Cc: Nathan Chancellor, Nicolas Schier, Jonathan Corbet,
Masahiro Yamada, Randy Dunlap, Arnd Bergmann, Krzysztof Kozlowski,
linux-kbuild, linux-doc, Miguel Ojeda, Stephen Brennan,
Marco Bonelli, Petr Vorel, linux-kernel, linux-hardening
On 01/09/2025 18:56, Kees Cook wrote:
>>> @@ -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);
>> This looks a bit odd to me. Just thinking out loud: your new logic is
>> there to be able to use a value even though it's not visible. In the
>> case where it's transitional you use the .config value instead of the
>> condition that makes it visible.
>>
>> Could you simply change sym_calc_visibility() instead to always return
>> 'yes' when the symbol is transitional? Wouldn't that simplify everything
>> in sym_calc_value()?
> It's a tristate, so "m" is also possible besides "y". (sym->visible is
> also a tristate. 🙂
That would be fine, right?
We'd pass the if (sym->visible != no) check... we'd do the
newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, sym->visible);
EXPR_AND() is basically min() (with n=0, m=1, y=2), so effectively it
would end up doing
newval.tri = min(sym->def[S_DEF_USER].tri, 2);
which is the same as
newval.tri = sym->def[S_DEF_USER].tri;
That's what your code is currently doing too, but in a much more
roundabout way.
Vegard
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v2] kconfig: Add transitional symbol attribute for migration support
2025-09-01 18:20 ` Vegard Nossum
@ 2025-09-01 18:31 ` Kees Cook
2025-09-01 18:44 ` Vegard Nossum
0 siblings, 1 reply; 17+ messages in thread
From: Kees Cook @ 2025-09-01 18:31 UTC (permalink / raw)
To: Vegard Nossum
Cc: Nathan Chancellor, Nicolas Schier, Jonathan Corbet,
Masahiro Yamada, Randy Dunlap, Arnd Bergmann, Krzysztof Kozlowski,
linux-kbuild, linux-doc, Miguel Ojeda, Stephen Brennan,
Marco Bonelli, Petr Vorel, linux-kernel, linux-hardening
On Mon, Sep 01, 2025 at 08:20:18PM +0200, Vegard Nossum wrote:
>
> On 01/09/2025 18:56, Kees Cook wrote:
> > > > @@ -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);
> > > This looks a bit odd to me. Just thinking out loud: your new logic is
> > > there to be able to use a value even though it's not visible. In the
> > > case where it's transitional you use the .config value instead of the
> > > condition that makes it visible.
> > >
> > > Could you simply change sym_calc_visibility() instead to always return
> > > 'yes' when the symbol is transitional? Wouldn't that simplify everything
> > > in sym_calc_value()?
> > It's a tristate, so "m" is also possible besides "y". (sym->visible is
> > also a tristate. 🙂
>
> That would be fine, right?
>
> We'd pass the if (sym->visible != no) check... we'd do the
>
> newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, sym->visible);
>
> EXPR_AND() is basically min() (with n=0, m=1, y=2), so effectively it
> would end up doing
>
> newval.tri = min(sym->def[S_DEF_USER].tri, 2);
>
> which is the same as
>
> newval.tri = sym->def[S_DEF_USER].tri;
>
> That's what your code is currently doing too, but in a much more
> roundabout way.
Right, it was this:
newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, sym->visible);
But I made it effectively:
if (sym->transitional)
newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, sym->def[S_DEF_USER].tri);
else
newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, sym->visible);
That first "if" is kind of pointless. I just sent the v3 before I saw
this email. :P
I was trying to avoid yet more indentation, but I could change it to:
if (sym->transitional)
newval.tri = sym->def[S_DEF_USER].tri;
else
newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,
sym->visible);
?
--
Kees Cook
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v2] kconfig: Add transitional symbol attribute for migration support
2025-09-01 18:31 ` Kees Cook
@ 2025-09-01 18:44 ` Vegard Nossum
2025-09-04 2:51 ` Kees Cook
0 siblings, 1 reply; 17+ messages in thread
From: Vegard Nossum @ 2025-09-01 18:44 UTC (permalink / raw)
To: Kees Cook
Cc: Nathan Chancellor, Nicolas Schier, Jonathan Corbet,
Masahiro Yamada, Randy Dunlap, Arnd Bergmann, Krzysztof Kozlowski,
linux-kbuild, linux-doc, Miguel Ojeda, Stephen Brennan,
Marco Bonelli, Petr Vorel, linux-kernel, linux-hardening
On 01/09/2025 20:31, Kees Cook wrote:
> On Mon, Sep 01, 2025 at 08:20:18PM +0200, Vegard Nossum wrote:
>>
>> On 01/09/2025 18:56, Kees Cook wrote:
>>>>> @@ -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);
>>>> This looks a bit odd to me. Just thinking out loud: your new logic is
>>>> there to be able to use a value even though it's not visible. In the
>>>> case where it's transitional you use the .config value instead of the
>>>> condition that makes it visible.
>>>>
>>>> Could you simply change sym_calc_visibility() instead to always return
>>>> 'yes' when the symbol is transitional? Wouldn't that simplify everything
>>>> in sym_calc_value()?
>>> It's a tristate, so "m" is also possible besides "y". (sym->visible is
>>> also a tristate. 🙂
>>
>> That would be fine, right?
>>
>> We'd pass the if (sym->visible != no) check... we'd do the
>>
>> newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, sym->visible);
>>
>> EXPR_AND() is basically min() (with n=0, m=1, y=2), so effectively it
>> would end up doing
>>
>> newval.tri = min(sym->def[S_DEF_USER].tri, 2);
>>
>> which is the same as
>>
>> newval.tri = sym->def[S_DEF_USER].tri;
>>
>> That's what your code is currently doing too, but in a much more
>> roundabout way.
>
> Right, it was this:
>
> newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, sym->visible);
>
> But I made it effectively:
>
> if (sym->transitional)
> newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, sym->def[S_DEF_USER].tri);
> else
> newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, sym->visible);
>
> That first "if" is kind of pointless. I just sent the v3 before I saw
> this email. :P
>
> I was trying to avoid yet more indentation, but I could change it to:
>
> if (sym->transitional)
> newval.tri = sym->def[S_DEF_USER].tri;
> else
> newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,
> sym->visible);
>
> ?
>
If you change sym_calc_visibility() to always return 'yes' for
transitional values then I don't think you need to touch
sym_calc_value() at all.
Vegard
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v2] kconfig: Add transitional symbol attribute for migration support
2025-09-01 18:44 ` Vegard Nossum
@ 2025-09-04 2:51 ` Kees Cook
2025-09-04 17:03 ` Vegard Nossum
0 siblings, 1 reply; 17+ messages in thread
From: Kees Cook @ 2025-09-04 2:51 UTC (permalink / raw)
To: Vegard Nossum
Cc: Nathan Chancellor, Nicolas Schier, Jonathan Corbet,
Masahiro Yamada, Randy Dunlap, Arnd Bergmann, Krzysztof Kozlowski,
linux-kbuild, linux-doc, Miguel Ojeda, Stephen Brennan,
Marco Bonelli, Petr Vorel, linux-kernel, linux-hardening
On Mon, Sep 01, 2025 at 08:44:56PM +0200, Vegard Nossum wrote:
> If you change sym_calc_visibility() to always return 'yes' for
> transitional values then I don't think you need to touch
> sym_calc_value() at all.
Hm, it looks like sym_calc_visibility() doesn't strictly just look at
visibility. And visibility seems to "last"? And I think the "tri" still
can't just be "yes", don't we need the other stuff handled?
Do you see a way to do it how you're suggesting? And now I wrote the
regression tests so we can test any alternatives! ;)
--
Kees Cook
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v2] kconfig: Add transitional symbol attribute for migration support
2025-09-04 2:51 ` Kees Cook
@ 2025-09-04 17:03 ` Vegard Nossum
2025-09-04 17:10 ` Vegard Nossum
2025-09-05 16:23 ` Kees Cook
0 siblings, 2 replies; 17+ messages in thread
From: Vegard Nossum @ 2025-09-04 17:03 UTC (permalink / raw)
To: Kees Cook
Cc: Nathan Chancellor, Nicolas Schier, Jonathan Corbet,
Masahiro Yamada, Randy Dunlap, Arnd Bergmann, Krzysztof Kozlowski,
linux-kbuild, linux-doc, Miguel Ojeda, Stephen Brennan,
Marco Bonelli, Petr Vorel, linux-kernel, linux-hardening
[-- Attachment #1: Type: text/plain, Size: 1338 bytes --]
On 04/09/2025 04:51, Kees Cook wrote:
> On Mon, Sep 01, 2025 at 08:44:56PM +0200, Vegard Nossum wrote:
>> If you change sym_calc_visibility() to always return 'yes' for
>> transitional values then I don't think you need to touch
>> sym_calc_value() at all.
>
> Hm, it looks like sym_calc_visibility() doesn't strictly just look at
> visibility. And visibility seems to "last"? And I think the "tri" still
> can't just be "yes", don't we need the other stuff handled?
>
> Do you see a way to do it how you're suggesting? And now I wrote the
> regression tests so we can test any alternatives! ;)
Here's what I had in mind (on top of your kcfi patchset), see the
attachment.
It basically undoes all your additions to sym_calc_value() in favour of
two straightforward additions:
@@ -214,6 +214,11 @@ static void sym_calc_visibility(struct symbol *sym)
struct property *prop;
tristate tri;
+ if (sym->flags & SYMBOL_HIDDEN) {
+ sym->visible = yes;
+ return;
+ }
+
and
@@ -536,7 +531,7 @@ void sym_calc_value(struct symbol *sym)
}
}
- if (sym_is_choice(sym))
+ if (sym_is_choice(sym) || sym->flags & SYMBOL_HIDDEN)
sym->flags &= ~SYMBOL_WRITE;
}
Let me know how that works for you (the new test passes here).
Vegard
[-- Attachment #2: hidden.patch --]
[-- Type: text/x-patch, Size: 2101 bytes --]
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index b2686dba05ece..37958ff57f707 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -214,6 +214,11 @@ static void sym_calc_visibility(struct symbol *sym)
struct property *prop;
tristate tri;
+ if (sym->flags & SYMBOL_HIDDEN) {
+ sym->visible = yes;
+ return;
+ }
+
/* any prompt visible? */
tri = no;
for_all_prompts(sym, prop) {
@@ -408,7 +413,6 @@ void sym_calc_value(struct symbol *sym)
struct symbol_value newval, oldval;
struct property *prop;
struct menu *choice_menu;
- bool usable;
if (!sym)
return;
@@ -448,13 +452,6 @@ void sym_calc_value(struct symbol *sym)
if (sym->visible != no)
sym->flags |= SYMBOL_WRITE;
- /*
- * For a symbol to be processed during configuration it needs to
- * be either visible or a transitional symbol that is hidden from
- * menus and omitted from newly written .config files.
- */
- usable = (sym->visible != no || (sym->flags & SYMBOL_HIDDEN));
-
/* set default if recursively called */
sym->curr = newval;
@@ -467,15 +464,13 @@ void sym_calc_value(struct symbol *sym)
sym_calc_choice(choice_menu);
newval.tri = sym->curr.tri;
} else {
- if (usable) {
+ if (sym->visible != no) {
/* if the symbol is visible use the user value
* if available, otherwise try the default value
*/
if (sym_has_value(sym)) {
- tristate value = (sym->flags & SYMBOL_HIDDEN) ?
- sym->def[S_DEF_USER].tri : sym->visible;
newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,
- value);
+ sym->visible);
goto calc_newval;
}
}
@@ -507,7 +502,7 @@ void sym_calc_value(struct symbol *sym)
case S_STRING:
case S_HEX:
case S_INT:
- if (usable && sym_has_value(sym)) {
+ if (sym->visible != no && sym_has_value(sym)) {
newval.val = sym->def[S_DEF_USER].val;
break;
}
@@ -536,7 +531,7 @@ void sym_calc_value(struct symbol *sym)
}
}
- if (sym_is_choice(sym))
+ if (sym_is_choice(sym) || sym->flags & SYMBOL_HIDDEN)
sym->flags &= ~SYMBOL_WRITE;
}
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH v2] kconfig: Add transitional symbol attribute for migration support
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:23 ` Kees Cook
1 sibling, 1 reply; 17+ messages in thread
From: Vegard Nossum @ 2025-09-04 17:10 UTC (permalink / raw)
To: Kees Cook
Cc: Nathan Chancellor, Nicolas Schier, Jonathan Corbet,
Masahiro Yamada, Randy Dunlap, Arnd Bergmann, Krzysztof Kozlowski,
linux-kbuild, linux-doc, Miguel Ojeda, Stephen Brennan,
Marco Bonelli, Petr Vorel, linux-kernel, linux-hardening
On 04/09/2025 19:03, Vegard Nossum wrote:
> @@ -214,6 +214,11 @@ static void sym_calc_visibility(struct symbol *sym)
> struct property *prop;
> tristate tri;
>
> + if (sym->flags & SYMBOL_HIDDEN) {
> + sym->visible = yes;
...I just saw the irony here after having already pressed "Send".
Let me explain:
SYMBOL_HIDDEN is your new flag that indicates that somebody used
"transitional" on the config entry.
sym->visible is tristate value that gives you the condition for whether
a symbol can take on a value -- y/m means the option is visible to the
user (hence the name) and thus eligible to have a value assigned to it.
In this case you've explicitly hidden the symbol from the user but you
_want_ it to be able to take on a value from the .config that was read in.
If we want to be perfectly clear, we'd rename SYMBOL_HIDDEN to
SYMBOL_TRANSITIONAL and rename sym->visible to sym->assignable or
something like that. Then the logic would be:
if (sym->flags & SYMBOL_TRANSITIONAL)
sym->assignable = yes;
which is much more intuitive.
Vegard
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v2] kconfig: Add transitional symbol attribute for migration support
2025-09-04 17:10 ` Vegard Nossum
@ 2025-09-05 9:41 ` Vegard Nossum
2025-09-05 16:24 ` Kees Cook
0 siblings, 1 reply; 17+ messages in thread
From: Vegard Nossum @ 2025-09-05 9:41 UTC (permalink / raw)
To: Kees Cook
Cc: Nathan Chancellor, Nicolas Schier, Jonathan Corbet,
Masahiro Yamada, Randy Dunlap, Arnd Bergmann, Krzysztof Kozlowski,
linux-kbuild, linux-doc, Miguel Ojeda, Stephen Brennan,
Marco Bonelli, Petr Vorel, linux-kernel, linux-hardening
On 04/09/2025 19:10, Vegard Nossum wrote:
> On 04/09/2025 19:03, Vegard Nossum wrote:
>> @@ -214,6 +214,11 @@ static void sym_calc_visibility(struct symbol *sym)
>> struct property *prop;
>> tristate tri;
>>
>> + if (sym->flags & SYMBOL_HIDDEN) {
>> + sym->visible = yes;
>
> ...I just saw the irony here after having already pressed "Send".
>
> Let me explain:
>
> SYMBOL_HIDDEN is your new flag that indicates that somebody used
> "transitional" on the config entry.
>
> sym->visible is tristate value that gives you the condition for whether
> a symbol can take on a value -- y/m means the option is visible to the
> user (hence the name) and thus eligible to have a value assigned to it.
Another small clarification: Replace "is visible to the user" by "can be
set by .config".
Actual user visibility is controlled by menu_is_visible(), not
sym->visible, so my patch still doesn't show transitional symbols to the
user in menuconfig. AFAICT, menu_is_visible() is completely independent
of sym->visible.
I tested menuconfig/mconf and oldconfig/conf --oldconfig with scripts/
kconfig/tests/transitional/Kconfig and my patch and it looks correct
(only the new options are displayed).
Vegard
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v2] kconfig: Add transitional symbol attribute for migration support
2025-09-05 9:41 ` Vegard Nossum
@ 2025-09-05 16:24 ` Kees Cook
0 siblings, 0 replies; 17+ messages in thread
From: Kees Cook @ 2025-09-05 16:24 UTC (permalink / raw)
To: Vegard Nossum
Cc: Nathan Chancellor, Nicolas Schier, Jonathan Corbet,
Masahiro Yamada, Randy Dunlap, Arnd Bergmann, Krzysztof Kozlowski,
linux-kbuild, linux-doc, Miguel Ojeda, Stephen Brennan,
Marco Bonelli, Petr Vorel, linux-kernel, linux-hardening
On Fri, Sep 05, 2025 at 11:41:18AM +0200, Vegard Nossum wrote:
>
> On 04/09/2025 19:10, Vegard Nossum wrote:
> > On 04/09/2025 19:03, Vegard Nossum wrote:
> > > @@ -214,6 +214,11 @@ static void sym_calc_visibility(struct symbol *sym)
> > > struct property *prop;
> > > tristate tri;
> > >
> > > + if (sym->flags & SYMBOL_HIDDEN) {
> > > + sym->visible = yes;
> >
> > ...I just saw the irony here after having already pressed "Send".
> >
> > Let me explain:
> >
> > SYMBOL_HIDDEN is your new flag that indicates that somebody used
> > "transitional" on the config entry.
> >
> > sym->visible is tristate value that gives you the condition for whether
> > a symbol can take on a value -- y/m means the option is visible to the
> > user (hence the name) and thus eligible to have a value assigned to it.
>
> Another small clarification: Replace "is visible to the user" by "can be
> set by .config".
>
> Actual user visibility is controlled by menu_is_visible(), not
> sym->visible, so my patch still doesn't show transitional symbols to the
> user in menuconfig. AFAICT, menu_is_visible() is completely independent
> of sym->visible.
Yeah, and I think this is another very good reason to rename stuff.
> I tested menuconfig/mconf and oldconfig/conf --oldconfig with scripts/
> kconfig/tests/transitional/Kconfig and my patch and it looks correct
> (only the new options are displayed).
Great! Thank you for looking at this. :)
--
Kees Cook
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v2] kconfig: Add transitional symbol attribute for migration support
2025-09-04 17:03 ` Vegard Nossum
2025-09-04 17:10 ` Vegard Nossum
@ 2025-09-05 16:23 ` Kees Cook
1 sibling, 0 replies; 17+ messages in thread
From: Kees Cook @ 2025-09-05 16:23 UTC (permalink / raw)
To: Vegard Nossum
Cc: Nathan Chancellor, Nicolas Schier, Jonathan Corbet,
Masahiro Yamada, Randy Dunlap, Arnd Bergmann, Krzysztof Kozlowski,
linux-kbuild, linux-doc, Miguel Ojeda, Stephen Brennan,
Marco Bonelli, Petr Vorel, linux-kernel, linux-hardening
On Thu, Sep 04, 2025 at 07:03:56PM +0200, Vegard Nossum wrote:
>
> On 04/09/2025 04:51, Kees Cook wrote:
> > On Mon, Sep 01, 2025 at 08:44:56PM +0200, Vegard Nossum wrote:
> > > If you change sym_calc_visibility() to always return 'yes' for
> > > transitional values then I don't think you need to touch
> > > sym_calc_value() at all.
> >
> > Hm, it looks like sym_calc_visibility() doesn't strictly just look at
> > visibility. And visibility seems to "last"? And I think the "tri" still
> > can't just be "yes", don't we need the other stuff handled?
> >
> > Do you see a way to do it how you're suggesting? And now I wrote the
> > regression tests so we can test any alternatives! ;)
>
> Here's what I had in mind (on top of your kcfi patchset), see the
> attachment.
>
> It basically undoes all your additions to sym_calc_value() in favour of
> two straightforward additions:
>
> @@ -214,6 +214,11 @@ static void sym_calc_visibility(struct symbol *sym)
> struct property *prop;
> tristate tri;
>
> + if (sym->flags & SYMBOL_HIDDEN) {
> + sym->visible = yes;
> + return;
> + }
> +
If this doesn't break "m" choices and the config doesn't show up in
menuconfig, then yeah, I can do this.
I'll give it a spin!
--
Kees Cook
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v2] kconfig: Add transitional symbol attribute for migration support
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 9:09 ` Jani Nikula
2025-09-01 16:48 ` Kees Cook
2025-09-01 16:39 ` Randy Dunlap
2 siblings, 1 reply; 17+ messages in thread
From: Jani Nikula @ 2025-09-01 9:09 UTC (permalink / raw)
To: Kees Cook, Nathan Chancellor
Cc: Kees Cook, Nicolas Schier, Jonathan Corbet, Masahiro Yamada,
Randy Dunlap, Arnd Bergmann, Krzysztof Kozlowski, linux-kbuild,
linux-doc, Miguel Ojeda, Stephen Brennan, Marco Bonelli,
Petr Vorel, linux-kernel, linux-hardening
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
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v2] kconfig: Add transitional symbol attribute for migration support
2025-09-01 9:09 ` Jani Nikula
@ 2025-09-01 16:48 ` Kees Cook
0 siblings, 0 replies; 17+ messages in thread
From: Kees Cook @ 2025-09-01 16:48 UTC (permalink / raw)
To: Jani Nikula
Cc: Nathan Chancellor, Nicolas Schier, Jonathan Corbet,
Masahiro Yamada, Randy Dunlap, Arnd Bergmann, Krzysztof Kozlowski,
linux-kbuild, linux-doc, Miguel Ojeda, Stephen Brennan,
Marco Bonelli, Petr Vorel, linux-kernel, linux-hardening
On Mon, Sep 01, 2025 at 12:09:14PM +0300, Jani Nikula wrote:
> On Fri, 29 Aug 2025, Kees Cook <kees@kernel.org> wrote:
> > 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?
As with the "manual" transitions, it'd probably be until the next LTS is
released.
--
Kees Cook
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v2] kconfig: Add transitional symbol attribute for migration support
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 9:09 ` Jani Nikula
@ 2025-09-01 16:39 ` Randy Dunlap
2025-09-01 16:45 ` Kees Cook
2 siblings, 1 reply; 17+ messages in thread
From: Randy Dunlap @ 2025-09-01 16:39 UTC (permalink / raw)
To: Kees Cook, Nathan Chancellor
Cc: Nicolas Schier, Jonathan Corbet, Masahiro Yamada, Arnd Bergmann,
Krzysztof Kozlowski, linux-kbuild, linux-doc, Miguel Ojeda,
Stephen Brennan, Marco Bonelli, Petr Vorel, linux-kernel,
linux-hardening
Hi Kees,
On 8/29/25 7:01 PM, Kees Cook 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.
>
> 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.
Are you (implicitly?) saying that all previous attempts at transitional
kconfig symbols have failed? If so, I just wasn't aware of that.
Or is there some new prime directive that requires this?
Thanks.
--
~Randy
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v2] kconfig: Add transitional symbol attribute for migration support
2025-09-01 16:39 ` Randy Dunlap
@ 2025-09-01 16:45 ` Kees Cook
2025-09-01 16:54 ` Randy Dunlap
0 siblings, 1 reply; 17+ messages in thread
From: Kees Cook @ 2025-09-01 16:45 UTC (permalink / raw)
To: Randy Dunlap
Cc: Nathan Chancellor, Nicolas Schier, Jonathan Corbet,
Masahiro Yamada, Arnd Bergmann, Krzysztof Kozlowski, linux-kbuild,
linux-doc, Miguel Ojeda, Stephen Brennan, Marco Bonelli,
Petr Vorel, linux-kernel, linux-hardening
On Mon, Sep 01, 2025 at 09:39:46AM -0700, Randy Dunlap wrote:
> Are you (implicitly?) saying that all previous attempts at transitional
> kconfig symbols have failed? If so, I just wasn't aware of that.
I haven't found any way to do a "proper" CONFIG transition. I looked
through past transitions and they all left stuff visible. Is there a way
to actually do this with existing kconfig?
--
Kees Cook
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v2] kconfig: Add transitional symbol attribute for migration support
2025-09-01 16:45 ` Kees Cook
@ 2025-09-01 16:54 ` Randy Dunlap
0 siblings, 0 replies; 17+ messages in thread
From: Randy Dunlap @ 2025-09-01 16:54 UTC (permalink / raw)
To: Kees Cook
Cc: Nathan Chancellor, Nicolas Schier, Jonathan Corbet,
Masahiro Yamada, Arnd Bergmann, Krzysztof Kozlowski, linux-kbuild,
linux-doc, Miguel Ojeda, Stephen Brennan, Marco Bonelli,
Petr Vorel, linux-kernel, linux-hardening
On 9/1/25 9:45 AM, Kees Cook wrote:
> On Mon, Sep 01, 2025 at 09:39:46AM -0700, Randy Dunlap wrote:
>> Are you (implicitly?) saying that all previous attempts at transitional
>> kconfig symbols have failed? If so, I just wasn't aware of that.
>
> I haven't found any way to do a "proper" CONFIG transition. I looked
> through past transitions and they all left stuff visible. Is there a way
> to actually do this with existing kconfig?
>
I don't know. I haven't looked as hard at it as you have.
I just didn't realize that there had been significant failures
that required kconfig code changes.
I'm just trying to understand. Carry on.
--
~Randy
^ permalink raw reply [flat|nested] 17+ messages in thread