]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/amd/pm: Add empty string validation to sysfs store functions
authorVitaly Prosyak <vitaly.prosyak@amd.com>
Thu, 23 Apr 2026 23:44:33 +0000 (19:44 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 3 Jun 2026 17:52:09 +0000 (13:52 -0400)
Discovery: Fuzzing for secure supply chain requirements
Tool: amd_fuzzing_sysfs (IGT test)

The AMDGPU power management sysfs store functions accept whitespace-only
strings when they should reject them with -EINVAL. This was discovered via
systematic fuzzing of sysfs interfaces crossing the user/kernel trust
boundary.

Affected functions:
- amdgpu_set_power_dpm_force_performance_level (power_dpm_force_performance_level)
- amdgpu_set_power_dpm_state (power_dpm_state)
- amdgpu_set_pp_power_profile_mode (pp_power_profile_mode)
- amdgpu_read_mask (used by pp_dpm_sclk/mclk/fclk/socclk/pcie)
- amdgpu_set_pp_features (pp_features)

Impact:
- Whitespace-only writes (e.g., "\n", " ") can cause unexpected behavior
- Better input validation at user/kernel trust boundary
- Defense-in-depth improvement

Root Cause:
The sysfs_streq() function matches whitespace-only strings against empty
string, allowing invalid input to be processed.

Fix:
Add explicit validation at the start of each affected store function:

    if (count == 0 || sysfs_streq(buf, ""))
        return -EINVAL;

This rejects whitespace-only inputs before they are processed. Note that
write() calls with count=0 (truly empty strings) are handled by the VFS
layer before reaching the sysfs .store() callback - the VFS returns 0
(success) without calling the kernel function. This is POSIX-compliant
behavior and cannot be changed at the kernel driver level.

What This Patch Fixes:
- Whitespace-only strings: "\n", " ", "  ", etc. are now rejected
- Defense-in-depth: Explicit validation at trust boundary
- Code clarity: Intent to reject invalid input is explicit

What This Patch Cannot Fix:
- write(fd, "", 0) returning success - this is VFS layer behavior
- Fuzzer tests for empty strings (count=0) will still report "accepted"
  because the VFS handles this before the kernel callback

Test Results After Fix:
- Whitespace strings ("\n", " ") now properly rejected
- Empty string tests (count=0) still show as "accepted" due to VFS behavior
- Overall improvement in input validation robustness
- No impact on valid inputs

This is a defense-in-depth improvement that hardens input validation
even though VFS layer behavior prevents catching all edge cases.

Tested: amd_fuzzing_sysfs IGT test

Cc: Christian König <christian.koenig@amd.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: Jesse Zhang <jesse.zhang@amd.com>
Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/pm/amdgpu_pm.c

index bb11f8bb7bd4b062d0e36257d0eb33057c0a2037..a0250431ad1120fad0d39457cc5d42952550e507 100644 (file)
@@ -244,6 +244,10 @@ static ssize_t amdgpu_set_power_dpm_state(struct device *dev,
        enum amd_pm_state_type  state;
        int ret;
 
+       /* Reject empty/whitespace strings - fuzzing found this is not validated */
+       if (count == 0 || sysfs_streq(buf, ""))
+               return -EINVAL;
+
        if (sysfs_streq(buf, "battery"))
                state = POWER_STATE_TYPE_BATTERY;
        else if (sysfs_streq(buf, "balanced"))
@@ -364,6 +368,10 @@ static ssize_t amdgpu_set_power_dpm_force_performance_level(struct device *dev,
        enum amd_dpm_forced_level level;
        int ret = 0;
 
+       /* Reject empty/whitespace strings - fuzzing found this is not validated */
+       if (count == 0 || sysfs_streq(buf, ""))
+               return -EINVAL;
+
        if (sysfs_streq(buf, "low"))
                level = AMD_DPM_FORCED_LEVEL_LOW;
        else if (sysfs_streq(buf, "high"))
@@ -902,6 +910,10 @@ static ssize_t amdgpu_set_pp_features(struct device *dev,
        uint64_t featuremask;
        int ret;
 
+       /* Reject empty/whitespace strings - fuzzing found kstrtou64 accepts "" as 0 */
+       if (count == 0 || sysfs_streq(buf, ""))
+               return -EINVAL;
+
        ret = kstrtou64(buf, 0, &featuremask);
        if (ret)
                return -EINVAL;
@@ -1027,6 +1039,10 @@ static ssize_t amdgpu_read_mask(const char *buf, size_t count, uint32_t *mask)
 
        *mask = 0;
 
+       /* Reject empty/whitespace strings - fuzzing found this is not validated */
+       if (count == 0 || sysfs_streq(buf, ""))
+               return -EINVAL;
+
        bytes = min(count, sizeof(buf_cpy) - 1);
        memcpy(buf_cpy, buf, bytes);
        buf_cpy[bytes] = '\0';
@@ -1378,6 +1394,10 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev,
        long int profile_mode = 0;
        const char delimiter[3] = {' ', '\n', '\0'};
 
+       /* Reject empty/whitespace strings - fuzzing found this is not validated */
+       if (count == 0 || sysfs_streq(buf, ""))
+               return -EINVAL;
+
        tmp[0] = *(buf);
        tmp[1] = '\0';
        ret = kstrtol(tmp, 0, &profile_mode);