1 /*
2 * Copyright 2015 David Herrmann <[email protected]>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 /*
25 * Testcase: drmGetMagic() and drmAuthMagic()
26 */
27
28 #include "igt.h"
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <signal.h>
35 #include <fcntl.h>
36 #include <inttypes.h>
37 #include <errno.h>
38 #include <sched.h>
39 #include <sys/mount.h>
40 #include <sys/stat.h>
41 #include <sys/ioctl.h>
42 #include <sys/time.h>
43 #include <sys/poll.h>
44 #include <sys/resource.h>
45 #include "drm.h"
46
47 #ifndef __linux__
48 # include <pthread.h>
49 #endif
50
51 IGT_TEST_DESCRIPTION("Call drmGetMagic() and drmAuthMagic() and see if it behaves.");
52
53 static bool
is_local_tid(pid_t tid)54 is_local_tid(pid_t tid)
55 {
56 #ifndef __linux__
57 return pthread_self() == tid;
58 #else
59 /* On Linux systems, drmGetClient() would return the thread ID
60 instead of the actual process ID */
61 return gettid() == tid;
62 #endif
63 }
64
65
check_auth(int fd)66 static bool check_auth(int fd)
67 {
68 pid_t client_pid;
69 int i, auth, pid, uid;
70 unsigned long magic, iocs;
71 bool is_authenticated = false;
72
73 client_pid = getpid();
74 for (i = 0; !is_authenticated; i++) {
75 if (drmGetClient(fd, i, &auth, &pid, &uid, &magic, &iocs) != 0)
76 break;
77 is_authenticated = auth && (pid == client_pid || is_local_tid(pid));
78 }
79 return is_authenticated;
80 }
81
82
magic_cmp(const void * p1,const void * p2)83 static int magic_cmp(const void *p1, const void *p2)
84 {
85 return *(const drm_magic_t*)p1 < *(const drm_magic_t*)p2;
86 }
87
test_many_magics(int master)88 static void test_many_magics(int master)
89 {
90 drm_magic_t magic, *magics = NULL;
91 unsigned int i, j, ns, allocated = 0;
92 char path[512];
93 int *fds = NULL, slave;
94
95 struct rlimit fd_limit;
96
97 do_or_die(getrlimit(RLIMIT_NOFILE, &fd_limit));
98 fd_limit.rlim_cur = 1024;
99 do_or_die(setrlimit(RLIMIT_NOFILE, &fd_limit));
100
101 sprintf(path, "/proc/self/fd/%d", master);
102
103 for (i = 0; ; ++i) {
104 /* open slave and make sure it's NOT a master */
105 slave = open(path, O_RDWR | O_CLOEXEC);
106 if (slave < 0) {
107 igt_info("Reopening device failed after %d opens\n", i);
108 igt_assert(errno == EMFILE);
109 break;
110 }
111 igt_assert(drmSetMaster(slave) < 0);
112
113 /* resize magic-map */
114 if (i >= allocated) {
115 ns = allocated * 2;
116 igt_assert(ns >= allocated);
117
118 if (!ns)
119 ns = 128;
120
121 magics = realloc(magics, sizeof(*magics) * ns);
122 igt_assert(magics);
123
124 fds = realloc(fds, sizeof(*fds) * ns);
125 igt_assert(fds);
126
127 allocated = ns;
128 }
129
130 /* insert magic */
131 igt_assert(drmGetMagic(slave, &magic) == 0);
132 igt_assert(magic > 0);
133
134 magics[i] = magic;
135 fds[i] = slave;
136 }
137
138 /* make sure we could at least open a reasonable number of files */
139 igt_assert(i > 128);
140
141 /*
142 * We cannot open the DRM file anymore. Lets sort the magic-map and
143 * verify no magic was used multiple times.
144 */
145 qsort(magics, i, sizeof(*magics), magic_cmp);
146 for (j = 1; j < i; ++j)
147 igt_assert(magics[j] != magics[j - 1]);
148
149 /* make sure we can authenticate all of them */
150 for (j = 0; j < i; ++j)
151 igt_assert(drmAuthMagic(master, magics[j]) == 0);
152
153 /* close files again */
154 for (j = 0; j < i; ++j)
155 close(fds[j]);
156
157 free(fds);
158 free(magics);
159 }
160
test_basic_auth(int master)161 static void test_basic_auth(int master)
162 {
163 drm_magic_t magic, old_magic;
164 int slave;
165
166 /* open slave and make sure it's NOT a master */
167 slave = drm_open_driver(DRIVER_ANY);
168 igt_require(slave >= 0);
169 igt_require(drmSetMaster(slave) < 0);
170
171 /* retrieve magic for slave */
172 igt_assert(drmGetMagic(slave, &magic) == 0);
173 igt_assert(magic > 0);
174
175 /* verify the same magic is returned every time */
176 old_magic = magic;
177 igt_assert(drmGetMagic(slave, &magic) == 0);
178 igt_assert_eq(magic, old_magic);
179
180 /* verify magic can be authorized exactly once, on the master */
181 igt_assert(drmAuthMagic(slave, magic) < 0);
182 igt_assert(drmAuthMagic(master, magic) == 0);
183 igt_assert(drmAuthMagic(master, magic) < 0);
184
185 /* verify that the magic did not change */
186 old_magic = magic;
187 igt_assert(drmGetMagic(slave, &magic) == 0);
188 igt_assert_eq(magic, old_magic);
189
190 close(slave);
191 }
192
193 igt_main
194 {
195 int master;
196
197 /* root (which we run igt as) should always be authenticated */
198 igt_subtest("getclient-simple") {
199 int fd = drm_open_driver(DRIVER_ANY);
200
201 igt_assert(check_auth(fd) == true);
202
203 close(fd);
204 }
205
206 igt_subtest("getclient-master-drop") {
207 int fd = drm_open_driver(DRIVER_ANY);
208 int fd2 = drm_open_driver(DRIVER_ANY);
209
210 igt_assert(check_auth(fd2) == true);
211
212 close(fd);
213
214 igt_assert(check_auth(fd2) == true);
215
216 close(fd2);
217 }
218
219 /* above tests require that no drm fd is open */
220 igt_subtest_group {
221 igt_fixture
222 master = drm_open_driver_master(DRIVER_ANY);
223
224 igt_subtest("basic-auth")
225 test_basic_auth(master);
226
227 /* this must be last, we adjust the rlimit */
228 igt_subtest("many-magics")
229 test_many_magics(master);
230 }
231 }
232