Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kconfig: Avoid prompting for transitional symbols

The "transitional" symbol keyword, while working with the "olddefconfig"
target, was prompting during "oldconfig". This occurred because these
symbols were not being marked as user-defined when they received values
from transitional symbols that had user values. The "olddefconfig" target
explicitly doesn't prompt for anything, so this deficiency wasn't noticed.

The issue manifested when a symbol's value came from a transitional
symbol's user value but the receiving symbol wasn't marked with
SYMBOL_DEF_USER. Thus the "oldconfig" logic would then prompt for these
symbols unnecessarily.

Check after value calculation whether a symbol without a user value
gets its value from a single transitional symbol that does have a user
value. In such cases, mark the receiving symbol as user-defined to
prevent prompting.

Update regression tests to verify that symbols with transitional defaults
are not prompted in "oldconfig", except when conditional defaults evaluate
to 'no' and should legitimately be prompted.

Build tested with "make testconfig".

Reported-by: Linus Torvalds <torvalds@linux-foundation.org>
Closes: https://lore.kernel.org/lkml/CAHk-=wgZjUk4Cy2XgNkTrQoO8XCmNUHrTe5D519Fij1POK+3qw@mail.gmail.com/
Fixes: f9afce4f32e9 ("kconfig: Add transitional symbol attribute for migration support")
Cc: Vegard Nossum <vegard.nossum@oracle.com>
Link: https://lore.kernel.org/r/20250930154514.it.623-kees@kernel.org
Signed-off-by: Kees Cook <kees@kernel.org>

Kees Cook 0902b3cb fd94619c

+61 -1
+14 -1
scripts/kconfig/symbol.c
··· 411 411 void sym_calc_value(struct symbol *sym) 412 412 { 413 413 struct symbol_value newval, oldval; 414 - struct property *prop; 414 + struct property *prop = NULL; 415 415 struct menu *choice_menu; 416 416 417 417 if (!sym) ··· 518 518 break; 519 519 default: 520 520 ; 521 + } 522 + 523 + /* 524 + * If the symbol lacks a user value but its value comes from a 525 + * single transitional symbol with an existing user value, mark 526 + * this symbol as having a user value to avoid prompting. 527 + */ 528 + if (prop && !sym_has_value(sym)) { 529 + struct symbol *ds = prop_get_symbol(prop); 530 + if (ds && (ds->flags & SYMBOL_TRANS) && sym_has_value(ds)) { 531 + sym->def[S_DEF_USER] = newval; 532 + sym->flags |= SYMBOL_DEF_USER; 533 + } 521 534 } 522 535 523 536 sym->curr = newval;
+32
scripts/kconfig/tests/transitional/Kconfig
··· 96 96 help 97 97 This transitional symbol has a help section to validate that help is allowed. 98 98 99 + # Test that we can set something to =n via transitional symbol 100 + config NEW_DISABLED 101 + tristate "Check for setting to disabled" 102 + default OLD_DISABLED 103 + 104 + config OLD_DISABLED 105 + tristate 106 + transitional 107 + 108 + # Test that a potential new value disappears if it lacks a prompt 109 + config NEW_DISABLED_UNSAVED 110 + tristate 111 + default OLD_DISABLED 112 + 113 + config OLD_DISABLED_UNSAVED 114 + tristate 115 + transitional 116 + 117 + # Test conditional default: transitional value should not prevent prompting 118 + # when default visibility makes the expression evaluate to 'no' 119 + config DEPENDENCY_TEST 120 + bool "Dependency for testing" 121 + default n 122 + 123 + config NEW_CONDITIONAL_DEFAULT 124 + bool "New option with conditional default" 125 + default OLD_CONDITIONAL_DEFAULT if DEPENDENCY_TEST 126 + 127 + config OLD_CONDITIONAL_DEFAULT 128 + bool 129 + transitional 130 + 99 131 config REGULAR_OPTION 100 132 bool "Regular option"
+7
scripts/kconfig/tests/transitional/__init__.py
··· 6 6 - OLD_* options in existing .config cause NEW_* options to be set 7 7 - OLD_* options are not written to the new .config file 8 8 - NEW_* options appear in the new .config file with correct values 9 + - NEW_* options with defaults from transitional symbols are not prompted 9 10 - All Kconfig types work correctly: bool, tristate, string, hex, int 10 11 - User-set NEW values take precedence over conflicting OLD transitional values 11 12 """ ··· 17 16 18 17 # Check that the configuration matches expected output 19 18 assert conf.config_contains('expected_config') 19 + 20 + # Test oldconfig to ensure symbols with transitional defaults are not prompted 21 + assert conf.oldconfig(dot_config='initial_config', in_keys='n\n') == 0 22 + 23 + # Except for when conditional default evaluates to 'no' 24 + assert conf.stdout_contains('expected_stdout')
+3
scripts/kconfig/tests/transitional/expected_config
··· 9 9 CONFIG_NEW_TRISTATE_PRECEDENCE=y 10 10 CONFIG_NEW_HEX_PRECEDENCE=0xABCD 11 11 CONFIG_NEW_INT_PRECEDENCE=100 12 + # CONFIG_NEW_DISABLED is not set 13 + # CONFIG_DEPENDENCY_TEST is not set 14 + # CONFIG_NEW_CONDITIONAL_DEFAULT is not set 12 15 # CONFIG_REGULAR_OPTION is not set
+1
scripts/kconfig/tests/transitional/expected_stdout
··· 1 + New option with conditional default (NEW_CONDITIONAL_DEFAULT) [N/y/?] (NEW) n
+4
scripts/kconfig/tests/transitional/initial_config
··· 14 14 CONFIG_OLD_HEX_PRECEDENCE=0x5678 15 15 CONFIG_NEW_INT_PRECEDENCE=100 16 16 CONFIG_OLD_INT_PRECEDENCE=200 17 + # CONFIG_OLD_DISABLED is not set 18 + # CONFIG_OLD_DISABLED_UNSAVED is not set 19 + # CONFIG_DEPENDENCY_TEST is not set 20 + CONFIG_OLD_CONDITIONAL_DEFAULT=y