Commit d8b9faec authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'drm-fixes-2020-07-31' of git://anongit.freedesktop.org/drm/drm

Pull more drm fixes from Dave Airlie:
 "As mentioned previously this contains the nouveau regression fix.

  amdgpu had three fixes outstanding as well, one revert, an info leak
  and use after free. The use after free is a bit trickier than I'd
  like, and I've personally gone over it to confirm I'm happy that it is
  doing what it says.

  nouveau:
   - final modifiers regression fix

  amdgpu:
   - Revert a fix which caused other regressions
   - Fix potential kernel info leak
   - Fix a use-after-free bug that was uncovered by another change in 5.7"

* tag 'drm-fixes-2020-07-31' of git://anongit.freedesktop.org/drm/drm:
  drm/nouveau: Accept 'legacy' format modifiers
  Revert "drm/amdgpu: Fix NULL dereference in dpm sysfs handlers"
  drm/amd/display: Clear dm_state for fast updates
  drm/amdgpu: Prevent kernel-infoleak in amdgpu_info_ioctl()
parents a2ec905d 887c909d
...@@ -692,9 +692,10 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file ...@@ -692,9 +692,10 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
return n ? -EFAULT : 0; return n ? -EFAULT : 0;
} }
case AMDGPU_INFO_DEV_INFO: { case AMDGPU_INFO_DEV_INFO: {
struct drm_amdgpu_info_device dev_info = {}; struct drm_amdgpu_info_device dev_info;
uint64_t vm_size; uint64_t vm_size;
memset(&dev_info, 0, sizeof(dev_info));
dev_info.device_id = dev->pdev->device; dev_info.device_id = dev->pdev->device;
dev_info.chip_rev = adev->rev_id; dev_info.chip_rev = adev->rev_id;
dev_info.external_rev = adev->external_rev_id; dev_info.external_rev = adev->external_rev_id;
......
...@@ -778,7 +778,8 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev, ...@@ -778,7 +778,8 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev,
tmp_str++; tmp_str++;
while (isspace(*++tmp_str)); while (isspace(*++tmp_str));
while ((sub_str = strsep(&tmp_str, delimiter)) != NULL) { while (tmp_str[0]) {
sub_str = strsep(&tmp_str, delimiter);
ret = kstrtol(sub_str, 0, &parameter[parameter_size]); ret = kstrtol(sub_str, 0, &parameter[parameter_size]);
if (ret) if (ret)
return -EINVAL; return -EINVAL;
...@@ -1038,7 +1039,8 @@ static ssize_t amdgpu_read_mask(const char *buf, size_t count, uint32_t *mask) ...@@ -1038,7 +1039,8 @@ static ssize_t amdgpu_read_mask(const char *buf, size_t count, uint32_t *mask)
memcpy(buf_cpy, buf, bytes); memcpy(buf_cpy, buf, bytes);
buf_cpy[bytes] = '\0'; buf_cpy[bytes] = '\0';
tmp = buf_cpy; tmp = buf_cpy;
while ((sub_str = strsep(&tmp, delimiter)) != NULL) { while (tmp[0]) {
sub_str = strsep(&tmp, delimiter);
if (strlen(sub_str)) { if (strlen(sub_str)) {
ret = kstrtol(sub_str, 0, &level); ret = kstrtol(sub_str, 0, &level);
if (ret) if (ret)
...@@ -1635,7 +1637,8 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev, ...@@ -1635,7 +1637,8 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev,
i++; i++;
memcpy(buf_cpy, buf, count-i); memcpy(buf_cpy, buf, count-i);
tmp_str = buf_cpy; tmp_str = buf_cpy;
while ((sub_str = strsep(&tmp_str, delimiter)) != NULL) { while (tmp_str[0]) {
sub_str = strsep(&tmp_str, delimiter);
ret = kstrtol(sub_str, 0, &parameter[parameter_size]); ret = kstrtol(sub_str, 0, &parameter[parameter_size]);
if (ret) if (ret)
return -EINVAL; return -EINVAL;
......
...@@ -8717,20 +8717,38 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, ...@@ -8717,20 +8717,38 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
* the same resource. If we have a new DC context as part of * the same resource. If we have a new DC context as part of
* the DM atomic state from validation we need to free it and * the DM atomic state from validation we need to free it and
* retain the existing one instead. * retain the existing one instead.
*
* Furthermore, since the DM atomic state only contains the DC
* context and can safely be annulled, we can free the state
* and clear the associated private object now to free
* some memory and avoid a possible use-after-free later.
*/ */
struct dm_atomic_state *new_dm_state, *old_dm_state;
new_dm_state = dm_atomic_get_new_state(state); for (i = 0; i < state->num_private_objs; i++) {
old_dm_state = dm_atomic_get_old_state(state); struct drm_private_obj *obj = state->private_objs[i].ptr;
if (new_dm_state && old_dm_state) { if (obj->funcs == adev->dm.atomic_obj.funcs) {
if (new_dm_state->context) int j = state->num_private_objs-1;
dc_release_state(new_dm_state->context);
new_dm_state->context = old_dm_state->context; dm_atomic_destroy_state(obj,
state->private_objs[i].state);
/* If i is not at the end of the array then the
* last element needs to be moved to where i was
* before the array can safely be truncated.
*/
if (i != j)
state->private_objs[i] =
state->private_objs[j];
if (old_dm_state->context) state->private_objs[j].ptr = NULL;
dc_retain_state(old_dm_state->context); state->private_objs[j].state = NULL;
state->private_objs[j].old_state = NULL;
state->private_objs[j].new_state = NULL;
state->num_private_objs = j;
break;
}
} }
} }
......
...@@ -191,6 +191,7 @@ nouveau_decode_mod(struct nouveau_drm *drm, ...@@ -191,6 +191,7 @@ nouveau_decode_mod(struct nouveau_drm *drm,
uint32_t *tile_mode, uint32_t *tile_mode,
uint8_t *kind) uint8_t *kind)
{ {
struct nouveau_display *disp = nouveau_display(drm->dev);
BUG_ON(!tile_mode || !kind); BUG_ON(!tile_mode || !kind);
if (modifier == DRM_FORMAT_MOD_LINEAR) { if (modifier == DRM_FORMAT_MOD_LINEAR) {
...@@ -202,6 +203,12 @@ nouveau_decode_mod(struct nouveau_drm *drm, ...@@ -202,6 +203,12 @@ nouveau_decode_mod(struct nouveau_drm *drm,
* Extract the block height and kind from the corresponding * Extract the block height and kind from the corresponding
* modifier fields. See drm_fourcc.h for details. * modifier fields. See drm_fourcc.h for details.
*/ */
if ((modifier & (0xffull << 12)) == 0ull) {
/* Legacy modifier. Translate to this dev's 'kind.' */
modifier |= disp->format_modifiers[0] & (0xffull << 12);
}
*tile_mode = (uint32_t)(modifier & 0xF); *tile_mode = (uint32_t)(modifier & 0xF);
*kind = (uint8_t)((modifier >> 12) & 0xFF); *kind = (uint8_t)((modifier >> 12) & 0xFF);
...@@ -227,6 +234,16 @@ nouveau_framebuffer_get_layout(struct drm_framebuffer *fb, ...@@ -227,6 +234,16 @@ nouveau_framebuffer_get_layout(struct drm_framebuffer *fb,
} }
} }
static const u64 legacy_modifiers[] = {
DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0),
DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1),
DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2),
DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3),
DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4),
DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5),
DRM_FORMAT_MOD_INVALID
};
static int static int
nouveau_validate_decode_mod(struct nouveau_drm *drm, nouveau_validate_decode_mod(struct nouveau_drm *drm,
uint64_t modifier, uint64_t modifier,
...@@ -247,8 +264,14 @@ nouveau_validate_decode_mod(struct nouveau_drm *drm, ...@@ -247,8 +264,14 @@ nouveau_validate_decode_mod(struct nouveau_drm *drm,
(disp->format_modifiers[mod] != modifier); (disp->format_modifiers[mod] != modifier);
mod++); mod++);
if (disp->format_modifiers[mod] == DRM_FORMAT_MOD_INVALID) if (disp->format_modifiers[mod] == DRM_FORMAT_MOD_INVALID) {
return -EINVAL; for (mod = 0;
(legacy_modifiers[mod] != DRM_FORMAT_MOD_INVALID) &&
(legacy_modifiers[mod] != modifier);
mod++);
if (legacy_modifiers[mod] == DRM_FORMAT_MOD_INVALID)
return -EINVAL;
}
nouveau_decode_mod(drm, modifier, tile_mode, kind); nouveau_decode_mod(drm, modifier, tile_mode, kind);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment