Commit 0902b3cb authored by Kees Cook's avatar Kees Cook
Browse files

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: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Closes: https://lore.kernel.org/lkml/CAHk-=wgZjUk4Cy2XgNkTrQoO8XCmNUHrTe5D519Fij1POK+3qw@mail.gmail.com/
Fixes: f9afce4f ("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: default avatarKees Cook <kees@kernel.org>
parent fd94619c
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -411,7 +411,7 @@ bool sym_dep_errors(void)
void sym_calc_value(struct symbol *sym)
{
	struct symbol_value newval, oldval;
	struct property *prop;
	struct property *prop = NULL;
	struct menu *choice_menu;

	if (!sym)
@@ -520,6 +520,19 @@ void sym_calc_value(struct symbol *sym)
		;
	}

	/*
	 * If the symbol lacks a user value but its value comes from a
	 * single transitional symbol with an existing user value, mark
	 * this symbol as having a user value to avoid prompting.
	 */
	if (prop && !sym_has_value(sym)) {
		struct symbol *ds = prop_get_symbol(prop);
		if (ds && (ds->flags & SYMBOL_TRANS) && sym_has_value(ds)) {
			sym->def[S_DEF_USER] = newval;
			sym->flags |= SYMBOL_DEF_USER;
		}
	}

	sym->curr = newval;
	sym_validate_range(sym);

+32 −0
Original line number Diff line number Diff line
@@ -96,5 +96,37 @@ config OLD_WITH_HELP
	help
	  This transitional symbol has a help section to validate that help is allowed.

# Test that we can set something to =n via transitional symbol
config NEW_DISABLED
	tristate "Check for setting to disabled"
	default OLD_DISABLED

config OLD_DISABLED
	tristate
	transitional

# Test that a potential new value disappears if it lacks a prompt
config NEW_DISABLED_UNSAVED
	tristate
	default OLD_DISABLED

config OLD_DISABLED_UNSAVED
	tristate
	transitional

# Test conditional default: transitional value should not prevent prompting
# when default visibility makes the expression evaluate to 'no'
config DEPENDENCY_TEST
	bool "Dependency for testing"
	default n

config NEW_CONDITIONAL_DEFAULT
	bool "New option with conditional default"
	default OLD_CONDITIONAL_DEFAULT if DEPENDENCY_TEST

config OLD_CONDITIONAL_DEFAULT
	bool
	transitional

config REGULAR_OPTION
	bool "Regular option"
+7 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ This tests that:
- OLD_* options in existing .config cause NEW_* options to be set
- OLD_* options are not written to the new .config file
- NEW_* options appear in the new .config file with correct values
- NEW_* options with defaults from transitional symbols are not prompted
- All Kconfig types work correctly: bool, tristate, string, hex, int
- User-set NEW values take precedence over conflicting OLD transitional values
"""
@@ -16,3 +17,9 @@ def test(conf):

    # Check that the configuration matches expected output
    assert conf.config_contains('expected_config')

    # Test oldconfig to ensure symbols with transitional defaults are not prompted
    assert conf.oldconfig(dot_config='initial_config', in_keys='n\n') == 0

    # Except for when conditional default evaluates to 'no'
    assert conf.stdout_contains('expected_stdout')
+3 −0
Original line number Diff line number Diff line
@@ -9,4 +9,7 @@ CONFIG_NEW_STRING_PRECEDENCE="user value"
CONFIG_NEW_TRISTATE_PRECEDENCE=y
CONFIG_NEW_HEX_PRECEDENCE=0xABCD
CONFIG_NEW_INT_PRECEDENCE=100
# CONFIG_NEW_DISABLED is not set
# CONFIG_DEPENDENCY_TEST is not set
# CONFIG_NEW_CONDITIONAL_DEFAULT is not set
# CONFIG_REGULAR_OPTION is not set
+1 −0
Original line number Diff line number Diff line
New option with conditional default (NEW_CONDITIONAL_DEFAULT) [N/y/?] (NEW) n
Loading