1
2
3
4
5
6
7
8 diff --git a/configure.ac b/configure.ac
9 index 2c92dc9..5ce6c55 100644
10 --- a/configure.ac
11 +++ b/configure.ac
12 @@ -233,6 +233,7 @@ AC_CHECK_HEADERS(\
13 stdint.h \
14 strings.h \
15 sys/asoundlib.h \
16 + sys/capability.h \
17 sys/cdio.h \
18 sys/elf32.h \
19 sys/epoll.h \
20 @@ -1193,6 +1194,7 @@ then
21 WINE_GET_SONAME(ungif,DGifOpen)
22 WINE_GET_SONAME(gif,DGifOpen)
23 WINE_GET_SONAME(capi20,capi20_isinstalled)
24 + WINE_GET_SONAME(cap,cap_set_proc)
25 fi
26
27
28 diff --git a/server/main.c b/server/main.c
29 index 43d3cf7..d283c12 100644
30 --- a/server/main.c
31 +++ b/server/main.c
32 @@ -28,6 +28,13 @@
33 #include <stdlib.h>
34 #include <sys/time.h>
35 #include <unistd.h>
36 +#include <dlfcn.h>
37 +
38 +#if defined(HAVE_SYS_CAPABILITY_H) && defined(HAVE_SYS_PRCTL_H) && defined(SONAME_LIBCAP)
39 +#define USE_CAPS
40 +#include <sys/capability.h>
41 +#include <sys/prctl.h>
42 +#endif
43
44 #include "object.h"
45 #include "file.h"
46 @@ -108,6 +115,51 @@ static void parse_args( int argc, char *
47 }
48 }
49
50 +static void setup_security()
51 +{
52 +#ifdef USE_CAPS
53 + cap_t cap;
54 +
55 + typeof(cap_set_proc) *cap_set_proc;
56 + typeof(cap_from_text) *cap_from_text;
57 + typeof(cap_free) *cap_free;
58 + void *libcap;
59 +
60 + if (geteuid() != 0) return;
61 + if (getuid() == 0) return;
62 +
63 +
64 + if ((libcap = dlopen( SONAME_LIBCAP, RTLD_LAZY )))
65 + {
66 + cap_set_proc = dlsym( libcap, "cap_set_proc" );
67 + cap_from_text = dlsym( libcap, "cap_from_text" );
68 + cap_free = dlsym( libcap, "cap_free" );
69 +
70 +
71 + assert( cap_set_proc );
72 + assert( cap_from_text );
73 + assert( cap_free );
74 +
75 +
76 + prctl( PR_SET_KEEPCAPS, 1, 0, 0, 0 );
77 + }
78 +
79 +
80 + setuid( getuid() );
81 +
82 + if (libcap)
83 + {
84 +
85 + if (cap_set_proc((cap = cap_from_text( "CAP_SYS_NICE+pe" ))) < 0)
86 + {
87 + perror( "wineserver: cap_set_proc: failed to drop privs, aborting" );
88 + exit( 1 );
89 + }
90 + cap_free(cap);
91 + }
92 +#endif
93 +}
94 +
95 static void sigterm_handler( int signum )
96 {
97 exit(1);
98 @@ -115,6 +167,8 @@ static void sigterm_handler( int signum
99
100 int main( int argc, char *argv[] )
101 {
102 + setup_security();
103 +
104 parse_args( argc, argv );
105
106
107 diff --git a/server/thread.c b/server/thread.c
108 index e5ef779..ef57972 100644
109 --- a/server/thread.c
110 +++ b/server/thread.c
111 @@ -32,6 +32,9 @@
112 #include <sys/types.h>
113 #include <unistd.h>
114 #include <time.h>
115 +#ifdef HAVE_SCHED_H
116 +#include <sched.h>
117 +#endif
118 #ifdef HAVE_POLL_H
119 #include <poll.h>
120 #endif
121 @@ -313,12 +316,59 @@ struct thread *get_thread_from_pid( int
122 return NULL;
123 }
124
125 +static void set_thread_priority( int unix_tid, int ntprio )
126 +{
127 +#ifdef HAVE_SCHED_H
128 + struct sched_param param;
129 + int result, scheduler;
130 +
131 + assert( unix_tid != -1 );
132 +
133 + if (ntprio == THREAD_PRIORITY_TIME_CRITICAL)
134 + {
135 + param.sched_priority = 1;
136 + scheduler = SCHED_FIFO;
137 + }
138 + else
139 + {
140 + param.sched_priority = 0;
141 + scheduler = SCHED_OTHER;
142 + }
143 +
144 + result = sched_setscheduler( unix_tid, scheduler, ¶m );
145 +
146 + if (result == 0) return;
147 +
148 + if (result == -EPERM)
149 + {
150 + static BOOL warned = FALSE;
151 +
152 + if (!warned)
153 + {
154 + fprintf( stderr, "\nwineserver: Failed to promote the priority of a time critical thread.\n" );
155 + fprintf( stderr, "wineserver: Audio may destabilise. Try making wineserver suid root.\n" );
156 + warned = TRUE;
157 + }
158 +
159 + return;
160 + }
161 +
162 + perror( "wineserver: sched_setscheduler" );
163 +#endif
164 +}
165 +
166
167 static void set_thread_info( struct thread *thread,
168 const struct set_thread_info_request *req )
169 {
170 if (req->mask & SET_THREAD_INFO_PRIORITY)
171 + {
172 + if ((thread->priority != req->priority) && (thread->unix_tid != -1))
173 + set_thread_priority( thread->unix_tid, req->priority );
174 +
175 thread->priority = req->priority;
176 + }
177 +
178 if (req->mask & SET_THREAD_INFO_AFFINITY)
179 {
180 if (req->affinity != 1) set_error( STATUS_INVALID_PARAMETER );
181 @@ -872,6 +922,10 @@ DECL_HANDLER(init_thread)
182 }
183 debug_level = max( debug_level, req->debug_level );
184
185 +
186 + if (current->priority != THREAD_PRIORITY_NORMAL)
187 + set_thread_priority( current->unix_tid, current->priority );
188 +
189 reply->pid = get_process_id( process );
190 reply->tid = get_thread_id( current );
191 reply->version = SERVER_PROTOCOL_VERSION;
192