From owner-svn-src-all@FreeBSD.ORG Mon Nov 25 11:15:52 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 835DA144; Mon, 25 Nov 2013 11:15:52 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 584C52167; Mon, 25 Nov 2013 11:15:52 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id rAPBFqfh007135; Mon, 25 Nov 2013 11:15:52 GMT (envelope-from dumbbell@svn.freebsd.org) Received: (from dumbbell@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id rAPBFqoJ007134; Mon, 25 Nov 2013 11:15:52 GMT (envelope-from dumbbell@svn.freebsd.org) Message-Id: <201311251115.rAPBFqoJ007134@svn.freebsd.org> From: Jean-Sebastien Pedron Date: Mon, 25 Nov 2013 11:15:52 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r258549 - head/sys/dev/drm2 X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 25 Nov 2013 11:15:52 -0000 Author: dumbbell Date: Mon Nov 25 11:15:51 2013 New Revision: 258549 URL: http://svnweb.freebsd.org/changeset/base/258549 Log: drm: Dereference pointers given to qsort_r()'s cmp callback drm_le_cmp() (qsort_r()'s callback) receives pointers to elements in the array passed to qsort_r(), not the elements themselves. Before this fix, the use of qsort_r() shuffled the array, not sorted it, because the compare callback accessed random memory locations, not the expected elements. This bug triggered an infinite loop in KDE/xserver: 1. KDE has a kded module called "randrmonitor" which queries xserver for current monitors at startup and then listens to RandR notifications from xserver. 2. xserver handles the query from "randrmonitor" by polling the video device using the "drm_mode_getconnector()" ioctl. This ioctl returns a list of connectors and, for those with a connected monitor, the available modes. Each modes list is sorted by the kernel before returning. When xserver gets the connectors list, it sorts the modes lists again. In the case of this bug, when two modes are equal (in xserver's compare function PoV), their order is kept stable (ie. the kernel order is kept for those two modes). And because the list was shuffled by the kernel, the order of two equal modes was frequently changed in the final modes list in xserver. 3. xserver compares the returned connectors list with the list obtained earlier. In particular, it compares the sorted modes lists for each connector. If a property of a connector changes (eg. modes), xserver sends a "RRNotify_OutputChange" notification. Because of the change of order between equal modes, xserver sent a notification after each polling of the connectors. 4. "randrmonitor" receives a notification, triggered by its query. The notification doesn't contain the new connectors list, therefore, it asks for the new list using the same function: go back to step #2. MFC after: 3 days Modified: head/sys/dev/drm2/drm_linux_list_sort.c Modified: head/sys/dev/drm2/drm_linux_list_sort.c ============================================================================== --- head/sys/dev/drm2/drm_linux_list_sort.c Mon Nov 25 11:02:58 2013 (r258548) +++ head/sys/dev/drm2/drm_linux_list_sort.c Mon Nov 25 11:15:51 2013 (r258549) @@ -42,8 +42,8 @@ drm_le_cmp(void *priv, const void *d1, c struct drm_list_sort_thunk *thunk; thunk = priv; - le1 = __DECONST(struct list_head *, d1); - le2 = __DECONST(struct list_head *, d2); + le1 = *(struct list_head **)d1; + le2 = *(struct list_head **)d2; return ((thunk->cmp)(thunk->priv, le1, le2)); }