Commit f020bc468fe4a91d32046d448511978c7b611315
Committed by
Linus Torvalds
1 parent
84d737866e
Exists in
master
and in
7 other branches
[PATCH] sys_setpgid: eliminate unnecessary do_each_task_pid(PIDTYPE_PGID)
All tasks in the process group have the same sid, we don't need to iterate them all to check that the caller of sys_setpgid() doesn't change its session. Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 1 changed file with 4 additions and 7 deletions Inline Diff
kernel/sys.c
1 | /* | 1 | /* |
2 | * linux/kernel/sys.c | 2 | * linux/kernel/sys.c |
3 | * | 3 | * |
4 | * Copyright (C) 1991, 1992 Linus Torvalds | 4 | * Copyright (C) 1991, 1992 Linus Torvalds |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/module.h> | 7 | #include <linux/module.h> |
8 | #include <linux/mm.h> | 8 | #include <linux/mm.h> |
9 | #include <linux/utsname.h> | 9 | #include <linux/utsname.h> |
10 | #include <linux/mman.h> | 10 | #include <linux/mman.h> |
11 | #include <linux/smp_lock.h> | 11 | #include <linux/smp_lock.h> |
12 | #include <linux/notifier.h> | 12 | #include <linux/notifier.h> |
13 | #include <linux/reboot.h> | 13 | #include <linux/reboot.h> |
14 | #include <linux/prctl.h> | 14 | #include <linux/prctl.h> |
15 | #include <linux/highuid.h> | 15 | #include <linux/highuid.h> |
16 | #include <linux/fs.h> | 16 | #include <linux/fs.h> |
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/kexec.h> | 18 | #include <linux/kexec.h> |
19 | #include <linux/workqueue.h> | 19 | #include <linux/workqueue.h> |
20 | #include <linux/capability.h> | 20 | #include <linux/capability.h> |
21 | #include <linux/device.h> | 21 | #include <linux/device.h> |
22 | #include <linux/key.h> | 22 | #include <linux/key.h> |
23 | #include <linux/times.h> | 23 | #include <linux/times.h> |
24 | #include <linux/posix-timers.h> | 24 | #include <linux/posix-timers.h> |
25 | #include <linux/security.h> | 25 | #include <linux/security.h> |
26 | #include <linux/dcookies.h> | 26 | #include <linux/dcookies.h> |
27 | #include <linux/suspend.h> | 27 | #include <linux/suspend.h> |
28 | #include <linux/tty.h> | 28 | #include <linux/tty.h> |
29 | #include <linux/signal.h> | 29 | #include <linux/signal.h> |
30 | #include <linux/cn_proc.h> | 30 | #include <linux/cn_proc.h> |
31 | #include <linux/getcpu.h> | 31 | #include <linux/getcpu.h> |
32 | 32 | ||
33 | #include <linux/compat.h> | 33 | #include <linux/compat.h> |
34 | #include <linux/syscalls.h> | 34 | #include <linux/syscalls.h> |
35 | #include <linux/kprobes.h> | 35 | #include <linux/kprobes.h> |
36 | 36 | ||
37 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
38 | #include <asm/io.h> | 38 | #include <asm/io.h> |
39 | #include <asm/unistd.h> | 39 | #include <asm/unistd.h> |
40 | 40 | ||
41 | #ifndef SET_UNALIGN_CTL | 41 | #ifndef SET_UNALIGN_CTL |
42 | # define SET_UNALIGN_CTL(a,b) (-EINVAL) | 42 | # define SET_UNALIGN_CTL(a,b) (-EINVAL) |
43 | #endif | 43 | #endif |
44 | #ifndef GET_UNALIGN_CTL | 44 | #ifndef GET_UNALIGN_CTL |
45 | # define GET_UNALIGN_CTL(a,b) (-EINVAL) | 45 | # define GET_UNALIGN_CTL(a,b) (-EINVAL) |
46 | #endif | 46 | #endif |
47 | #ifndef SET_FPEMU_CTL | 47 | #ifndef SET_FPEMU_CTL |
48 | # define SET_FPEMU_CTL(a,b) (-EINVAL) | 48 | # define SET_FPEMU_CTL(a,b) (-EINVAL) |
49 | #endif | 49 | #endif |
50 | #ifndef GET_FPEMU_CTL | 50 | #ifndef GET_FPEMU_CTL |
51 | # define GET_FPEMU_CTL(a,b) (-EINVAL) | 51 | # define GET_FPEMU_CTL(a,b) (-EINVAL) |
52 | #endif | 52 | #endif |
53 | #ifndef SET_FPEXC_CTL | 53 | #ifndef SET_FPEXC_CTL |
54 | # define SET_FPEXC_CTL(a,b) (-EINVAL) | 54 | # define SET_FPEXC_CTL(a,b) (-EINVAL) |
55 | #endif | 55 | #endif |
56 | #ifndef GET_FPEXC_CTL | 56 | #ifndef GET_FPEXC_CTL |
57 | # define GET_FPEXC_CTL(a,b) (-EINVAL) | 57 | # define GET_FPEXC_CTL(a,b) (-EINVAL) |
58 | #endif | 58 | #endif |
59 | #ifndef GET_ENDIAN | 59 | #ifndef GET_ENDIAN |
60 | # define GET_ENDIAN(a,b) (-EINVAL) | 60 | # define GET_ENDIAN(a,b) (-EINVAL) |
61 | #endif | 61 | #endif |
62 | #ifndef SET_ENDIAN | 62 | #ifndef SET_ENDIAN |
63 | # define SET_ENDIAN(a,b) (-EINVAL) | 63 | # define SET_ENDIAN(a,b) (-EINVAL) |
64 | #endif | 64 | #endif |
65 | 65 | ||
66 | /* | 66 | /* |
67 | * this is where the system-wide overflow UID and GID are defined, for | 67 | * this is where the system-wide overflow UID and GID are defined, for |
68 | * architectures that now have 32-bit UID/GID but didn't in the past | 68 | * architectures that now have 32-bit UID/GID but didn't in the past |
69 | */ | 69 | */ |
70 | 70 | ||
71 | int overflowuid = DEFAULT_OVERFLOWUID; | 71 | int overflowuid = DEFAULT_OVERFLOWUID; |
72 | int overflowgid = DEFAULT_OVERFLOWGID; | 72 | int overflowgid = DEFAULT_OVERFLOWGID; |
73 | 73 | ||
74 | #ifdef CONFIG_UID16 | 74 | #ifdef CONFIG_UID16 |
75 | EXPORT_SYMBOL(overflowuid); | 75 | EXPORT_SYMBOL(overflowuid); |
76 | EXPORT_SYMBOL(overflowgid); | 76 | EXPORT_SYMBOL(overflowgid); |
77 | #endif | 77 | #endif |
78 | 78 | ||
79 | /* | 79 | /* |
80 | * the same as above, but for filesystems which can only store a 16-bit | 80 | * the same as above, but for filesystems which can only store a 16-bit |
81 | * UID and GID. as such, this is needed on all architectures | 81 | * UID and GID. as such, this is needed on all architectures |
82 | */ | 82 | */ |
83 | 83 | ||
84 | int fs_overflowuid = DEFAULT_FS_OVERFLOWUID; | 84 | int fs_overflowuid = DEFAULT_FS_OVERFLOWUID; |
85 | int fs_overflowgid = DEFAULT_FS_OVERFLOWUID; | 85 | int fs_overflowgid = DEFAULT_FS_OVERFLOWUID; |
86 | 86 | ||
87 | EXPORT_SYMBOL(fs_overflowuid); | 87 | EXPORT_SYMBOL(fs_overflowuid); |
88 | EXPORT_SYMBOL(fs_overflowgid); | 88 | EXPORT_SYMBOL(fs_overflowgid); |
89 | 89 | ||
90 | /* | 90 | /* |
91 | * this indicates whether you can reboot with ctrl-alt-del: the default is yes | 91 | * this indicates whether you can reboot with ctrl-alt-del: the default is yes |
92 | */ | 92 | */ |
93 | 93 | ||
94 | int C_A_D = 1; | 94 | int C_A_D = 1; |
95 | struct pid *cad_pid; | 95 | struct pid *cad_pid; |
96 | EXPORT_SYMBOL(cad_pid); | 96 | EXPORT_SYMBOL(cad_pid); |
97 | 97 | ||
98 | /* | 98 | /* |
99 | * Notifier list for kernel code which wants to be called | 99 | * Notifier list for kernel code which wants to be called |
100 | * at shutdown. This is used to stop any idling DMA operations | 100 | * at shutdown. This is used to stop any idling DMA operations |
101 | * and the like. | 101 | * and the like. |
102 | */ | 102 | */ |
103 | 103 | ||
104 | static BLOCKING_NOTIFIER_HEAD(reboot_notifier_list); | 104 | static BLOCKING_NOTIFIER_HEAD(reboot_notifier_list); |
105 | 105 | ||
106 | /* | 106 | /* |
107 | * Notifier chain core routines. The exported routines below | 107 | * Notifier chain core routines. The exported routines below |
108 | * are layered on top of these, with appropriate locking added. | 108 | * are layered on top of these, with appropriate locking added. |
109 | */ | 109 | */ |
110 | 110 | ||
111 | static int notifier_chain_register(struct notifier_block **nl, | 111 | static int notifier_chain_register(struct notifier_block **nl, |
112 | struct notifier_block *n) | 112 | struct notifier_block *n) |
113 | { | 113 | { |
114 | while ((*nl) != NULL) { | 114 | while ((*nl) != NULL) { |
115 | if (n->priority > (*nl)->priority) | 115 | if (n->priority > (*nl)->priority) |
116 | break; | 116 | break; |
117 | nl = &((*nl)->next); | 117 | nl = &((*nl)->next); |
118 | } | 118 | } |
119 | n->next = *nl; | 119 | n->next = *nl; |
120 | rcu_assign_pointer(*nl, n); | 120 | rcu_assign_pointer(*nl, n); |
121 | return 0; | 121 | return 0; |
122 | } | 122 | } |
123 | 123 | ||
124 | static int notifier_chain_unregister(struct notifier_block **nl, | 124 | static int notifier_chain_unregister(struct notifier_block **nl, |
125 | struct notifier_block *n) | 125 | struct notifier_block *n) |
126 | { | 126 | { |
127 | while ((*nl) != NULL) { | 127 | while ((*nl) != NULL) { |
128 | if ((*nl) == n) { | 128 | if ((*nl) == n) { |
129 | rcu_assign_pointer(*nl, n->next); | 129 | rcu_assign_pointer(*nl, n->next); |
130 | return 0; | 130 | return 0; |
131 | } | 131 | } |
132 | nl = &((*nl)->next); | 132 | nl = &((*nl)->next); |
133 | } | 133 | } |
134 | return -ENOENT; | 134 | return -ENOENT; |
135 | } | 135 | } |
136 | 136 | ||
137 | static int __kprobes notifier_call_chain(struct notifier_block **nl, | 137 | static int __kprobes notifier_call_chain(struct notifier_block **nl, |
138 | unsigned long val, void *v) | 138 | unsigned long val, void *v) |
139 | { | 139 | { |
140 | int ret = NOTIFY_DONE; | 140 | int ret = NOTIFY_DONE; |
141 | struct notifier_block *nb, *next_nb; | 141 | struct notifier_block *nb, *next_nb; |
142 | 142 | ||
143 | nb = rcu_dereference(*nl); | 143 | nb = rcu_dereference(*nl); |
144 | while (nb) { | 144 | while (nb) { |
145 | next_nb = rcu_dereference(nb->next); | 145 | next_nb = rcu_dereference(nb->next); |
146 | ret = nb->notifier_call(nb, val, v); | 146 | ret = nb->notifier_call(nb, val, v); |
147 | if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK) | 147 | if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK) |
148 | break; | 148 | break; |
149 | nb = next_nb; | 149 | nb = next_nb; |
150 | } | 150 | } |
151 | return ret; | 151 | return ret; |
152 | } | 152 | } |
153 | 153 | ||
154 | /* | 154 | /* |
155 | * Atomic notifier chain routines. Registration and unregistration | 155 | * Atomic notifier chain routines. Registration and unregistration |
156 | * use a spinlock, and call_chain is synchronized by RCU (no locks). | 156 | * use a spinlock, and call_chain is synchronized by RCU (no locks). |
157 | */ | 157 | */ |
158 | 158 | ||
159 | /** | 159 | /** |
160 | * atomic_notifier_chain_register - Add notifier to an atomic notifier chain | 160 | * atomic_notifier_chain_register - Add notifier to an atomic notifier chain |
161 | * @nh: Pointer to head of the atomic notifier chain | 161 | * @nh: Pointer to head of the atomic notifier chain |
162 | * @n: New entry in notifier chain | 162 | * @n: New entry in notifier chain |
163 | * | 163 | * |
164 | * Adds a notifier to an atomic notifier chain. | 164 | * Adds a notifier to an atomic notifier chain. |
165 | * | 165 | * |
166 | * Currently always returns zero. | 166 | * Currently always returns zero. |
167 | */ | 167 | */ |
168 | 168 | ||
169 | int atomic_notifier_chain_register(struct atomic_notifier_head *nh, | 169 | int atomic_notifier_chain_register(struct atomic_notifier_head *nh, |
170 | struct notifier_block *n) | 170 | struct notifier_block *n) |
171 | { | 171 | { |
172 | unsigned long flags; | 172 | unsigned long flags; |
173 | int ret; | 173 | int ret; |
174 | 174 | ||
175 | spin_lock_irqsave(&nh->lock, flags); | 175 | spin_lock_irqsave(&nh->lock, flags); |
176 | ret = notifier_chain_register(&nh->head, n); | 176 | ret = notifier_chain_register(&nh->head, n); |
177 | spin_unlock_irqrestore(&nh->lock, flags); | 177 | spin_unlock_irqrestore(&nh->lock, flags); |
178 | return ret; | 178 | return ret; |
179 | } | 179 | } |
180 | 180 | ||
181 | EXPORT_SYMBOL_GPL(atomic_notifier_chain_register); | 181 | EXPORT_SYMBOL_GPL(atomic_notifier_chain_register); |
182 | 182 | ||
183 | /** | 183 | /** |
184 | * atomic_notifier_chain_unregister - Remove notifier from an atomic notifier chain | 184 | * atomic_notifier_chain_unregister - Remove notifier from an atomic notifier chain |
185 | * @nh: Pointer to head of the atomic notifier chain | 185 | * @nh: Pointer to head of the atomic notifier chain |
186 | * @n: Entry to remove from notifier chain | 186 | * @n: Entry to remove from notifier chain |
187 | * | 187 | * |
188 | * Removes a notifier from an atomic notifier chain. | 188 | * Removes a notifier from an atomic notifier chain. |
189 | * | 189 | * |
190 | * Returns zero on success or %-ENOENT on failure. | 190 | * Returns zero on success or %-ENOENT on failure. |
191 | */ | 191 | */ |
192 | int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh, | 192 | int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh, |
193 | struct notifier_block *n) | 193 | struct notifier_block *n) |
194 | { | 194 | { |
195 | unsigned long flags; | 195 | unsigned long flags; |
196 | int ret; | 196 | int ret; |
197 | 197 | ||
198 | spin_lock_irqsave(&nh->lock, flags); | 198 | spin_lock_irqsave(&nh->lock, flags); |
199 | ret = notifier_chain_unregister(&nh->head, n); | 199 | ret = notifier_chain_unregister(&nh->head, n); |
200 | spin_unlock_irqrestore(&nh->lock, flags); | 200 | spin_unlock_irqrestore(&nh->lock, flags); |
201 | synchronize_rcu(); | 201 | synchronize_rcu(); |
202 | return ret; | 202 | return ret; |
203 | } | 203 | } |
204 | 204 | ||
205 | EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister); | 205 | EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister); |
206 | 206 | ||
207 | /** | 207 | /** |
208 | * atomic_notifier_call_chain - Call functions in an atomic notifier chain | 208 | * atomic_notifier_call_chain - Call functions in an atomic notifier chain |
209 | * @nh: Pointer to head of the atomic notifier chain | 209 | * @nh: Pointer to head of the atomic notifier chain |
210 | * @val: Value passed unmodified to notifier function | 210 | * @val: Value passed unmodified to notifier function |
211 | * @v: Pointer passed unmodified to notifier function | 211 | * @v: Pointer passed unmodified to notifier function |
212 | * | 212 | * |
213 | * Calls each function in a notifier chain in turn. The functions | 213 | * Calls each function in a notifier chain in turn. The functions |
214 | * run in an atomic context, so they must not block. | 214 | * run in an atomic context, so they must not block. |
215 | * This routine uses RCU to synchronize with changes to the chain. | 215 | * This routine uses RCU to synchronize with changes to the chain. |
216 | * | 216 | * |
217 | * If the return value of the notifier can be and'ed | 217 | * If the return value of the notifier can be and'ed |
218 | * with %NOTIFY_STOP_MASK then atomic_notifier_call_chain | 218 | * with %NOTIFY_STOP_MASK then atomic_notifier_call_chain |
219 | * will return immediately, with the return value of | 219 | * will return immediately, with the return value of |
220 | * the notifier function which halted execution. | 220 | * the notifier function which halted execution. |
221 | * Otherwise the return value is the return value | 221 | * Otherwise the return value is the return value |
222 | * of the last notifier function called. | 222 | * of the last notifier function called. |
223 | */ | 223 | */ |
224 | 224 | ||
225 | int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh, | 225 | int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh, |
226 | unsigned long val, void *v) | 226 | unsigned long val, void *v) |
227 | { | 227 | { |
228 | int ret; | 228 | int ret; |
229 | 229 | ||
230 | rcu_read_lock(); | 230 | rcu_read_lock(); |
231 | ret = notifier_call_chain(&nh->head, val, v); | 231 | ret = notifier_call_chain(&nh->head, val, v); |
232 | rcu_read_unlock(); | 232 | rcu_read_unlock(); |
233 | return ret; | 233 | return ret; |
234 | } | 234 | } |
235 | 235 | ||
236 | EXPORT_SYMBOL_GPL(atomic_notifier_call_chain); | 236 | EXPORT_SYMBOL_GPL(atomic_notifier_call_chain); |
237 | 237 | ||
238 | /* | 238 | /* |
239 | * Blocking notifier chain routines. All access to the chain is | 239 | * Blocking notifier chain routines. All access to the chain is |
240 | * synchronized by an rwsem. | 240 | * synchronized by an rwsem. |
241 | */ | 241 | */ |
242 | 242 | ||
243 | /** | 243 | /** |
244 | * blocking_notifier_chain_register - Add notifier to a blocking notifier chain | 244 | * blocking_notifier_chain_register - Add notifier to a blocking notifier chain |
245 | * @nh: Pointer to head of the blocking notifier chain | 245 | * @nh: Pointer to head of the blocking notifier chain |
246 | * @n: New entry in notifier chain | 246 | * @n: New entry in notifier chain |
247 | * | 247 | * |
248 | * Adds a notifier to a blocking notifier chain. | 248 | * Adds a notifier to a blocking notifier chain. |
249 | * Must be called in process context. | 249 | * Must be called in process context. |
250 | * | 250 | * |
251 | * Currently always returns zero. | 251 | * Currently always returns zero. |
252 | */ | 252 | */ |
253 | 253 | ||
254 | int blocking_notifier_chain_register(struct blocking_notifier_head *nh, | 254 | int blocking_notifier_chain_register(struct blocking_notifier_head *nh, |
255 | struct notifier_block *n) | 255 | struct notifier_block *n) |
256 | { | 256 | { |
257 | int ret; | 257 | int ret; |
258 | 258 | ||
259 | /* | 259 | /* |
260 | * This code gets used during boot-up, when task switching is | 260 | * This code gets used during boot-up, when task switching is |
261 | * not yet working and interrupts must remain disabled. At | 261 | * not yet working and interrupts must remain disabled. At |
262 | * such times we must not call down_write(). | 262 | * such times we must not call down_write(). |
263 | */ | 263 | */ |
264 | if (unlikely(system_state == SYSTEM_BOOTING)) | 264 | if (unlikely(system_state == SYSTEM_BOOTING)) |
265 | return notifier_chain_register(&nh->head, n); | 265 | return notifier_chain_register(&nh->head, n); |
266 | 266 | ||
267 | down_write(&nh->rwsem); | 267 | down_write(&nh->rwsem); |
268 | ret = notifier_chain_register(&nh->head, n); | 268 | ret = notifier_chain_register(&nh->head, n); |
269 | up_write(&nh->rwsem); | 269 | up_write(&nh->rwsem); |
270 | return ret; | 270 | return ret; |
271 | } | 271 | } |
272 | 272 | ||
273 | EXPORT_SYMBOL_GPL(blocking_notifier_chain_register); | 273 | EXPORT_SYMBOL_GPL(blocking_notifier_chain_register); |
274 | 274 | ||
275 | /** | 275 | /** |
276 | * blocking_notifier_chain_unregister - Remove notifier from a blocking notifier chain | 276 | * blocking_notifier_chain_unregister - Remove notifier from a blocking notifier chain |
277 | * @nh: Pointer to head of the blocking notifier chain | 277 | * @nh: Pointer to head of the blocking notifier chain |
278 | * @n: Entry to remove from notifier chain | 278 | * @n: Entry to remove from notifier chain |
279 | * | 279 | * |
280 | * Removes a notifier from a blocking notifier chain. | 280 | * Removes a notifier from a blocking notifier chain. |
281 | * Must be called from process context. | 281 | * Must be called from process context. |
282 | * | 282 | * |
283 | * Returns zero on success or %-ENOENT on failure. | 283 | * Returns zero on success or %-ENOENT on failure. |
284 | */ | 284 | */ |
285 | int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh, | 285 | int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh, |
286 | struct notifier_block *n) | 286 | struct notifier_block *n) |
287 | { | 287 | { |
288 | int ret; | 288 | int ret; |
289 | 289 | ||
290 | /* | 290 | /* |
291 | * This code gets used during boot-up, when task switching is | 291 | * This code gets used during boot-up, when task switching is |
292 | * not yet working and interrupts must remain disabled. At | 292 | * not yet working and interrupts must remain disabled. At |
293 | * such times we must not call down_write(). | 293 | * such times we must not call down_write(). |
294 | */ | 294 | */ |
295 | if (unlikely(system_state == SYSTEM_BOOTING)) | 295 | if (unlikely(system_state == SYSTEM_BOOTING)) |
296 | return notifier_chain_unregister(&nh->head, n); | 296 | return notifier_chain_unregister(&nh->head, n); |
297 | 297 | ||
298 | down_write(&nh->rwsem); | 298 | down_write(&nh->rwsem); |
299 | ret = notifier_chain_unregister(&nh->head, n); | 299 | ret = notifier_chain_unregister(&nh->head, n); |
300 | up_write(&nh->rwsem); | 300 | up_write(&nh->rwsem); |
301 | return ret; | 301 | return ret; |
302 | } | 302 | } |
303 | 303 | ||
304 | EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister); | 304 | EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister); |
305 | 305 | ||
306 | /** | 306 | /** |
307 | * blocking_notifier_call_chain - Call functions in a blocking notifier chain | 307 | * blocking_notifier_call_chain - Call functions in a blocking notifier chain |
308 | * @nh: Pointer to head of the blocking notifier chain | 308 | * @nh: Pointer to head of the blocking notifier chain |
309 | * @val: Value passed unmodified to notifier function | 309 | * @val: Value passed unmodified to notifier function |
310 | * @v: Pointer passed unmodified to notifier function | 310 | * @v: Pointer passed unmodified to notifier function |
311 | * | 311 | * |
312 | * Calls each function in a notifier chain in turn. The functions | 312 | * Calls each function in a notifier chain in turn. The functions |
313 | * run in a process context, so they are allowed to block. | 313 | * run in a process context, so they are allowed to block. |
314 | * | 314 | * |
315 | * If the return value of the notifier can be and'ed | 315 | * If the return value of the notifier can be and'ed |
316 | * with %NOTIFY_STOP_MASK then blocking_notifier_call_chain | 316 | * with %NOTIFY_STOP_MASK then blocking_notifier_call_chain |
317 | * will return immediately, with the return value of | 317 | * will return immediately, with the return value of |
318 | * the notifier function which halted execution. | 318 | * the notifier function which halted execution. |
319 | * Otherwise the return value is the return value | 319 | * Otherwise the return value is the return value |
320 | * of the last notifier function called. | 320 | * of the last notifier function called. |
321 | */ | 321 | */ |
322 | 322 | ||
323 | int blocking_notifier_call_chain(struct blocking_notifier_head *nh, | 323 | int blocking_notifier_call_chain(struct blocking_notifier_head *nh, |
324 | unsigned long val, void *v) | 324 | unsigned long val, void *v) |
325 | { | 325 | { |
326 | int ret; | 326 | int ret; |
327 | 327 | ||
328 | down_read(&nh->rwsem); | 328 | down_read(&nh->rwsem); |
329 | ret = notifier_call_chain(&nh->head, val, v); | 329 | ret = notifier_call_chain(&nh->head, val, v); |
330 | up_read(&nh->rwsem); | 330 | up_read(&nh->rwsem); |
331 | return ret; | 331 | return ret; |
332 | } | 332 | } |
333 | 333 | ||
334 | EXPORT_SYMBOL_GPL(blocking_notifier_call_chain); | 334 | EXPORT_SYMBOL_GPL(blocking_notifier_call_chain); |
335 | 335 | ||
336 | /* | 336 | /* |
337 | * Raw notifier chain routines. There is no protection; | 337 | * Raw notifier chain routines. There is no protection; |
338 | * the caller must provide it. Use at your own risk! | 338 | * the caller must provide it. Use at your own risk! |
339 | */ | 339 | */ |
340 | 340 | ||
341 | /** | 341 | /** |
342 | * raw_notifier_chain_register - Add notifier to a raw notifier chain | 342 | * raw_notifier_chain_register - Add notifier to a raw notifier chain |
343 | * @nh: Pointer to head of the raw notifier chain | 343 | * @nh: Pointer to head of the raw notifier chain |
344 | * @n: New entry in notifier chain | 344 | * @n: New entry in notifier chain |
345 | * | 345 | * |
346 | * Adds a notifier to a raw notifier chain. | 346 | * Adds a notifier to a raw notifier chain. |
347 | * All locking must be provided by the caller. | 347 | * All locking must be provided by the caller. |
348 | * | 348 | * |
349 | * Currently always returns zero. | 349 | * Currently always returns zero. |
350 | */ | 350 | */ |
351 | 351 | ||
352 | int raw_notifier_chain_register(struct raw_notifier_head *nh, | 352 | int raw_notifier_chain_register(struct raw_notifier_head *nh, |
353 | struct notifier_block *n) | 353 | struct notifier_block *n) |
354 | { | 354 | { |
355 | return notifier_chain_register(&nh->head, n); | 355 | return notifier_chain_register(&nh->head, n); |
356 | } | 356 | } |
357 | 357 | ||
358 | EXPORT_SYMBOL_GPL(raw_notifier_chain_register); | 358 | EXPORT_SYMBOL_GPL(raw_notifier_chain_register); |
359 | 359 | ||
360 | /** | 360 | /** |
361 | * raw_notifier_chain_unregister - Remove notifier from a raw notifier chain | 361 | * raw_notifier_chain_unregister - Remove notifier from a raw notifier chain |
362 | * @nh: Pointer to head of the raw notifier chain | 362 | * @nh: Pointer to head of the raw notifier chain |
363 | * @n: Entry to remove from notifier chain | 363 | * @n: Entry to remove from notifier chain |
364 | * | 364 | * |
365 | * Removes a notifier from a raw notifier chain. | 365 | * Removes a notifier from a raw notifier chain. |
366 | * All locking must be provided by the caller. | 366 | * All locking must be provided by the caller. |
367 | * | 367 | * |
368 | * Returns zero on success or %-ENOENT on failure. | 368 | * Returns zero on success or %-ENOENT on failure. |
369 | */ | 369 | */ |
370 | int raw_notifier_chain_unregister(struct raw_notifier_head *nh, | 370 | int raw_notifier_chain_unregister(struct raw_notifier_head *nh, |
371 | struct notifier_block *n) | 371 | struct notifier_block *n) |
372 | { | 372 | { |
373 | return notifier_chain_unregister(&nh->head, n); | 373 | return notifier_chain_unregister(&nh->head, n); |
374 | } | 374 | } |
375 | 375 | ||
376 | EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister); | 376 | EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister); |
377 | 377 | ||
378 | /** | 378 | /** |
379 | * raw_notifier_call_chain - Call functions in a raw notifier chain | 379 | * raw_notifier_call_chain - Call functions in a raw notifier chain |
380 | * @nh: Pointer to head of the raw notifier chain | 380 | * @nh: Pointer to head of the raw notifier chain |
381 | * @val: Value passed unmodified to notifier function | 381 | * @val: Value passed unmodified to notifier function |
382 | * @v: Pointer passed unmodified to notifier function | 382 | * @v: Pointer passed unmodified to notifier function |
383 | * | 383 | * |
384 | * Calls each function in a notifier chain in turn. The functions | 384 | * Calls each function in a notifier chain in turn. The functions |
385 | * run in an undefined context. | 385 | * run in an undefined context. |
386 | * All locking must be provided by the caller. | 386 | * All locking must be provided by the caller. |
387 | * | 387 | * |
388 | * If the return value of the notifier can be and'ed | 388 | * If the return value of the notifier can be and'ed |
389 | * with %NOTIFY_STOP_MASK then raw_notifier_call_chain | 389 | * with %NOTIFY_STOP_MASK then raw_notifier_call_chain |
390 | * will return immediately, with the return value of | 390 | * will return immediately, with the return value of |
391 | * the notifier function which halted execution. | 391 | * the notifier function which halted execution. |
392 | * Otherwise the return value is the return value | 392 | * Otherwise the return value is the return value |
393 | * of the last notifier function called. | 393 | * of the last notifier function called. |
394 | */ | 394 | */ |
395 | 395 | ||
396 | int raw_notifier_call_chain(struct raw_notifier_head *nh, | 396 | int raw_notifier_call_chain(struct raw_notifier_head *nh, |
397 | unsigned long val, void *v) | 397 | unsigned long val, void *v) |
398 | { | 398 | { |
399 | return notifier_call_chain(&nh->head, val, v); | 399 | return notifier_call_chain(&nh->head, val, v); |
400 | } | 400 | } |
401 | 401 | ||
402 | EXPORT_SYMBOL_GPL(raw_notifier_call_chain); | 402 | EXPORT_SYMBOL_GPL(raw_notifier_call_chain); |
403 | 403 | ||
404 | /* | 404 | /* |
405 | * SRCU notifier chain routines. Registration and unregistration | 405 | * SRCU notifier chain routines. Registration and unregistration |
406 | * use a mutex, and call_chain is synchronized by SRCU (no locks). | 406 | * use a mutex, and call_chain is synchronized by SRCU (no locks). |
407 | */ | 407 | */ |
408 | 408 | ||
409 | /** | 409 | /** |
410 | * srcu_notifier_chain_register - Add notifier to an SRCU notifier chain | 410 | * srcu_notifier_chain_register - Add notifier to an SRCU notifier chain |
411 | * @nh: Pointer to head of the SRCU notifier chain | 411 | * @nh: Pointer to head of the SRCU notifier chain |
412 | * @n: New entry in notifier chain | 412 | * @n: New entry in notifier chain |
413 | * | 413 | * |
414 | * Adds a notifier to an SRCU notifier chain. | 414 | * Adds a notifier to an SRCU notifier chain. |
415 | * Must be called in process context. | 415 | * Must be called in process context. |
416 | * | 416 | * |
417 | * Currently always returns zero. | 417 | * Currently always returns zero. |
418 | */ | 418 | */ |
419 | 419 | ||
420 | int srcu_notifier_chain_register(struct srcu_notifier_head *nh, | 420 | int srcu_notifier_chain_register(struct srcu_notifier_head *nh, |
421 | struct notifier_block *n) | 421 | struct notifier_block *n) |
422 | { | 422 | { |
423 | int ret; | 423 | int ret; |
424 | 424 | ||
425 | /* | 425 | /* |
426 | * This code gets used during boot-up, when task switching is | 426 | * This code gets used during boot-up, when task switching is |
427 | * not yet working and interrupts must remain disabled. At | 427 | * not yet working and interrupts must remain disabled. At |
428 | * such times we must not call mutex_lock(). | 428 | * such times we must not call mutex_lock(). |
429 | */ | 429 | */ |
430 | if (unlikely(system_state == SYSTEM_BOOTING)) | 430 | if (unlikely(system_state == SYSTEM_BOOTING)) |
431 | return notifier_chain_register(&nh->head, n); | 431 | return notifier_chain_register(&nh->head, n); |
432 | 432 | ||
433 | mutex_lock(&nh->mutex); | 433 | mutex_lock(&nh->mutex); |
434 | ret = notifier_chain_register(&nh->head, n); | 434 | ret = notifier_chain_register(&nh->head, n); |
435 | mutex_unlock(&nh->mutex); | 435 | mutex_unlock(&nh->mutex); |
436 | return ret; | 436 | return ret; |
437 | } | 437 | } |
438 | 438 | ||
439 | EXPORT_SYMBOL_GPL(srcu_notifier_chain_register); | 439 | EXPORT_SYMBOL_GPL(srcu_notifier_chain_register); |
440 | 440 | ||
441 | /** | 441 | /** |
442 | * srcu_notifier_chain_unregister - Remove notifier from an SRCU notifier chain | 442 | * srcu_notifier_chain_unregister - Remove notifier from an SRCU notifier chain |
443 | * @nh: Pointer to head of the SRCU notifier chain | 443 | * @nh: Pointer to head of the SRCU notifier chain |
444 | * @n: Entry to remove from notifier chain | 444 | * @n: Entry to remove from notifier chain |
445 | * | 445 | * |
446 | * Removes a notifier from an SRCU notifier chain. | 446 | * Removes a notifier from an SRCU notifier chain. |
447 | * Must be called from process context. | 447 | * Must be called from process context. |
448 | * | 448 | * |
449 | * Returns zero on success or %-ENOENT on failure. | 449 | * Returns zero on success or %-ENOENT on failure. |
450 | */ | 450 | */ |
451 | int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh, | 451 | int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh, |
452 | struct notifier_block *n) | 452 | struct notifier_block *n) |
453 | { | 453 | { |
454 | int ret; | 454 | int ret; |
455 | 455 | ||
456 | /* | 456 | /* |
457 | * This code gets used during boot-up, when task switching is | 457 | * This code gets used during boot-up, when task switching is |
458 | * not yet working and interrupts must remain disabled. At | 458 | * not yet working and interrupts must remain disabled. At |
459 | * such times we must not call mutex_lock(). | 459 | * such times we must not call mutex_lock(). |
460 | */ | 460 | */ |
461 | if (unlikely(system_state == SYSTEM_BOOTING)) | 461 | if (unlikely(system_state == SYSTEM_BOOTING)) |
462 | return notifier_chain_unregister(&nh->head, n); | 462 | return notifier_chain_unregister(&nh->head, n); |
463 | 463 | ||
464 | mutex_lock(&nh->mutex); | 464 | mutex_lock(&nh->mutex); |
465 | ret = notifier_chain_unregister(&nh->head, n); | 465 | ret = notifier_chain_unregister(&nh->head, n); |
466 | mutex_unlock(&nh->mutex); | 466 | mutex_unlock(&nh->mutex); |
467 | synchronize_srcu(&nh->srcu); | 467 | synchronize_srcu(&nh->srcu); |
468 | return ret; | 468 | return ret; |
469 | } | 469 | } |
470 | 470 | ||
471 | EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister); | 471 | EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister); |
472 | 472 | ||
473 | /** | 473 | /** |
474 | * srcu_notifier_call_chain - Call functions in an SRCU notifier chain | 474 | * srcu_notifier_call_chain - Call functions in an SRCU notifier chain |
475 | * @nh: Pointer to head of the SRCU notifier chain | 475 | * @nh: Pointer to head of the SRCU notifier chain |
476 | * @val: Value passed unmodified to notifier function | 476 | * @val: Value passed unmodified to notifier function |
477 | * @v: Pointer passed unmodified to notifier function | 477 | * @v: Pointer passed unmodified to notifier function |
478 | * | 478 | * |
479 | * Calls each function in a notifier chain in turn. The functions | 479 | * Calls each function in a notifier chain in turn. The functions |
480 | * run in a process context, so they are allowed to block. | 480 | * run in a process context, so they are allowed to block. |
481 | * | 481 | * |
482 | * If the return value of the notifier can be and'ed | 482 | * If the return value of the notifier can be and'ed |
483 | * with %NOTIFY_STOP_MASK then srcu_notifier_call_chain | 483 | * with %NOTIFY_STOP_MASK then srcu_notifier_call_chain |
484 | * will return immediately, with the return value of | 484 | * will return immediately, with the return value of |
485 | * the notifier function which halted execution. | 485 | * the notifier function which halted execution. |
486 | * Otherwise the return value is the return value | 486 | * Otherwise the return value is the return value |
487 | * of the last notifier function called. | 487 | * of the last notifier function called. |
488 | */ | 488 | */ |
489 | 489 | ||
490 | int srcu_notifier_call_chain(struct srcu_notifier_head *nh, | 490 | int srcu_notifier_call_chain(struct srcu_notifier_head *nh, |
491 | unsigned long val, void *v) | 491 | unsigned long val, void *v) |
492 | { | 492 | { |
493 | int ret; | 493 | int ret; |
494 | int idx; | 494 | int idx; |
495 | 495 | ||
496 | idx = srcu_read_lock(&nh->srcu); | 496 | idx = srcu_read_lock(&nh->srcu); |
497 | ret = notifier_call_chain(&nh->head, val, v); | 497 | ret = notifier_call_chain(&nh->head, val, v); |
498 | srcu_read_unlock(&nh->srcu, idx); | 498 | srcu_read_unlock(&nh->srcu, idx); |
499 | return ret; | 499 | return ret; |
500 | } | 500 | } |
501 | 501 | ||
502 | EXPORT_SYMBOL_GPL(srcu_notifier_call_chain); | 502 | EXPORT_SYMBOL_GPL(srcu_notifier_call_chain); |
503 | 503 | ||
504 | /** | 504 | /** |
505 | * srcu_init_notifier_head - Initialize an SRCU notifier head | 505 | * srcu_init_notifier_head - Initialize an SRCU notifier head |
506 | * @nh: Pointer to head of the srcu notifier chain | 506 | * @nh: Pointer to head of the srcu notifier chain |
507 | * | 507 | * |
508 | * Unlike other sorts of notifier heads, SRCU notifier heads require | 508 | * Unlike other sorts of notifier heads, SRCU notifier heads require |
509 | * dynamic initialization. Be sure to call this routine before | 509 | * dynamic initialization. Be sure to call this routine before |
510 | * calling any of the other SRCU notifier routines for this head. | 510 | * calling any of the other SRCU notifier routines for this head. |
511 | * | 511 | * |
512 | * If an SRCU notifier head is deallocated, it must first be cleaned | 512 | * If an SRCU notifier head is deallocated, it must first be cleaned |
513 | * up by calling srcu_cleanup_notifier_head(). Otherwise the head's | 513 | * up by calling srcu_cleanup_notifier_head(). Otherwise the head's |
514 | * per-cpu data (used by the SRCU mechanism) will leak. | 514 | * per-cpu data (used by the SRCU mechanism) will leak. |
515 | */ | 515 | */ |
516 | 516 | ||
517 | void srcu_init_notifier_head(struct srcu_notifier_head *nh) | 517 | void srcu_init_notifier_head(struct srcu_notifier_head *nh) |
518 | { | 518 | { |
519 | mutex_init(&nh->mutex); | 519 | mutex_init(&nh->mutex); |
520 | if (init_srcu_struct(&nh->srcu) < 0) | 520 | if (init_srcu_struct(&nh->srcu) < 0) |
521 | BUG(); | 521 | BUG(); |
522 | nh->head = NULL; | 522 | nh->head = NULL; |
523 | } | 523 | } |
524 | 524 | ||
525 | EXPORT_SYMBOL_GPL(srcu_init_notifier_head); | 525 | EXPORT_SYMBOL_GPL(srcu_init_notifier_head); |
526 | 526 | ||
527 | /** | 527 | /** |
528 | * register_reboot_notifier - Register function to be called at reboot time | 528 | * register_reboot_notifier - Register function to be called at reboot time |
529 | * @nb: Info about notifier function to be called | 529 | * @nb: Info about notifier function to be called |
530 | * | 530 | * |
531 | * Registers a function with the list of functions | 531 | * Registers a function with the list of functions |
532 | * to be called at reboot time. | 532 | * to be called at reboot time. |
533 | * | 533 | * |
534 | * Currently always returns zero, as blocking_notifier_chain_register | 534 | * Currently always returns zero, as blocking_notifier_chain_register |
535 | * always returns zero. | 535 | * always returns zero. |
536 | */ | 536 | */ |
537 | 537 | ||
538 | int register_reboot_notifier(struct notifier_block * nb) | 538 | int register_reboot_notifier(struct notifier_block * nb) |
539 | { | 539 | { |
540 | return blocking_notifier_chain_register(&reboot_notifier_list, nb); | 540 | return blocking_notifier_chain_register(&reboot_notifier_list, nb); |
541 | } | 541 | } |
542 | 542 | ||
543 | EXPORT_SYMBOL(register_reboot_notifier); | 543 | EXPORT_SYMBOL(register_reboot_notifier); |
544 | 544 | ||
545 | /** | 545 | /** |
546 | * unregister_reboot_notifier - Unregister previously registered reboot notifier | 546 | * unregister_reboot_notifier - Unregister previously registered reboot notifier |
547 | * @nb: Hook to be unregistered | 547 | * @nb: Hook to be unregistered |
548 | * | 548 | * |
549 | * Unregisters a previously registered reboot | 549 | * Unregisters a previously registered reboot |
550 | * notifier function. | 550 | * notifier function. |
551 | * | 551 | * |
552 | * Returns zero on success, or %-ENOENT on failure. | 552 | * Returns zero on success, or %-ENOENT on failure. |
553 | */ | 553 | */ |
554 | 554 | ||
555 | int unregister_reboot_notifier(struct notifier_block * nb) | 555 | int unregister_reboot_notifier(struct notifier_block * nb) |
556 | { | 556 | { |
557 | return blocking_notifier_chain_unregister(&reboot_notifier_list, nb); | 557 | return blocking_notifier_chain_unregister(&reboot_notifier_list, nb); |
558 | } | 558 | } |
559 | 559 | ||
560 | EXPORT_SYMBOL(unregister_reboot_notifier); | 560 | EXPORT_SYMBOL(unregister_reboot_notifier); |
561 | 561 | ||
562 | static int set_one_prio(struct task_struct *p, int niceval, int error) | 562 | static int set_one_prio(struct task_struct *p, int niceval, int error) |
563 | { | 563 | { |
564 | int no_nice; | 564 | int no_nice; |
565 | 565 | ||
566 | if (p->uid != current->euid && | 566 | if (p->uid != current->euid && |
567 | p->euid != current->euid && !capable(CAP_SYS_NICE)) { | 567 | p->euid != current->euid && !capable(CAP_SYS_NICE)) { |
568 | error = -EPERM; | 568 | error = -EPERM; |
569 | goto out; | 569 | goto out; |
570 | } | 570 | } |
571 | if (niceval < task_nice(p) && !can_nice(p, niceval)) { | 571 | if (niceval < task_nice(p) && !can_nice(p, niceval)) { |
572 | error = -EACCES; | 572 | error = -EACCES; |
573 | goto out; | 573 | goto out; |
574 | } | 574 | } |
575 | no_nice = security_task_setnice(p, niceval); | 575 | no_nice = security_task_setnice(p, niceval); |
576 | if (no_nice) { | 576 | if (no_nice) { |
577 | error = no_nice; | 577 | error = no_nice; |
578 | goto out; | 578 | goto out; |
579 | } | 579 | } |
580 | if (error == -ESRCH) | 580 | if (error == -ESRCH) |
581 | error = 0; | 581 | error = 0; |
582 | set_user_nice(p, niceval); | 582 | set_user_nice(p, niceval); |
583 | out: | 583 | out: |
584 | return error; | 584 | return error; |
585 | } | 585 | } |
586 | 586 | ||
587 | asmlinkage long sys_setpriority(int which, int who, int niceval) | 587 | asmlinkage long sys_setpriority(int which, int who, int niceval) |
588 | { | 588 | { |
589 | struct task_struct *g, *p; | 589 | struct task_struct *g, *p; |
590 | struct user_struct *user; | 590 | struct user_struct *user; |
591 | int error = -EINVAL; | 591 | int error = -EINVAL; |
592 | 592 | ||
593 | if (which > 2 || which < 0) | 593 | if (which > 2 || which < 0) |
594 | goto out; | 594 | goto out; |
595 | 595 | ||
596 | /* normalize: avoid signed division (rounding problems) */ | 596 | /* normalize: avoid signed division (rounding problems) */ |
597 | error = -ESRCH; | 597 | error = -ESRCH; |
598 | if (niceval < -20) | 598 | if (niceval < -20) |
599 | niceval = -20; | 599 | niceval = -20; |
600 | if (niceval > 19) | 600 | if (niceval > 19) |
601 | niceval = 19; | 601 | niceval = 19; |
602 | 602 | ||
603 | read_lock(&tasklist_lock); | 603 | read_lock(&tasklist_lock); |
604 | switch (which) { | 604 | switch (which) { |
605 | case PRIO_PROCESS: | 605 | case PRIO_PROCESS: |
606 | if (!who) | 606 | if (!who) |
607 | who = current->pid; | 607 | who = current->pid; |
608 | p = find_task_by_pid(who); | 608 | p = find_task_by_pid(who); |
609 | if (p) | 609 | if (p) |
610 | error = set_one_prio(p, niceval, error); | 610 | error = set_one_prio(p, niceval, error); |
611 | break; | 611 | break; |
612 | case PRIO_PGRP: | 612 | case PRIO_PGRP: |
613 | if (!who) | 613 | if (!who) |
614 | who = process_group(current); | 614 | who = process_group(current); |
615 | do_each_task_pid(who, PIDTYPE_PGID, p) { | 615 | do_each_task_pid(who, PIDTYPE_PGID, p) { |
616 | error = set_one_prio(p, niceval, error); | 616 | error = set_one_prio(p, niceval, error); |
617 | } while_each_task_pid(who, PIDTYPE_PGID, p); | 617 | } while_each_task_pid(who, PIDTYPE_PGID, p); |
618 | break; | 618 | break; |
619 | case PRIO_USER: | 619 | case PRIO_USER: |
620 | user = current->user; | 620 | user = current->user; |
621 | if (!who) | 621 | if (!who) |
622 | who = current->uid; | 622 | who = current->uid; |
623 | else | 623 | else |
624 | if ((who != current->uid) && !(user = find_user(who))) | 624 | if ((who != current->uid) && !(user = find_user(who))) |
625 | goto out_unlock; /* No processes for this user */ | 625 | goto out_unlock; /* No processes for this user */ |
626 | 626 | ||
627 | do_each_thread(g, p) | 627 | do_each_thread(g, p) |
628 | if (p->uid == who) | 628 | if (p->uid == who) |
629 | error = set_one_prio(p, niceval, error); | 629 | error = set_one_prio(p, niceval, error); |
630 | while_each_thread(g, p); | 630 | while_each_thread(g, p); |
631 | if (who != current->uid) | 631 | if (who != current->uid) |
632 | free_uid(user); /* For find_user() */ | 632 | free_uid(user); /* For find_user() */ |
633 | break; | 633 | break; |
634 | } | 634 | } |
635 | out_unlock: | 635 | out_unlock: |
636 | read_unlock(&tasklist_lock); | 636 | read_unlock(&tasklist_lock); |
637 | out: | 637 | out: |
638 | return error; | 638 | return error; |
639 | } | 639 | } |
640 | 640 | ||
641 | /* | 641 | /* |
642 | * Ugh. To avoid negative return values, "getpriority()" will | 642 | * Ugh. To avoid negative return values, "getpriority()" will |
643 | * not return the normal nice-value, but a negated value that | 643 | * not return the normal nice-value, but a negated value that |
644 | * has been offset by 20 (ie it returns 40..1 instead of -20..19) | 644 | * has been offset by 20 (ie it returns 40..1 instead of -20..19) |
645 | * to stay compatible. | 645 | * to stay compatible. |
646 | */ | 646 | */ |
647 | asmlinkage long sys_getpriority(int which, int who) | 647 | asmlinkage long sys_getpriority(int which, int who) |
648 | { | 648 | { |
649 | struct task_struct *g, *p; | 649 | struct task_struct *g, *p; |
650 | struct user_struct *user; | 650 | struct user_struct *user; |
651 | long niceval, retval = -ESRCH; | 651 | long niceval, retval = -ESRCH; |
652 | 652 | ||
653 | if (which > 2 || which < 0) | 653 | if (which > 2 || which < 0) |
654 | return -EINVAL; | 654 | return -EINVAL; |
655 | 655 | ||
656 | read_lock(&tasklist_lock); | 656 | read_lock(&tasklist_lock); |
657 | switch (which) { | 657 | switch (which) { |
658 | case PRIO_PROCESS: | 658 | case PRIO_PROCESS: |
659 | if (!who) | 659 | if (!who) |
660 | who = current->pid; | 660 | who = current->pid; |
661 | p = find_task_by_pid(who); | 661 | p = find_task_by_pid(who); |
662 | if (p) { | 662 | if (p) { |
663 | niceval = 20 - task_nice(p); | 663 | niceval = 20 - task_nice(p); |
664 | if (niceval > retval) | 664 | if (niceval > retval) |
665 | retval = niceval; | 665 | retval = niceval; |
666 | } | 666 | } |
667 | break; | 667 | break; |
668 | case PRIO_PGRP: | 668 | case PRIO_PGRP: |
669 | if (!who) | 669 | if (!who) |
670 | who = process_group(current); | 670 | who = process_group(current); |
671 | do_each_task_pid(who, PIDTYPE_PGID, p) { | 671 | do_each_task_pid(who, PIDTYPE_PGID, p) { |
672 | niceval = 20 - task_nice(p); | 672 | niceval = 20 - task_nice(p); |
673 | if (niceval > retval) | 673 | if (niceval > retval) |
674 | retval = niceval; | 674 | retval = niceval; |
675 | } while_each_task_pid(who, PIDTYPE_PGID, p); | 675 | } while_each_task_pid(who, PIDTYPE_PGID, p); |
676 | break; | 676 | break; |
677 | case PRIO_USER: | 677 | case PRIO_USER: |
678 | user = current->user; | 678 | user = current->user; |
679 | if (!who) | 679 | if (!who) |
680 | who = current->uid; | 680 | who = current->uid; |
681 | else | 681 | else |
682 | if ((who != current->uid) && !(user = find_user(who))) | 682 | if ((who != current->uid) && !(user = find_user(who))) |
683 | goto out_unlock; /* No processes for this user */ | 683 | goto out_unlock; /* No processes for this user */ |
684 | 684 | ||
685 | do_each_thread(g, p) | 685 | do_each_thread(g, p) |
686 | if (p->uid == who) { | 686 | if (p->uid == who) { |
687 | niceval = 20 - task_nice(p); | 687 | niceval = 20 - task_nice(p); |
688 | if (niceval > retval) | 688 | if (niceval > retval) |
689 | retval = niceval; | 689 | retval = niceval; |
690 | } | 690 | } |
691 | while_each_thread(g, p); | 691 | while_each_thread(g, p); |
692 | if (who != current->uid) | 692 | if (who != current->uid) |
693 | free_uid(user); /* for find_user() */ | 693 | free_uid(user); /* for find_user() */ |
694 | break; | 694 | break; |
695 | } | 695 | } |
696 | out_unlock: | 696 | out_unlock: |
697 | read_unlock(&tasklist_lock); | 697 | read_unlock(&tasklist_lock); |
698 | 698 | ||
699 | return retval; | 699 | return retval; |
700 | } | 700 | } |
701 | 701 | ||
702 | /** | 702 | /** |
703 | * emergency_restart - reboot the system | 703 | * emergency_restart - reboot the system |
704 | * | 704 | * |
705 | * Without shutting down any hardware or taking any locks | 705 | * Without shutting down any hardware or taking any locks |
706 | * reboot the system. This is called when we know we are in | 706 | * reboot the system. This is called when we know we are in |
707 | * trouble so this is our best effort to reboot. This is | 707 | * trouble so this is our best effort to reboot. This is |
708 | * safe to call in interrupt context. | 708 | * safe to call in interrupt context. |
709 | */ | 709 | */ |
710 | void emergency_restart(void) | 710 | void emergency_restart(void) |
711 | { | 711 | { |
712 | machine_emergency_restart(); | 712 | machine_emergency_restart(); |
713 | } | 713 | } |
714 | EXPORT_SYMBOL_GPL(emergency_restart); | 714 | EXPORT_SYMBOL_GPL(emergency_restart); |
715 | 715 | ||
716 | static void kernel_restart_prepare(char *cmd) | 716 | static void kernel_restart_prepare(char *cmd) |
717 | { | 717 | { |
718 | blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); | 718 | blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); |
719 | system_state = SYSTEM_RESTART; | 719 | system_state = SYSTEM_RESTART; |
720 | device_shutdown(); | 720 | device_shutdown(); |
721 | } | 721 | } |
722 | 722 | ||
723 | /** | 723 | /** |
724 | * kernel_restart - reboot the system | 724 | * kernel_restart - reboot the system |
725 | * @cmd: pointer to buffer containing command to execute for restart | 725 | * @cmd: pointer to buffer containing command to execute for restart |
726 | * or %NULL | 726 | * or %NULL |
727 | * | 727 | * |
728 | * Shutdown everything and perform a clean reboot. | 728 | * Shutdown everything and perform a clean reboot. |
729 | * This is not safe to call in interrupt context. | 729 | * This is not safe to call in interrupt context. |
730 | */ | 730 | */ |
731 | void kernel_restart(char *cmd) | 731 | void kernel_restart(char *cmd) |
732 | { | 732 | { |
733 | kernel_restart_prepare(cmd); | 733 | kernel_restart_prepare(cmd); |
734 | if (!cmd) | 734 | if (!cmd) |
735 | printk(KERN_EMERG "Restarting system.\n"); | 735 | printk(KERN_EMERG "Restarting system.\n"); |
736 | else | 736 | else |
737 | printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd); | 737 | printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd); |
738 | machine_restart(cmd); | 738 | machine_restart(cmd); |
739 | } | 739 | } |
740 | EXPORT_SYMBOL_GPL(kernel_restart); | 740 | EXPORT_SYMBOL_GPL(kernel_restart); |
741 | 741 | ||
742 | /** | 742 | /** |
743 | * kernel_kexec - reboot the system | 743 | * kernel_kexec - reboot the system |
744 | * | 744 | * |
745 | * Move into place and start executing a preloaded standalone | 745 | * Move into place and start executing a preloaded standalone |
746 | * executable. If nothing was preloaded return an error. | 746 | * executable. If nothing was preloaded return an error. |
747 | */ | 747 | */ |
748 | static void kernel_kexec(void) | 748 | static void kernel_kexec(void) |
749 | { | 749 | { |
750 | #ifdef CONFIG_KEXEC | 750 | #ifdef CONFIG_KEXEC |
751 | struct kimage *image; | 751 | struct kimage *image; |
752 | image = xchg(&kexec_image, NULL); | 752 | image = xchg(&kexec_image, NULL); |
753 | if (!image) | 753 | if (!image) |
754 | return; | 754 | return; |
755 | kernel_restart_prepare(NULL); | 755 | kernel_restart_prepare(NULL); |
756 | printk(KERN_EMERG "Starting new kernel\n"); | 756 | printk(KERN_EMERG "Starting new kernel\n"); |
757 | machine_shutdown(); | 757 | machine_shutdown(); |
758 | machine_kexec(image); | 758 | machine_kexec(image); |
759 | #endif | 759 | #endif |
760 | } | 760 | } |
761 | 761 | ||
762 | void kernel_shutdown_prepare(enum system_states state) | 762 | void kernel_shutdown_prepare(enum system_states state) |
763 | { | 763 | { |
764 | blocking_notifier_call_chain(&reboot_notifier_list, | 764 | blocking_notifier_call_chain(&reboot_notifier_list, |
765 | (state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL); | 765 | (state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL); |
766 | system_state = state; | 766 | system_state = state; |
767 | device_shutdown(); | 767 | device_shutdown(); |
768 | } | 768 | } |
769 | /** | 769 | /** |
770 | * kernel_halt - halt the system | 770 | * kernel_halt - halt the system |
771 | * | 771 | * |
772 | * Shutdown everything and perform a clean system halt. | 772 | * Shutdown everything and perform a clean system halt. |
773 | */ | 773 | */ |
774 | void kernel_halt(void) | 774 | void kernel_halt(void) |
775 | { | 775 | { |
776 | kernel_shutdown_prepare(SYSTEM_HALT); | 776 | kernel_shutdown_prepare(SYSTEM_HALT); |
777 | printk(KERN_EMERG "System halted.\n"); | 777 | printk(KERN_EMERG "System halted.\n"); |
778 | machine_halt(); | 778 | machine_halt(); |
779 | } | 779 | } |
780 | 780 | ||
781 | EXPORT_SYMBOL_GPL(kernel_halt); | 781 | EXPORT_SYMBOL_GPL(kernel_halt); |
782 | 782 | ||
783 | /** | 783 | /** |
784 | * kernel_power_off - power_off the system | 784 | * kernel_power_off - power_off the system |
785 | * | 785 | * |
786 | * Shutdown everything and perform a clean system power_off. | 786 | * Shutdown everything and perform a clean system power_off. |
787 | */ | 787 | */ |
788 | void kernel_power_off(void) | 788 | void kernel_power_off(void) |
789 | { | 789 | { |
790 | kernel_shutdown_prepare(SYSTEM_POWER_OFF); | 790 | kernel_shutdown_prepare(SYSTEM_POWER_OFF); |
791 | printk(KERN_EMERG "Power down.\n"); | 791 | printk(KERN_EMERG "Power down.\n"); |
792 | machine_power_off(); | 792 | machine_power_off(); |
793 | } | 793 | } |
794 | EXPORT_SYMBOL_GPL(kernel_power_off); | 794 | EXPORT_SYMBOL_GPL(kernel_power_off); |
795 | /* | 795 | /* |
796 | * Reboot system call: for obvious reasons only root may call it, | 796 | * Reboot system call: for obvious reasons only root may call it, |
797 | * and even root needs to set up some magic numbers in the registers | 797 | * and even root needs to set up some magic numbers in the registers |
798 | * so that some mistake won't make this reboot the whole machine. | 798 | * so that some mistake won't make this reboot the whole machine. |
799 | * You can also set the meaning of the ctrl-alt-del-key here. | 799 | * You can also set the meaning of the ctrl-alt-del-key here. |
800 | * | 800 | * |
801 | * reboot doesn't sync: do that yourself before calling this. | 801 | * reboot doesn't sync: do that yourself before calling this. |
802 | */ | 802 | */ |
803 | asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user * arg) | 803 | asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user * arg) |
804 | { | 804 | { |
805 | char buffer[256]; | 805 | char buffer[256]; |
806 | 806 | ||
807 | /* We only trust the superuser with rebooting the system. */ | 807 | /* We only trust the superuser with rebooting the system. */ |
808 | if (!capable(CAP_SYS_BOOT)) | 808 | if (!capable(CAP_SYS_BOOT)) |
809 | return -EPERM; | 809 | return -EPERM; |
810 | 810 | ||
811 | /* For safety, we require "magic" arguments. */ | 811 | /* For safety, we require "magic" arguments. */ |
812 | if (magic1 != LINUX_REBOOT_MAGIC1 || | 812 | if (magic1 != LINUX_REBOOT_MAGIC1 || |
813 | (magic2 != LINUX_REBOOT_MAGIC2 && | 813 | (magic2 != LINUX_REBOOT_MAGIC2 && |
814 | magic2 != LINUX_REBOOT_MAGIC2A && | 814 | magic2 != LINUX_REBOOT_MAGIC2A && |
815 | magic2 != LINUX_REBOOT_MAGIC2B && | 815 | magic2 != LINUX_REBOOT_MAGIC2B && |
816 | magic2 != LINUX_REBOOT_MAGIC2C)) | 816 | magic2 != LINUX_REBOOT_MAGIC2C)) |
817 | return -EINVAL; | 817 | return -EINVAL; |
818 | 818 | ||
819 | /* Instead of trying to make the power_off code look like | 819 | /* Instead of trying to make the power_off code look like |
820 | * halt when pm_power_off is not set do it the easy way. | 820 | * halt when pm_power_off is not set do it the easy way. |
821 | */ | 821 | */ |
822 | if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off) | 822 | if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off) |
823 | cmd = LINUX_REBOOT_CMD_HALT; | 823 | cmd = LINUX_REBOOT_CMD_HALT; |
824 | 824 | ||
825 | lock_kernel(); | 825 | lock_kernel(); |
826 | switch (cmd) { | 826 | switch (cmd) { |
827 | case LINUX_REBOOT_CMD_RESTART: | 827 | case LINUX_REBOOT_CMD_RESTART: |
828 | kernel_restart(NULL); | 828 | kernel_restart(NULL); |
829 | break; | 829 | break; |
830 | 830 | ||
831 | case LINUX_REBOOT_CMD_CAD_ON: | 831 | case LINUX_REBOOT_CMD_CAD_ON: |
832 | C_A_D = 1; | 832 | C_A_D = 1; |
833 | break; | 833 | break; |
834 | 834 | ||
835 | case LINUX_REBOOT_CMD_CAD_OFF: | 835 | case LINUX_REBOOT_CMD_CAD_OFF: |
836 | C_A_D = 0; | 836 | C_A_D = 0; |
837 | break; | 837 | break; |
838 | 838 | ||
839 | case LINUX_REBOOT_CMD_HALT: | 839 | case LINUX_REBOOT_CMD_HALT: |
840 | kernel_halt(); | 840 | kernel_halt(); |
841 | unlock_kernel(); | 841 | unlock_kernel(); |
842 | do_exit(0); | 842 | do_exit(0); |
843 | break; | 843 | break; |
844 | 844 | ||
845 | case LINUX_REBOOT_CMD_POWER_OFF: | 845 | case LINUX_REBOOT_CMD_POWER_OFF: |
846 | kernel_power_off(); | 846 | kernel_power_off(); |
847 | unlock_kernel(); | 847 | unlock_kernel(); |
848 | do_exit(0); | 848 | do_exit(0); |
849 | break; | 849 | break; |
850 | 850 | ||
851 | case LINUX_REBOOT_CMD_RESTART2: | 851 | case LINUX_REBOOT_CMD_RESTART2: |
852 | if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) { | 852 | if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) { |
853 | unlock_kernel(); | 853 | unlock_kernel(); |
854 | return -EFAULT; | 854 | return -EFAULT; |
855 | } | 855 | } |
856 | buffer[sizeof(buffer) - 1] = '\0'; | 856 | buffer[sizeof(buffer) - 1] = '\0'; |
857 | 857 | ||
858 | kernel_restart(buffer); | 858 | kernel_restart(buffer); |
859 | break; | 859 | break; |
860 | 860 | ||
861 | case LINUX_REBOOT_CMD_KEXEC: | 861 | case LINUX_REBOOT_CMD_KEXEC: |
862 | kernel_kexec(); | 862 | kernel_kexec(); |
863 | unlock_kernel(); | 863 | unlock_kernel(); |
864 | return -EINVAL; | 864 | return -EINVAL; |
865 | 865 | ||
866 | #ifdef CONFIG_SOFTWARE_SUSPEND | 866 | #ifdef CONFIG_SOFTWARE_SUSPEND |
867 | case LINUX_REBOOT_CMD_SW_SUSPEND: | 867 | case LINUX_REBOOT_CMD_SW_SUSPEND: |
868 | { | 868 | { |
869 | int ret = software_suspend(); | 869 | int ret = software_suspend(); |
870 | unlock_kernel(); | 870 | unlock_kernel(); |
871 | return ret; | 871 | return ret; |
872 | } | 872 | } |
873 | #endif | 873 | #endif |
874 | 874 | ||
875 | default: | 875 | default: |
876 | unlock_kernel(); | 876 | unlock_kernel(); |
877 | return -EINVAL; | 877 | return -EINVAL; |
878 | } | 878 | } |
879 | unlock_kernel(); | 879 | unlock_kernel(); |
880 | return 0; | 880 | return 0; |
881 | } | 881 | } |
882 | 882 | ||
883 | static void deferred_cad(struct work_struct *dummy) | 883 | static void deferred_cad(struct work_struct *dummy) |
884 | { | 884 | { |
885 | kernel_restart(NULL); | 885 | kernel_restart(NULL); |
886 | } | 886 | } |
887 | 887 | ||
888 | /* | 888 | /* |
889 | * This function gets called by ctrl-alt-del - ie the keyboard interrupt. | 889 | * This function gets called by ctrl-alt-del - ie the keyboard interrupt. |
890 | * As it's called within an interrupt, it may NOT sync: the only choice | 890 | * As it's called within an interrupt, it may NOT sync: the only choice |
891 | * is whether to reboot at once, or just ignore the ctrl-alt-del. | 891 | * is whether to reboot at once, or just ignore the ctrl-alt-del. |
892 | */ | 892 | */ |
893 | void ctrl_alt_del(void) | 893 | void ctrl_alt_del(void) |
894 | { | 894 | { |
895 | static DECLARE_WORK(cad_work, deferred_cad); | 895 | static DECLARE_WORK(cad_work, deferred_cad); |
896 | 896 | ||
897 | if (C_A_D) | 897 | if (C_A_D) |
898 | schedule_work(&cad_work); | 898 | schedule_work(&cad_work); |
899 | else | 899 | else |
900 | kill_cad_pid(SIGINT, 1); | 900 | kill_cad_pid(SIGINT, 1); |
901 | } | 901 | } |
902 | 902 | ||
903 | /* | 903 | /* |
904 | * Unprivileged users may change the real gid to the effective gid | 904 | * Unprivileged users may change the real gid to the effective gid |
905 | * or vice versa. (BSD-style) | 905 | * or vice versa. (BSD-style) |
906 | * | 906 | * |
907 | * If you set the real gid at all, or set the effective gid to a value not | 907 | * If you set the real gid at all, or set the effective gid to a value not |
908 | * equal to the real gid, then the saved gid is set to the new effective gid. | 908 | * equal to the real gid, then the saved gid is set to the new effective gid. |
909 | * | 909 | * |
910 | * This makes it possible for a setgid program to completely drop its | 910 | * This makes it possible for a setgid program to completely drop its |
911 | * privileges, which is often a useful assertion to make when you are doing | 911 | * privileges, which is often a useful assertion to make when you are doing |
912 | * a security audit over a program. | 912 | * a security audit over a program. |
913 | * | 913 | * |
914 | * The general idea is that a program which uses just setregid() will be | 914 | * The general idea is that a program which uses just setregid() will be |
915 | * 100% compatible with BSD. A program which uses just setgid() will be | 915 | * 100% compatible with BSD. A program which uses just setgid() will be |
916 | * 100% compatible with POSIX with saved IDs. | 916 | * 100% compatible with POSIX with saved IDs. |
917 | * | 917 | * |
918 | * SMP: There are not races, the GIDs are checked only by filesystem | 918 | * SMP: There are not races, the GIDs are checked only by filesystem |
919 | * operations (as far as semantic preservation is concerned). | 919 | * operations (as far as semantic preservation is concerned). |
920 | */ | 920 | */ |
921 | asmlinkage long sys_setregid(gid_t rgid, gid_t egid) | 921 | asmlinkage long sys_setregid(gid_t rgid, gid_t egid) |
922 | { | 922 | { |
923 | int old_rgid = current->gid; | 923 | int old_rgid = current->gid; |
924 | int old_egid = current->egid; | 924 | int old_egid = current->egid; |
925 | int new_rgid = old_rgid; | 925 | int new_rgid = old_rgid; |
926 | int new_egid = old_egid; | 926 | int new_egid = old_egid; |
927 | int retval; | 927 | int retval; |
928 | 928 | ||
929 | retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE); | 929 | retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE); |
930 | if (retval) | 930 | if (retval) |
931 | return retval; | 931 | return retval; |
932 | 932 | ||
933 | if (rgid != (gid_t) -1) { | 933 | if (rgid != (gid_t) -1) { |
934 | if ((old_rgid == rgid) || | 934 | if ((old_rgid == rgid) || |
935 | (current->egid==rgid) || | 935 | (current->egid==rgid) || |
936 | capable(CAP_SETGID)) | 936 | capable(CAP_SETGID)) |
937 | new_rgid = rgid; | 937 | new_rgid = rgid; |
938 | else | 938 | else |
939 | return -EPERM; | 939 | return -EPERM; |
940 | } | 940 | } |
941 | if (egid != (gid_t) -1) { | 941 | if (egid != (gid_t) -1) { |
942 | if ((old_rgid == egid) || | 942 | if ((old_rgid == egid) || |
943 | (current->egid == egid) || | 943 | (current->egid == egid) || |
944 | (current->sgid == egid) || | 944 | (current->sgid == egid) || |
945 | capable(CAP_SETGID)) | 945 | capable(CAP_SETGID)) |
946 | new_egid = egid; | 946 | new_egid = egid; |
947 | else | 947 | else |
948 | return -EPERM; | 948 | return -EPERM; |
949 | } | 949 | } |
950 | if (new_egid != old_egid) { | 950 | if (new_egid != old_egid) { |
951 | current->mm->dumpable = suid_dumpable; | 951 | current->mm->dumpable = suid_dumpable; |
952 | smp_wmb(); | 952 | smp_wmb(); |
953 | } | 953 | } |
954 | if (rgid != (gid_t) -1 || | 954 | if (rgid != (gid_t) -1 || |
955 | (egid != (gid_t) -1 && egid != old_rgid)) | 955 | (egid != (gid_t) -1 && egid != old_rgid)) |
956 | current->sgid = new_egid; | 956 | current->sgid = new_egid; |
957 | current->fsgid = new_egid; | 957 | current->fsgid = new_egid; |
958 | current->egid = new_egid; | 958 | current->egid = new_egid; |
959 | current->gid = new_rgid; | 959 | current->gid = new_rgid; |
960 | key_fsgid_changed(current); | 960 | key_fsgid_changed(current); |
961 | proc_id_connector(current, PROC_EVENT_GID); | 961 | proc_id_connector(current, PROC_EVENT_GID); |
962 | return 0; | 962 | return 0; |
963 | } | 963 | } |
964 | 964 | ||
965 | /* | 965 | /* |
966 | * setgid() is implemented like SysV w/ SAVED_IDS | 966 | * setgid() is implemented like SysV w/ SAVED_IDS |
967 | * | 967 | * |
968 | * SMP: Same implicit races as above. | 968 | * SMP: Same implicit races as above. |
969 | */ | 969 | */ |
970 | asmlinkage long sys_setgid(gid_t gid) | 970 | asmlinkage long sys_setgid(gid_t gid) |
971 | { | 971 | { |
972 | int old_egid = current->egid; | 972 | int old_egid = current->egid; |
973 | int retval; | 973 | int retval; |
974 | 974 | ||
975 | retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID); | 975 | retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID); |
976 | if (retval) | 976 | if (retval) |
977 | return retval; | 977 | return retval; |
978 | 978 | ||
979 | if (capable(CAP_SETGID)) { | 979 | if (capable(CAP_SETGID)) { |
980 | if (old_egid != gid) { | 980 | if (old_egid != gid) { |
981 | current->mm->dumpable = suid_dumpable; | 981 | current->mm->dumpable = suid_dumpable; |
982 | smp_wmb(); | 982 | smp_wmb(); |
983 | } | 983 | } |
984 | current->gid = current->egid = current->sgid = current->fsgid = gid; | 984 | current->gid = current->egid = current->sgid = current->fsgid = gid; |
985 | } else if ((gid == current->gid) || (gid == current->sgid)) { | 985 | } else if ((gid == current->gid) || (gid == current->sgid)) { |
986 | if (old_egid != gid) { | 986 | if (old_egid != gid) { |
987 | current->mm->dumpable = suid_dumpable; | 987 | current->mm->dumpable = suid_dumpable; |
988 | smp_wmb(); | 988 | smp_wmb(); |
989 | } | 989 | } |
990 | current->egid = current->fsgid = gid; | 990 | current->egid = current->fsgid = gid; |
991 | } | 991 | } |
992 | else | 992 | else |
993 | return -EPERM; | 993 | return -EPERM; |
994 | 994 | ||
995 | key_fsgid_changed(current); | 995 | key_fsgid_changed(current); |
996 | proc_id_connector(current, PROC_EVENT_GID); | 996 | proc_id_connector(current, PROC_EVENT_GID); |
997 | return 0; | 997 | return 0; |
998 | } | 998 | } |
999 | 999 | ||
1000 | static int set_user(uid_t new_ruid, int dumpclear) | 1000 | static int set_user(uid_t new_ruid, int dumpclear) |
1001 | { | 1001 | { |
1002 | struct user_struct *new_user; | 1002 | struct user_struct *new_user; |
1003 | 1003 | ||
1004 | new_user = alloc_uid(new_ruid); | 1004 | new_user = alloc_uid(new_ruid); |
1005 | if (!new_user) | 1005 | if (!new_user) |
1006 | return -EAGAIN; | 1006 | return -EAGAIN; |
1007 | 1007 | ||
1008 | if (atomic_read(&new_user->processes) >= | 1008 | if (atomic_read(&new_user->processes) >= |
1009 | current->signal->rlim[RLIMIT_NPROC].rlim_cur && | 1009 | current->signal->rlim[RLIMIT_NPROC].rlim_cur && |
1010 | new_user != &root_user) { | 1010 | new_user != &root_user) { |
1011 | free_uid(new_user); | 1011 | free_uid(new_user); |
1012 | return -EAGAIN; | 1012 | return -EAGAIN; |
1013 | } | 1013 | } |
1014 | 1014 | ||
1015 | switch_uid(new_user); | 1015 | switch_uid(new_user); |
1016 | 1016 | ||
1017 | if (dumpclear) { | 1017 | if (dumpclear) { |
1018 | current->mm->dumpable = suid_dumpable; | 1018 | current->mm->dumpable = suid_dumpable; |
1019 | smp_wmb(); | 1019 | smp_wmb(); |
1020 | } | 1020 | } |
1021 | current->uid = new_ruid; | 1021 | current->uid = new_ruid; |
1022 | return 0; | 1022 | return 0; |
1023 | } | 1023 | } |
1024 | 1024 | ||
1025 | /* | 1025 | /* |
1026 | * Unprivileged users may change the real uid to the effective uid | 1026 | * Unprivileged users may change the real uid to the effective uid |
1027 | * or vice versa. (BSD-style) | 1027 | * or vice versa. (BSD-style) |
1028 | * | 1028 | * |
1029 | * If you set the real uid at all, or set the effective uid to a value not | 1029 | * If you set the real uid at all, or set the effective uid to a value not |
1030 | * equal to the real uid, then the saved uid is set to the new effective uid. | 1030 | * equal to the real uid, then the saved uid is set to the new effective uid. |
1031 | * | 1031 | * |
1032 | * This makes it possible for a setuid program to completely drop its | 1032 | * This makes it possible for a setuid program to completely drop its |
1033 | * privileges, which is often a useful assertion to make when you are doing | 1033 | * privileges, which is often a useful assertion to make when you are doing |
1034 | * a security audit over a program. | 1034 | * a security audit over a program. |
1035 | * | 1035 | * |
1036 | * The general idea is that a program which uses just setreuid() will be | 1036 | * The general idea is that a program which uses just setreuid() will be |
1037 | * 100% compatible with BSD. A program which uses just setuid() will be | 1037 | * 100% compatible with BSD. A program which uses just setuid() will be |
1038 | * 100% compatible with POSIX with saved IDs. | 1038 | * 100% compatible with POSIX with saved IDs. |
1039 | */ | 1039 | */ |
1040 | asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) | 1040 | asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) |
1041 | { | 1041 | { |
1042 | int old_ruid, old_euid, old_suid, new_ruid, new_euid; | 1042 | int old_ruid, old_euid, old_suid, new_ruid, new_euid; |
1043 | int retval; | 1043 | int retval; |
1044 | 1044 | ||
1045 | retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE); | 1045 | retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE); |
1046 | if (retval) | 1046 | if (retval) |
1047 | return retval; | 1047 | return retval; |
1048 | 1048 | ||
1049 | new_ruid = old_ruid = current->uid; | 1049 | new_ruid = old_ruid = current->uid; |
1050 | new_euid = old_euid = current->euid; | 1050 | new_euid = old_euid = current->euid; |
1051 | old_suid = current->suid; | 1051 | old_suid = current->suid; |
1052 | 1052 | ||
1053 | if (ruid != (uid_t) -1) { | 1053 | if (ruid != (uid_t) -1) { |
1054 | new_ruid = ruid; | 1054 | new_ruid = ruid; |
1055 | if ((old_ruid != ruid) && | 1055 | if ((old_ruid != ruid) && |
1056 | (current->euid != ruid) && | 1056 | (current->euid != ruid) && |
1057 | !capable(CAP_SETUID)) | 1057 | !capable(CAP_SETUID)) |
1058 | return -EPERM; | 1058 | return -EPERM; |
1059 | } | 1059 | } |
1060 | 1060 | ||
1061 | if (euid != (uid_t) -1) { | 1061 | if (euid != (uid_t) -1) { |
1062 | new_euid = euid; | 1062 | new_euid = euid; |
1063 | if ((old_ruid != euid) && | 1063 | if ((old_ruid != euid) && |
1064 | (current->euid != euid) && | 1064 | (current->euid != euid) && |
1065 | (current->suid != euid) && | 1065 | (current->suid != euid) && |
1066 | !capable(CAP_SETUID)) | 1066 | !capable(CAP_SETUID)) |
1067 | return -EPERM; | 1067 | return -EPERM; |
1068 | } | 1068 | } |
1069 | 1069 | ||
1070 | if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0) | 1070 | if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0) |
1071 | return -EAGAIN; | 1071 | return -EAGAIN; |
1072 | 1072 | ||
1073 | if (new_euid != old_euid) { | 1073 | if (new_euid != old_euid) { |
1074 | current->mm->dumpable = suid_dumpable; | 1074 | current->mm->dumpable = suid_dumpable; |
1075 | smp_wmb(); | 1075 | smp_wmb(); |
1076 | } | 1076 | } |
1077 | current->fsuid = current->euid = new_euid; | 1077 | current->fsuid = current->euid = new_euid; |
1078 | if (ruid != (uid_t) -1 || | 1078 | if (ruid != (uid_t) -1 || |
1079 | (euid != (uid_t) -1 && euid != old_ruid)) | 1079 | (euid != (uid_t) -1 && euid != old_ruid)) |
1080 | current->suid = current->euid; | 1080 | current->suid = current->euid; |
1081 | current->fsuid = current->euid; | 1081 | current->fsuid = current->euid; |
1082 | 1082 | ||
1083 | key_fsuid_changed(current); | 1083 | key_fsuid_changed(current); |
1084 | proc_id_connector(current, PROC_EVENT_UID); | 1084 | proc_id_connector(current, PROC_EVENT_UID); |
1085 | 1085 | ||
1086 | return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE); | 1086 | return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE); |
1087 | } | 1087 | } |
1088 | 1088 | ||
1089 | 1089 | ||
1090 | 1090 | ||
1091 | /* | 1091 | /* |
1092 | * setuid() is implemented like SysV with SAVED_IDS | 1092 | * setuid() is implemented like SysV with SAVED_IDS |
1093 | * | 1093 | * |
1094 | * Note that SAVED_ID's is deficient in that a setuid root program | 1094 | * Note that SAVED_ID's is deficient in that a setuid root program |
1095 | * like sendmail, for example, cannot set its uid to be a normal | 1095 | * like sendmail, for example, cannot set its uid to be a normal |
1096 | * user and then switch back, because if you're root, setuid() sets | 1096 | * user and then switch back, because if you're root, setuid() sets |
1097 | * the saved uid too. If you don't like this, blame the bright people | 1097 | * the saved uid too. If you don't like this, blame the bright people |
1098 | * in the POSIX committee and/or USG. Note that the BSD-style setreuid() | 1098 | * in the POSIX committee and/or USG. Note that the BSD-style setreuid() |
1099 | * will allow a root program to temporarily drop privileges and be able to | 1099 | * will allow a root program to temporarily drop privileges and be able to |
1100 | * regain them by swapping the real and effective uid. | 1100 | * regain them by swapping the real and effective uid. |
1101 | */ | 1101 | */ |
1102 | asmlinkage long sys_setuid(uid_t uid) | 1102 | asmlinkage long sys_setuid(uid_t uid) |
1103 | { | 1103 | { |
1104 | int old_euid = current->euid; | 1104 | int old_euid = current->euid; |
1105 | int old_ruid, old_suid, new_suid; | 1105 | int old_ruid, old_suid, new_suid; |
1106 | int retval; | 1106 | int retval; |
1107 | 1107 | ||
1108 | retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID); | 1108 | retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID); |
1109 | if (retval) | 1109 | if (retval) |
1110 | return retval; | 1110 | return retval; |
1111 | 1111 | ||
1112 | old_ruid = current->uid; | 1112 | old_ruid = current->uid; |
1113 | old_suid = current->suid; | 1113 | old_suid = current->suid; |
1114 | new_suid = old_suid; | 1114 | new_suid = old_suid; |
1115 | 1115 | ||
1116 | if (capable(CAP_SETUID)) { | 1116 | if (capable(CAP_SETUID)) { |
1117 | if (uid != old_ruid && set_user(uid, old_euid != uid) < 0) | 1117 | if (uid != old_ruid && set_user(uid, old_euid != uid) < 0) |
1118 | return -EAGAIN; | 1118 | return -EAGAIN; |
1119 | new_suid = uid; | 1119 | new_suid = uid; |
1120 | } else if ((uid != current->uid) && (uid != new_suid)) | 1120 | } else if ((uid != current->uid) && (uid != new_suid)) |
1121 | return -EPERM; | 1121 | return -EPERM; |
1122 | 1122 | ||
1123 | if (old_euid != uid) { | 1123 | if (old_euid != uid) { |
1124 | current->mm->dumpable = suid_dumpable; | 1124 | current->mm->dumpable = suid_dumpable; |
1125 | smp_wmb(); | 1125 | smp_wmb(); |
1126 | } | 1126 | } |
1127 | current->fsuid = current->euid = uid; | 1127 | current->fsuid = current->euid = uid; |
1128 | current->suid = new_suid; | 1128 | current->suid = new_suid; |
1129 | 1129 | ||
1130 | key_fsuid_changed(current); | 1130 | key_fsuid_changed(current); |
1131 | proc_id_connector(current, PROC_EVENT_UID); | 1131 | proc_id_connector(current, PROC_EVENT_UID); |
1132 | 1132 | ||
1133 | return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID); | 1133 | return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID); |
1134 | } | 1134 | } |
1135 | 1135 | ||
1136 | 1136 | ||
1137 | /* | 1137 | /* |
1138 | * This function implements a generic ability to update ruid, euid, | 1138 | * This function implements a generic ability to update ruid, euid, |
1139 | * and suid. This allows you to implement the 4.4 compatible seteuid(). | 1139 | * and suid. This allows you to implement the 4.4 compatible seteuid(). |
1140 | */ | 1140 | */ |
1141 | asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) | 1141 | asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) |
1142 | { | 1142 | { |
1143 | int old_ruid = current->uid; | 1143 | int old_ruid = current->uid; |
1144 | int old_euid = current->euid; | 1144 | int old_euid = current->euid; |
1145 | int old_suid = current->suid; | 1145 | int old_suid = current->suid; |
1146 | int retval; | 1146 | int retval; |
1147 | 1147 | ||
1148 | retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES); | 1148 | retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES); |
1149 | if (retval) | 1149 | if (retval) |
1150 | return retval; | 1150 | return retval; |
1151 | 1151 | ||
1152 | if (!capable(CAP_SETUID)) { | 1152 | if (!capable(CAP_SETUID)) { |
1153 | if ((ruid != (uid_t) -1) && (ruid != current->uid) && | 1153 | if ((ruid != (uid_t) -1) && (ruid != current->uid) && |
1154 | (ruid != current->euid) && (ruid != current->suid)) | 1154 | (ruid != current->euid) && (ruid != current->suid)) |
1155 | return -EPERM; | 1155 | return -EPERM; |
1156 | if ((euid != (uid_t) -1) && (euid != current->uid) && | 1156 | if ((euid != (uid_t) -1) && (euid != current->uid) && |
1157 | (euid != current->euid) && (euid != current->suid)) | 1157 | (euid != current->euid) && (euid != current->suid)) |
1158 | return -EPERM; | 1158 | return -EPERM; |
1159 | if ((suid != (uid_t) -1) && (suid != current->uid) && | 1159 | if ((suid != (uid_t) -1) && (suid != current->uid) && |
1160 | (suid != current->euid) && (suid != current->suid)) | 1160 | (suid != current->euid) && (suid != current->suid)) |
1161 | return -EPERM; | 1161 | return -EPERM; |
1162 | } | 1162 | } |
1163 | if (ruid != (uid_t) -1) { | 1163 | if (ruid != (uid_t) -1) { |
1164 | if (ruid != current->uid && set_user(ruid, euid != current->euid) < 0) | 1164 | if (ruid != current->uid && set_user(ruid, euid != current->euid) < 0) |
1165 | return -EAGAIN; | 1165 | return -EAGAIN; |
1166 | } | 1166 | } |
1167 | if (euid != (uid_t) -1) { | 1167 | if (euid != (uid_t) -1) { |
1168 | if (euid != current->euid) { | 1168 | if (euid != current->euid) { |
1169 | current->mm->dumpable = suid_dumpable; | 1169 | current->mm->dumpable = suid_dumpable; |
1170 | smp_wmb(); | 1170 | smp_wmb(); |
1171 | } | 1171 | } |
1172 | current->euid = euid; | 1172 | current->euid = euid; |
1173 | } | 1173 | } |
1174 | current->fsuid = current->euid; | 1174 | current->fsuid = current->euid; |
1175 | if (suid != (uid_t) -1) | 1175 | if (suid != (uid_t) -1) |
1176 | current->suid = suid; | 1176 | current->suid = suid; |
1177 | 1177 | ||
1178 | key_fsuid_changed(current); | 1178 | key_fsuid_changed(current); |
1179 | proc_id_connector(current, PROC_EVENT_UID); | 1179 | proc_id_connector(current, PROC_EVENT_UID); |
1180 | 1180 | ||
1181 | return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES); | 1181 | return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES); |
1182 | } | 1182 | } |
1183 | 1183 | ||
1184 | asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid) | 1184 | asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid) |
1185 | { | 1185 | { |
1186 | int retval; | 1186 | int retval; |
1187 | 1187 | ||
1188 | if (!(retval = put_user(current->uid, ruid)) && | 1188 | if (!(retval = put_user(current->uid, ruid)) && |
1189 | !(retval = put_user(current->euid, euid))) | 1189 | !(retval = put_user(current->euid, euid))) |
1190 | retval = put_user(current->suid, suid); | 1190 | retval = put_user(current->suid, suid); |
1191 | 1191 | ||
1192 | return retval; | 1192 | return retval; |
1193 | } | 1193 | } |
1194 | 1194 | ||
1195 | /* | 1195 | /* |
1196 | * Same as above, but for rgid, egid, sgid. | 1196 | * Same as above, but for rgid, egid, sgid. |
1197 | */ | 1197 | */ |
1198 | asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) | 1198 | asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) |
1199 | { | 1199 | { |
1200 | int retval; | 1200 | int retval; |
1201 | 1201 | ||
1202 | retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES); | 1202 | retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES); |
1203 | if (retval) | 1203 | if (retval) |
1204 | return retval; | 1204 | return retval; |
1205 | 1205 | ||
1206 | if (!capable(CAP_SETGID)) { | 1206 | if (!capable(CAP_SETGID)) { |
1207 | if ((rgid != (gid_t) -1) && (rgid != current->gid) && | 1207 | if ((rgid != (gid_t) -1) && (rgid != current->gid) && |
1208 | (rgid != current->egid) && (rgid != current->sgid)) | 1208 | (rgid != current->egid) && (rgid != current->sgid)) |
1209 | return -EPERM; | 1209 | return -EPERM; |
1210 | if ((egid != (gid_t) -1) && (egid != current->gid) && | 1210 | if ((egid != (gid_t) -1) && (egid != current->gid) && |
1211 | (egid != current->egid) && (egid != current->sgid)) | 1211 | (egid != current->egid) && (egid != current->sgid)) |
1212 | return -EPERM; | 1212 | return -EPERM; |
1213 | if ((sgid != (gid_t) -1) && (sgid != current->gid) && | 1213 | if ((sgid != (gid_t) -1) && (sgid != current->gid) && |
1214 | (sgid != current->egid) && (sgid != current->sgid)) | 1214 | (sgid != current->egid) && (sgid != current->sgid)) |
1215 | return -EPERM; | 1215 | return -EPERM; |
1216 | } | 1216 | } |
1217 | if (egid != (gid_t) -1) { | 1217 | if (egid != (gid_t) -1) { |
1218 | if (egid != current->egid) { | 1218 | if (egid != current->egid) { |
1219 | current->mm->dumpable = suid_dumpable; | 1219 | current->mm->dumpable = suid_dumpable; |
1220 | smp_wmb(); | 1220 | smp_wmb(); |
1221 | } | 1221 | } |
1222 | current->egid = egid; | 1222 | current->egid = egid; |
1223 | } | 1223 | } |
1224 | current->fsgid = current->egid; | 1224 | current->fsgid = current->egid; |
1225 | if (rgid != (gid_t) -1) | 1225 | if (rgid != (gid_t) -1) |
1226 | current->gid = rgid; | 1226 | current->gid = rgid; |
1227 | if (sgid != (gid_t) -1) | 1227 | if (sgid != (gid_t) -1) |
1228 | current->sgid = sgid; | 1228 | current->sgid = sgid; |
1229 | 1229 | ||
1230 | key_fsgid_changed(current); | 1230 | key_fsgid_changed(current); |
1231 | proc_id_connector(current, PROC_EVENT_GID); | 1231 | proc_id_connector(current, PROC_EVENT_GID); |
1232 | return 0; | 1232 | return 0; |
1233 | } | 1233 | } |
1234 | 1234 | ||
1235 | asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid) | 1235 | asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid) |
1236 | { | 1236 | { |
1237 | int retval; | 1237 | int retval; |
1238 | 1238 | ||
1239 | if (!(retval = put_user(current->gid, rgid)) && | 1239 | if (!(retval = put_user(current->gid, rgid)) && |
1240 | !(retval = put_user(current->egid, egid))) | 1240 | !(retval = put_user(current->egid, egid))) |
1241 | retval = put_user(current->sgid, sgid); | 1241 | retval = put_user(current->sgid, sgid); |
1242 | 1242 | ||
1243 | return retval; | 1243 | return retval; |
1244 | } | 1244 | } |
1245 | 1245 | ||
1246 | 1246 | ||
1247 | /* | 1247 | /* |
1248 | * "setfsuid()" sets the fsuid - the uid used for filesystem checks. This | 1248 | * "setfsuid()" sets the fsuid - the uid used for filesystem checks. This |
1249 | * is used for "access()" and for the NFS daemon (letting nfsd stay at | 1249 | * is used for "access()" and for the NFS daemon (letting nfsd stay at |
1250 | * whatever uid it wants to). It normally shadows "euid", except when | 1250 | * whatever uid it wants to). It normally shadows "euid", except when |
1251 | * explicitly set by setfsuid() or for access.. | 1251 | * explicitly set by setfsuid() or for access.. |
1252 | */ | 1252 | */ |
1253 | asmlinkage long sys_setfsuid(uid_t uid) | 1253 | asmlinkage long sys_setfsuid(uid_t uid) |
1254 | { | 1254 | { |
1255 | int old_fsuid; | 1255 | int old_fsuid; |
1256 | 1256 | ||
1257 | old_fsuid = current->fsuid; | 1257 | old_fsuid = current->fsuid; |
1258 | if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS)) | 1258 | if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS)) |
1259 | return old_fsuid; | 1259 | return old_fsuid; |
1260 | 1260 | ||
1261 | if (uid == current->uid || uid == current->euid || | 1261 | if (uid == current->uid || uid == current->euid || |
1262 | uid == current->suid || uid == current->fsuid || | 1262 | uid == current->suid || uid == current->fsuid || |
1263 | capable(CAP_SETUID)) { | 1263 | capable(CAP_SETUID)) { |
1264 | if (uid != old_fsuid) { | 1264 | if (uid != old_fsuid) { |
1265 | current->mm->dumpable = suid_dumpable; | 1265 | current->mm->dumpable = suid_dumpable; |
1266 | smp_wmb(); | 1266 | smp_wmb(); |
1267 | } | 1267 | } |
1268 | current->fsuid = uid; | 1268 | current->fsuid = uid; |
1269 | } | 1269 | } |
1270 | 1270 | ||
1271 | key_fsuid_changed(current); | 1271 | key_fsuid_changed(current); |
1272 | proc_id_connector(current, PROC_EVENT_UID); | 1272 | proc_id_connector(current, PROC_EVENT_UID); |
1273 | 1273 | ||
1274 | security_task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS); | 1274 | security_task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS); |
1275 | 1275 | ||
1276 | return old_fsuid; | 1276 | return old_fsuid; |
1277 | } | 1277 | } |
1278 | 1278 | ||
1279 | /* | 1279 | /* |
1280 | * Samma pรฅ svenska.. | 1280 | * Samma pรฅ svenska.. |
1281 | */ | 1281 | */ |
1282 | asmlinkage long sys_setfsgid(gid_t gid) | 1282 | asmlinkage long sys_setfsgid(gid_t gid) |
1283 | { | 1283 | { |
1284 | int old_fsgid; | 1284 | int old_fsgid; |
1285 | 1285 | ||
1286 | old_fsgid = current->fsgid; | 1286 | old_fsgid = current->fsgid; |
1287 | if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS)) | 1287 | if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS)) |
1288 | return old_fsgid; | 1288 | return old_fsgid; |
1289 | 1289 | ||
1290 | if (gid == current->gid || gid == current->egid || | 1290 | if (gid == current->gid || gid == current->egid || |
1291 | gid == current->sgid || gid == current->fsgid || | 1291 | gid == current->sgid || gid == current->fsgid || |
1292 | capable(CAP_SETGID)) { | 1292 | capable(CAP_SETGID)) { |
1293 | if (gid != old_fsgid) { | 1293 | if (gid != old_fsgid) { |
1294 | current->mm->dumpable = suid_dumpable; | 1294 | current->mm->dumpable = suid_dumpable; |
1295 | smp_wmb(); | 1295 | smp_wmb(); |
1296 | } | 1296 | } |
1297 | current->fsgid = gid; | 1297 | current->fsgid = gid; |
1298 | key_fsgid_changed(current); | 1298 | key_fsgid_changed(current); |
1299 | proc_id_connector(current, PROC_EVENT_GID); | 1299 | proc_id_connector(current, PROC_EVENT_GID); |
1300 | } | 1300 | } |
1301 | return old_fsgid; | 1301 | return old_fsgid; |
1302 | } | 1302 | } |
1303 | 1303 | ||
1304 | asmlinkage long sys_times(struct tms __user * tbuf) | 1304 | asmlinkage long sys_times(struct tms __user * tbuf) |
1305 | { | 1305 | { |
1306 | /* | 1306 | /* |
1307 | * In the SMP world we might just be unlucky and have one of | 1307 | * In the SMP world we might just be unlucky and have one of |
1308 | * the times increment as we use it. Since the value is an | 1308 | * the times increment as we use it. Since the value is an |
1309 | * atomically safe type this is just fine. Conceptually its | 1309 | * atomically safe type this is just fine. Conceptually its |
1310 | * as if the syscall took an instant longer to occur. | 1310 | * as if the syscall took an instant longer to occur. |
1311 | */ | 1311 | */ |
1312 | if (tbuf) { | 1312 | if (tbuf) { |
1313 | struct tms tmp; | 1313 | struct tms tmp; |
1314 | struct task_struct *tsk = current; | 1314 | struct task_struct *tsk = current; |
1315 | struct task_struct *t; | 1315 | struct task_struct *t; |
1316 | cputime_t utime, stime, cutime, cstime; | 1316 | cputime_t utime, stime, cutime, cstime; |
1317 | 1317 | ||
1318 | spin_lock_irq(&tsk->sighand->siglock); | 1318 | spin_lock_irq(&tsk->sighand->siglock); |
1319 | utime = tsk->signal->utime; | 1319 | utime = tsk->signal->utime; |
1320 | stime = tsk->signal->stime; | 1320 | stime = tsk->signal->stime; |
1321 | t = tsk; | 1321 | t = tsk; |
1322 | do { | 1322 | do { |
1323 | utime = cputime_add(utime, t->utime); | 1323 | utime = cputime_add(utime, t->utime); |
1324 | stime = cputime_add(stime, t->stime); | 1324 | stime = cputime_add(stime, t->stime); |
1325 | t = next_thread(t); | 1325 | t = next_thread(t); |
1326 | } while (t != tsk); | 1326 | } while (t != tsk); |
1327 | 1327 | ||
1328 | cutime = tsk->signal->cutime; | 1328 | cutime = tsk->signal->cutime; |
1329 | cstime = tsk->signal->cstime; | 1329 | cstime = tsk->signal->cstime; |
1330 | spin_unlock_irq(&tsk->sighand->siglock); | 1330 | spin_unlock_irq(&tsk->sighand->siglock); |
1331 | 1331 | ||
1332 | tmp.tms_utime = cputime_to_clock_t(utime); | 1332 | tmp.tms_utime = cputime_to_clock_t(utime); |
1333 | tmp.tms_stime = cputime_to_clock_t(stime); | 1333 | tmp.tms_stime = cputime_to_clock_t(stime); |
1334 | tmp.tms_cutime = cputime_to_clock_t(cutime); | 1334 | tmp.tms_cutime = cputime_to_clock_t(cutime); |
1335 | tmp.tms_cstime = cputime_to_clock_t(cstime); | 1335 | tmp.tms_cstime = cputime_to_clock_t(cstime); |
1336 | if (copy_to_user(tbuf, &tmp, sizeof(struct tms))) | 1336 | if (copy_to_user(tbuf, &tmp, sizeof(struct tms))) |
1337 | return -EFAULT; | 1337 | return -EFAULT; |
1338 | } | 1338 | } |
1339 | return (long) jiffies_64_to_clock_t(get_jiffies_64()); | 1339 | return (long) jiffies_64_to_clock_t(get_jiffies_64()); |
1340 | } | 1340 | } |
1341 | 1341 | ||
1342 | /* | 1342 | /* |
1343 | * This needs some heavy checking ... | 1343 | * This needs some heavy checking ... |
1344 | * I just haven't the stomach for it. I also don't fully | 1344 | * I just haven't the stomach for it. I also don't fully |
1345 | * understand sessions/pgrp etc. Let somebody who does explain it. | 1345 | * understand sessions/pgrp etc. Let somebody who does explain it. |
1346 | * | 1346 | * |
1347 | * OK, I think I have the protection semantics right.... this is really | 1347 | * OK, I think I have the protection semantics right.... this is really |
1348 | * only important on a multi-user system anyway, to make sure one user | 1348 | * only important on a multi-user system anyway, to make sure one user |
1349 | * can't send a signal to a process owned by another. -TYT, 12/12/91 | 1349 | * can't send a signal to a process owned by another. -TYT, 12/12/91 |
1350 | * | 1350 | * |
1351 | * Auch. Had to add the 'did_exec' flag to conform completely to POSIX. | 1351 | * Auch. Had to add the 'did_exec' flag to conform completely to POSIX. |
1352 | * LBT 04.03.94 | 1352 | * LBT 04.03.94 |
1353 | */ | 1353 | */ |
1354 | 1354 | ||
1355 | asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) | 1355 | asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) |
1356 | { | 1356 | { |
1357 | struct task_struct *p; | 1357 | struct task_struct *p; |
1358 | struct task_struct *group_leader = current->group_leader; | 1358 | struct task_struct *group_leader = current->group_leader; |
1359 | int err = -EINVAL; | 1359 | int err = -EINVAL; |
1360 | 1360 | ||
1361 | if (!pid) | 1361 | if (!pid) |
1362 | pid = group_leader->pid; | 1362 | pid = group_leader->pid; |
1363 | if (!pgid) | 1363 | if (!pgid) |
1364 | pgid = pid; | 1364 | pgid = pid; |
1365 | if (pgid < 0) | 1365 | if (pgid < 0) |
1366 | return -EINVAL; | 1366 | return -EINVAL; |
1367 | 1367 | ||
1368 | /* From this point forward we keep holding onto the tasklist lock | 1368 | /* From this point forward we keep holding onto the tasklist lock |
1369 | * so that our parent does not change from under us. -DaveM | 1369 | * so that our parent does not change from under us. -DaveM |
1370 | */ | 1370 | */ |
1371 | write_lock_irq(&tasklist_lock); | 1371 | write_lock_irq(&tasklist_lock); |
1372 | 1372 | ||
1373 | err = -ESRCH; | 1373 | err = -ESRCH; |
1374 | p = find_task_by_pid(pid); | 1374 | p = find_task_by_pid(pid); |
1375 | if (!p) | 1375 | if (!p) |
1376 | goto out; | 1376 | goto out; |
1377 | 1377 | ||
1378 | err = -EINVAL; | 1378 | err = -EINVAL; |
1379 | if (!thread_group_leader(p)) | 1379 | if (!thread_group_leader(p)) |
1380 | goto out; | 1380 | goto out; |
1381 | 1381 | ||
1382 | if (p->real_parent == group_leader) { | 1382 | if (p->real_parent == group_leader) { |
1383 | err = -EPERM; | 1383 | err = -EPERM; |
1384 | if (process_session(p) != process_session(group_leader)) | 1384 | if (process_session(p) != process_session(group_leader)) |
1385 | goto out; | 1385 | goto out; |
1386 | err = -EACCES; | 1386 | err = -EACCES; |
1387 | if (p->did_exec) | 1387 | if (p->did_exec) |
1388 | goto out; | 1388 | goto out; |
1389 | } else { | 1389 | } else { |
1390 | err = -ESRCH; | 1390 | err = -ESRCH; |
1391 | if (p != group_leader) | 1391 | if (p != group_leader) |
1392 | goto out; | 1392 | goto out; |
1393 | } | 1393 | } |
1394 | 1394 | ||
1395 | err = -EPERM; | 1395 | err = -EPERM; |
1396 | if (p->signal->leader) | 1396 | if (p->signal->leader) |
1397 | goto out; | 1397 | goto out; |
1398 | 1398 | ||
1399 | if (pgid != pid) { | 1399 | if (pgid != pid) { |
1400 | struct task_struct *p; | 1400 | struct task_struct *g = |
1401 | find_task_by_pid_type(PIDTYPE_PGID, pgid); | ||
1401 | 1402 | ||
1402 | do_each_task_pid(pgid, PIDTYPE_PGID, p) { | 1403 | if (!g || process_session(g) != process_session(group_leader)) |
1403 | if (process_session(p) == process_session(group_leader)) | 1404 | goto out; |
1404 | goto ok_pgid; | ||
1405 | } while_each_task_pid(pgid, PIDTYPE_PGID, p); | ||
1406 | goto out; | ||
1407 | } | 1405 | } |
1408 | 1406 | ||
1409 | ok_pgid: | ||
1410 | err = security_task_setpgid(p, pgid); | 1407 | err = security_task_setpgid(p, pgid); |
1411 | if (err) | 1408 | if (err) |
1412 | goto out; | 1409 | goto out; |
1413 | 1410 | ||
1414 | if (process_group(p) != pgid) { | 1411 | if (process_group(p) != pgid) { |
1415 | detach_pid(p, PIDTYPE_PGID); | 1412 | detach_pid(p, PIDTYPE_PGID); |
1416 | p->signal->pgrp = pgid; | 1413 | p->signal->pgrp = pgid; |
1417 | attach_pid(p, PIDTYPE_PGID, pgid); | 1414 | attach_pid(p, PIDTYPE_PGID, pgid); |
1418 | } | 1415 | } |
1419 | 1416 | ||
1420 | err = 0; | 1417 | err = 0; |
1421 | out: | 1418 | out: |
1422 | /* All paths lead to here, thus we are safe. -DaveM */ | 1419 | /* All paths lead to here, thus we are safe. -DaveM */ |
1423 | write_unlock_irq(&tasklist_lock); | 1420 | write_unlock_irq(&tasklist_lock); |
1424 | return err; | 1421 | return err; |
1425 | } | 1422 | } |
1426 | 1423 | ||
1427 | asmlinkage long sys_getpgid(pid_t pid) | 1424 | asmlinkage long sys_getpgid(pid_t pid) |
1428 | { | 1425 | { |
1429 | if (!pid) | 1426 | if (!pid) |
1430 | return process_group(current); | 1427 | return process_group(current); |
1431 | else { | 1428 | else { |
1432 | int retval; | 1429 | int retval; |
1433 | struct task_struct *p; | 1430 | struct task_struct *p; |
1434 | 1431 | ||
1435 | read_lock(&tasklist_lock); | 1432 | read_lock(&tasklist_lock); |
1436 | p = find_task_by_pid(pid); | 1433 | p = find_task_by_pid(pid); |
1437 | 1434 | ||
1438 | retval = -ESRCH; | 1435 | retval = -ESRCH; |
1439 | if (p) { | 1436 | if (p) { |
1440 | retval = security_task_getpgid(p); | 1437 | retval = security_task_getpgid(p); |
1441 | if (!retval) | 1438 | if (!retval) |
1442 | retval = process_group(p); | 1439 | retval = process_group(p); |
1443 | } | 1440 | } |
1444 | read_unlock(&tasklist_lock); | 1441 | read_unlock(&tasklist_lock); |
1445 | return retval; | 1442 | return retval; |
1446 | } | 1443 | } |
1447 | } | 1444 | } |
1448 | 1445 | ||
1449 | #ifdef __ARCH_WANT_SYS_GETPGRP | 1446 | #ifdef __ARCH_WANT_SYS_GETPGRP |
1450 | 1447 | ||
1451 | asmlinkage long sys_getpgrp(void) | 1448 | asmlinkage long sys_getpgrp(void) |
1452 | { | 1449 | { |
1453 | /* SMP - assuming writes are word atomic this is fine */ | 1450 | /* SMP - assuming writes are word atomic this is fine */ |
1454 | return process_group(current); | 1451 | return process_group(current); |
1455 | } | 1452 | } |
1456 | 1453 | ||
1457 | #endif | 1454 | #endif |
1458 | 1455 | ||
1459 | asmlinkage long sys_getsid(pid_t pid) | 1456 | asmlinkage long sys_getsid(pid_t pid) |
1460 | { | 1457 | { |
1461 | if (!pid) | 1458 | if (!pid) |
1462 | return process_session(current); | 1459 | return process_session(current); |
1463 | else { | 1460 | else { |
1464 | int retval; | 1461 | int retval; |
1465 | struct task_struct *p; | 1462 | struct task_struct *p; |
1466 | 1463 | ||
1467 | read_lock(&tasklist_lock); | 1464 | read_lock(&tasklist_lock); |
1468 | p = find_task_by_pid(pid); | 1465 | p = find_task_by_pid(pid); |
1469 | 1466 | ||
1470 | retval = -ESRCH; | 1467 | retval = -ESRCH; |
1471 | if (p) { | 1468 | if (p) { |
1472 | retval = security_task_getsid(p); | 1469 | retval = security_task_getsid(p); |
1473 | if (!retval) | 1470 | if (!retval) |
1474 | retval = process_session(p); | 1471 | retval = process_session(p); |
1475 | } | 1472 | } |
1476 | read_unlock(&tasklist_lock); | 1473 | read_unlock(&tasklist_lock); |
1477 | return retval; | 1474 | return retval; |
1478 | } | 1475 | } |
1479 | } | 1476 | } |
1480 | 1477 | ||
1481 | asmlinkage long sys_setsid(void) | 1478 | asmlinkage long sys_setsid(void) |
1482 | { | 1479 | { |
1483 | struct task_struct *group_leader = current->group_leader; | 1480 | struct task_struct *group_leader = current->group_leader; |
1484 | pid_t session; | 1481 | pid_t session; |
1485 | int err = -EPERM; | 1482 | int err = -EPERM; |
1486 | 1483 | ||
1487 | write_lock_irq(&tasklist_lock); | 1484 | write_lock_irq(&tasklist_lock); |
1488 | 1485 | ||
1489 | /* Fail if I am already a session leader */ | 1486 | /* Fail if I am already a session leader */ |
1490 | if (group_leader->signal->leader) | 1487 | if (group_leader->signal->leader) |
1491 | goto out; | 1488 | goto out; |
1492 | 1489 | ||
1493 | session = group_leader->pid; | 1490 | session = group_leader->pid; |
1494 | /* Fail if a process group id already exists that equals the | 1491 | /* Fail if a process group id already exists that equals the |
1495 | * proposed session id. | 1492 | * proposed session id. |
1496 | * | 1493 | * |
1497 | * Don't check if session id == 1 because kernel threads use this | 1494 | * Don't check if session id == 1 because kernel threads use this |
1498 | * session id and so the check will always fail and make it so | 1495 | * session id and so the check will always fail and make it so |
1499 | * init cannot successfully call setsid. | 1496 | * init cannot successfully call setsid. |
1500 | */ | 1497 | */ |
1501 | if (session > 1 && find_task_by_pid_type(PIDTYPE_PGID, session)) | 1498 | if (session > 1 && find_task_by_pid_type(PIDTYPE_PGID, session)) |
1502 | goto out; | 1499 | goto out; |
1503 | 1500 | ||
1504 | group_leader->signal->leader = 1; | 1501 | group_leader->signal->leader = 1; |
1505 | __set_special_pids(session, session); | 1502 | __set_special_pids(session, session); |
1506 | 1503 | ||
1507 | spin_lock(&group_leader->sighand->siglock); | 1504 | spin_lock(&group_leader->sighand->siglock); |
1508 | group_leader->signal->tty = NULL; | 1505 | group_leader->signal->tty = NULL; |
1509 | group_leader->signal->tty_old_pgrp = 0; | 1506 | group_leader->signal->tty_old_pgrp = 0; |
1510 | spin_unlock(&group_leader->sighand->siglock); | 1507 | spin_unlock(&group_leader->sighand->siglock); |
1511 | 1508 | ||
1512 | err = process_group(group_leader); | 1509 | err = process_group(group_leader); |
1513 | out: | 1510 | out: |
1514 | write_unlock_irq(&tasklist_lock); | 1511 | write_unlock_irq(&tasklist_lock); |
1515 | return err; | 1512 | return err; |
1516 | } | 1513 | } |
1517 | 1514 | ||
1518 | /* | 1515 | /* |
1519 | * Supplementary group IDs | 1516 | * Supplementary group IDs |
1520 | */ | 1517 | */ |
1521 | 1518 | ||
1522 | /* init to 2 - one for init_task, one to ensure it is never freed */ | 1519 | /* init to 2 - one for init_task, one to ensure it is never freed */ |
1523 | struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; | 1520 | struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; |
1524 | 1521 | ||
1525 | struct group_info *groups_alloc(int gidsetsize) | 1522 | struct group_info *groups_alloc(int gidsetsize) |
1526 | { | 1523 | { |
1527 | struct group_info *group_info; | 1524 | struct group_info *group_info; |
1528 | int nblocks; | 1525 | int nblocks; |
1529 | int i; | 1526 | int i; |
1530 | 1527 | ||
1531 | nblocks = (gidsetsize + NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; | 1528 | nblocks = (gidsetsize + NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; |
1532 | /* Make sure we always allocate at least one indirect block pointer */ | 1529 | /* Make sure we always allocate at least one indirect block pointer */ |
1533 | nblocks = nblocks ? : 1; | 1530 | nblocks = nblocks ? : 1; |
1534 | group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *), GFP_USER); | 1531 | group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *), GFP_USER); |
1535 | if (!group_info) | 1532 | if (!group_info) |
1536 | return NULL; | 1533 | return NULL; |
1537 | group_info->ngroups = gidsetsize; | 1534 | group_info->ngroups = gidsetsize; |
1538 | group_info->nblocks = nblocks; | 1535 | group_info->nblocks = nblocks; |
1539 | atomic_set(&group_info->usage, 1); | 1536 | atomic_set(&group_info->usage, 1); |
1540 | 1537 | ||
1541 | if (gidsetsize <= NGROUPS_SMALL) | 1538 | if (gidsetsize <= NGROUPS_SMALL) |
1542 | group_info->blocks[0] = group_info->small_block; | 1539 | group_info->blocks[0] = group_info->small_block; |
1543 | else { | 1540 | else { |
1544 | for (i = 0; i < nblocks; i++) { | 1541 | for (i = 0; i < nblocks; i++) { |
1545 | gid_t *b; | 1542 | gid_t *b; |
1546 | b = (void *)__get_free_page(GFP_USER); | 1543 | b = (void *)__get_free_page(GFP_USER); |
1547 | if (!b) | 1544 | if (!b) |
1548 | goto out_undo_partial_alloc; | 1545 | goto out_undo_partial_alloc; |
1549 | group_info->blocks[i] = b; | 1546 | group_info->blocks[i] = b; |
1550 | } | 1547 | } |
1551 | } | 1548 | } |
1552 | return group_info; | 1549 | return group_info; |
1553 | 1550 | ||
1554 | out_undo_partial_alloc: | 1551 | out_undo_partial_alloc: |
1555 | while (--i >= 0) { | 1552 | while (--i >= 0) { |
1556 | free_page((unsigned long)group_info->blocks[i]); | 1553 | free_page((unsigned long)group_info->blocks[i]); |
1557 | } | 1554 | } |
1558 | kfree(group_info); | 1555 | kfree(group_info); |
1559 | return NULL; | 1556 | return NULL; |
1560 | } | 1557 | } |
1561 | 1558 | ||
1562 | EXPORT_SYMBOL(groups_alloc); | 1559 | EXPORT_SYMBOL(groups_alloc); |
1563 | 1560 | ||
1564 | void groups_free(struct group_info *group_info) | 1561 | void groups_free(struct group_info *group_info) |
1565 | { | 1562 | { |
1566 | if (group_info->blocks[0] != group_info->small_block) { | 1563 | if (group_info->blocks[0] != group_info->small_block) { |
1567 | int i; | 1564 | int i; |
1568 | for (i = 0; i < group_info->nblocks; i++) | 1565 | for (i = 0; i < group_info->nblocks; i++) |
1569 | free_page((unsigned long)group_info->blocks[i]); | 1566 | free_page((unsigned long)group_info->blocks[i]); |
1570 | } | 1567 | } |
1571 | kfree(group_info); | 1568 | kfree(group_info); |
1572 | } | 1569 | } |
1573 | 1570 | ||
1574 | EXPORT_SYMBOL(groups_free); | 1571 | EXPORT_SYMBOL(groups_free); |
1575 | 1572 | ||
1576 | /* export the group_info to a user-space array */ | 1573 | /* export the group_info to a user-space array */ |
1577 | static int groups_to_user(gid_t __user *grouplist, | 1574 | static int groups_to_user(gid_t __user *grouplist, |
1578 | struct group_info *group_info) | 1575 | struct group_info *group_info) |
1579 | { | 1576 | { |
1580 | int i; | 1577 | int i; |
1581 | int count = group_info->ngroups; | 1578 | int count = group_info->ngroups; |
1582 | 1579 | ||
1583 | for (i = 0; i < group_info->nblocks; i++) { | 1580 | for (i = 0; i < group_info->nblocks; i++) { |
1584 | int cp_count = min(NGROUPS_PER_BLOCK, count); | 1581 | int cp_count = min(NGROUPS_PER_BLOCK, count); |
1585 | int off = i * NGROUPS_PER_BLOCK; | 1582 | int off = i * NGROUPS_PER_BLOCK; |
1586 | int len = cp_count * sizeof(*grouplist); | 1583 | int len = cp_count * sizeof(*grouplist); |
1587 | 1584 | ||
1588 | if (copy_to_user(grouplist+off, group_info->blocks[i], len)) | 1585 | if (copy_to_user(grouplist+off, group_info->blocks[i], len)) |
1589 | return -EFAULT; | 1586 | return -EFAULT; |
1590 | 1587 | ||
1591 | count -= cp_count; | 1588 | count -= cp_count; |
1592 | } | 1589 | } |
1593 | return 0; | 1590 | return 0; |
1594 | } | 1591 | } |
1595 | 1592 | ||
1596 | /* fill a group_info from a user-space array - it must be allocated already */ | 1593 | /* fill a group_info from a user-space array - it must be allocated already */ |
1597 | static int groups_from_user(struct group_info *group_info, | 1594 | static int groups_from_user(struct group_info *group_info, |
1598 | gid_t __user *grouplist) | 1595 | gid_t __user *grouplist) |
1599 | { | 1596 | { |
1600 | int i; | 1597 | int i; |
1601 | int count = group_info->ngroups; | 1598 | int count = group_info->ngroups; |
1602 | 1599 | ||
1603 | for (i = 0; i < group_info->nblocks; i++) { | 1600 | for (i = 0; i < group_info->nblocks; i++) { |
1604 | int cp_count = min(NGROUPS_PER_BLOCK, count); | 1601 | int cp_count = min(NGROUPS_PER_BLOCK, count); |
1605 | int off = i * NGROUPS_PER_BLOCK; | 1602 | int off = i * NGROUPS_PER_BLOCK; |
1606 | int len = cp_count * sizeof(*grouplist); | 1603 | int len = cp_count * sizeof(*grouplist); |
1607 | 1604 | ||
1608 | if (copy_from_user(group_info->blocks[i], grouplist+off, len)) | 1605 | if (copy_from_user(group_info->blocks[i], grouplist+off, len)) |
1609 | return -EFAULT; | 1606 | return -EFAULT; |
1610 | 1607 | ||
1611 | count -= cp_count; | 1608 | count -= cp_count; |
1612 | } | 1609 | } |
1613 | return 0; | 1610 | return 0; |
1614 | } | 1611 | } |
1615 | 1612 | ||
1616 | /* a simple Shell sort */ | 1613 | /* a simple Shell sort */ |
1617 | static void groups_sort(struct group_info *group_info) | 1614 | static void groups_sort(struct group_info *group_info) |
1618 | { | 1615 | { |
1619 | int base, max, stride; | 1616 | int base, max, stride; |
1620 | int gidsetsize = group_info->ngroups; | 1617 | int gidsetsize = group_info->ngroups; |
1621 | 1618 | ||
1622 | for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1) | 1619 | for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1) |
1623 | ; /* nothing */ | 1620 | ; /* nothing */ |
1624 | stride /= 3; | 1621 | stride /= 3; |
1625 | 1622 | ||
1626 | while (stride) { | 1623 | while (stride) { |
1627 | max = gidsetsize - stride; | 1624 | max = gidsetsize - stride; |
1628 | for (base = 0; base < max; base++) { | 1625 | for (base = 0; base < max; base++) { |
1629 | int left = base; | 1626 | int left = base; |
1630 | int right = left + stride; | 1627 | int right = left + stride; |
1631 | gid_t tmp = GROUP_AT(group_info, right); | 1628 | gid_t tmp = GROUP_AT(group_info, right); |
1632 | 1629 | ||
1633 | while (left >= 0 && GROUP_AT(group_info, left) > tmp) { | 1630 | while (left >= 0 && GROUP_AT(group_info, left) > tmp) { |
1634 | GROUP_AT(group_info, right) = | 1631 | GROUP_AT(group_info, right) = |
1635 | GROUP_AT(group_info, left); | 1632 | GROUP_AT(group_info, left); |
1636 | right = left; | 1633 | right = left; |
1637 | left -= stride; | 1634 | left -= stride; |
1638 | } | 1635 | } |
1639 | GROUP_AT(group_info, right) = tmp; | 1636 | GROUP_AT(group_info, right) = tmp; |
1640 | } | 1637 | } |
1641 | stride /= 3; | 1638 | stride /= 3; |
1642 | } | 1639 | } |
1643 | } | 1640 | } |
1644 | 1641 | ||
1645 | /* a simple bsearch */ | 1642 | /* a simple bsearch */ |
1646 | int groups_search(struct group_info *group_info, gid_t grp) | 1643 | int groups_search(struct group_info *group_info, gid_t grp) |
1647 | { | 1644 | { |
1648 | unsigned int left, right; | 1645 | unsigned int left, right; |
1649 | 1646 | ||
1650 | if (!group_info) | 1647 | if (!group_info) |
1651 | return 0; | 1648 | return 0; |
1652 | 1649 | ||
1653 | left = 0; | 1650 | left = 0; |
1654 | right = group_info->ngroups; | 1651 | right = group_info->ngroups; |
1655 | while (left < right) { | 1652 | while (left < right) { |
1656 | unsigned int mid = (left+right)/2; | 1653 | unsigned int mid = (left+right)/2; |
1657 | int cmp = grp - GROUP_AT(group_info, mid); | 1654 | int cmp = grp - GROUP_AT(group_info, mid); |
1658 | if (cmp > 0) | 1655 | if (cmp > 0) |
1659 | left = mid + 1; | 1656 | left = mid + 1; |
1660 | else if (cmp < 0) | 1657 | else if (cmp < 0) |
1661 | right = mid; | 1658 | right = mid; |
1662 | else | 1659 | else |
1663 | return 1; | 1660 | return 1; |
1664 | } | 1661 | } |
1665 | return 0; | 1662 | return 0; |
1666 | } | 1663 | } |
1667 | 1664 | ||
1668 | /* validate and set current->group_info */ | 1665 | /* validate and set current->group_info */ |
1669 | int set_current_groups(struct group_info *group_info) | 1666 | int set_current_groups(struct group_info *group_info) |
1670 | { | 1667 | { |
1671 | int retval; | 1668 | int retval; |
1672 | struct group_info *old_info; | 1669 | struct group_info *old_info; |
1673 | 1670 | ||
1674 | retval = security_task_setgroups(group_info); | 1671 | retval = security_task_setgroups(group_info); |
1675 | if (retval) | 1672 | if (retval) |
1676 | return retval; | 1673 | return retval; |
1677 | 1674 | ||
1678 | groups_sort(group_info); | 1675 | groups_sort(group_info); |
1679 | get_group_info(group_info); | 1676 | get_group_info(group_info); |
1680 | 1677 | ||
1681 | task_lock(current); | 1678 | task_lock(current); |
1682 | old_info = current->group_info; | 1679 | old_info = current->group_info; |
1683 | current->group_info = group_info; | 1680 | current->group_info = group_info; |
1684 | task_unlock(current); | 1681 | task_unlock(current); |
1685 | 1682 | ||
1686 | put_group_info(old_info); | 1683 | put_group_info(old_info); |
1687 | 1684 | ||
1688 | return 0; | 1685 | return 0; |
1689 | } | 1686 | } |
1690 | 1687 | ||
1691 | EXPORT_SYMBOL(set_current_groups); | 1688 | EXPORT_SYMBOL(set_current_groups); |
1692 | 1689 | ||
1693 | asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist) | 1690 | asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist) |
1694 | { | 1691 | { |
1695 | int i = 0; | 1692 | int i = 0; |
1696 | 1693 | ||
1697 | /* | 1694 | /* |
1698 | * SMP: Nobody else can change our grouplist. Thus we are | 1695 | * SMP: Nobody else can change our grouplist. Thus we are |
1699 | * safe. | 1696 | * safe. |
1700 | */ | 1697 | */ |
1701 | 1698 | ||
1702 | if (gidsetsize < 0) | 1699 | if (gidsetsize < 0) |
1703 | return -EINVAL; | 1700 | return -EINVAL; |
1704 | 1701 | ||
1705 | /* no need to grab task_lock here; it cannot change */ | 1702 | /* no need to grab task_lock here; it cannot change */ |
1706 | i = current->group_info->ngroups; | 1703 | i = current->group_info->ngroups; |
1707 | if (gidsetsize) { | 1704 | if (gidsetsize) { |
1708 | if (i > gidsetsize) { | 1705 | if (i > gidsetsize) { |
1709 | i = -EINVAL; | 1706 | i = -EINVAL; |
1710 | goto out; | 1707 | goto out; |
1711 | } | 1708 | } |
1712 | if (groups_to_user(grouplist, current->group_info)) { | 1709 | if (groups_to_user(grouplist, current->group_info)) { |
1713 | i = -EFAULT; | 1710 | i = -EFAULT; |
1714 | goto out; | 1711 | goto out; |
1715 | } | 1712 | } |
1716 | } | 1713 | } |
1717 | out: | 1714 | out: |
1718 | return i; | 1715 | return i; |
1719 | } | 1716 | } |
1720 | 1717 | ||
1721 | /* | 1718 | /* |
1722 | * SMP: Our groups are copy-on-write. We can set them safely | 1719 | * SMP: Our groups are copy-on-write. We can set them safely |
1723 | * without another task interfering. | 1720 | * without another task interfering. |
1724 | */ | 1721 | */ |
1725 | 1722 | ||
1726 | asmlinkage long sys_setgroups(int gidsetsize, gid_t __user *grouplist) | 1723 | asmlinkage long sys_setgroups(int gidsetsize, gid_t __user *grouplist) |
1727 | { | 1724 | { |
1728 | struct group_info *group_info; | 1725 | struct group_info *group_info; |
1729 | int retval; | 1726 | int retval; |
1730 | 1727 | ||
1731 | if (!capable(CAP_SETGID)) | 1728 | if (!capable(CAP_SETGID)) |
1732 | return -EPERM; | 1729 | return -EPERM; |
1733 | if ((unsigned)gidsetsize > NGROUPS_MAX) | 1730 | if ((unsigned)gidsetsize > NGROUPS_MAX) |
1734 | return -EINVAL; | 1731 | return -EINVAL; |
1735 | 1732 | ||
1736 | group_info = groups_alloc(gidsetsize); | 1733 | group_info = groups_alloc(gidsetsize); |
1737 | if (!group_info) | 1734 | if (!group_info) |
1738 | return -ENOMEM; | 1735 | return -ENOMEM; |
1739 | retval = groups_from_user(group_info, grouplist); | 1736 | retval = groups_from_user(group_info, grouplist); |
1740 | if (retval) { | 1737 | if (retval) { |
1741 | put_group_info(group_info); | 1738 | put_group_info(group_info); |
1742 | return retval; | 1739 | return retval; |
1743 | } | 1740 | } |
1744 | 1741 | ||
1745 | retval = set_current_groups(group_info); | 1742 | retval = set_current_groups(group_info); |
1746 | put_group_info(group_info); | 1743 | put_group_info(group_info); |
1747 | 1744 | ||
1748 | return retval; | 1745 | return retval; |
1749 | } | 1746 | } |
1750 | 1747 | ||
1751 | /* | 1748 | /* |
1752 | * Check whether we're fsgid/egid or in the supplemental group.. | 1749 | * Check whether we're fsgid/egid or in the supplemental group.. |
1753 | */ | 1750 | */ |
1754 | int in_group_p(gid_t grp) | 1751 | int in_group_p(gid_t grp) |
1755 | { | 1752 | { |
1756 | int retval = 1; | 1753 | int retval = 1; |
1757 | if (grp != current->fsgid) | 1754 | if (grp != current->fsgid) |
1758 | retval = groups_search(current->group_info, grp); | 1755 | retval = groups_search(current->group_info, grp); |
1759 | return retval; | 1756 | return retval; |
1760 | } | 1757 | } |
1761 | 1758 | ||
1762 | EXPORT_SYMBOL(in_group_p); | 1759 | EXPORT_SYMBOL(in_group_p); |
1763 | 1760 | ||
1764 | int in_egroup_p(gid_t grp) | 1761 | int in_egroup_p(gid_t grp) |
1765 | { | 1762 | { |
1766 | int retval = 1; | 1763 | int retval = 1; |
1767 | if (grp != current->egid) | 1764 | if (grp != current->egid) |
1768 | retval = groups_search(current->group_info, grp); | 1765 | retval = groups_search(current->group_info, grp); |
1769 | return retval; | 1766 | return retval; |
1770 | } | 1767 | } |
1771 | 1768 | ||
1772 | EXPORT_SYMBOL(in_egroup_p); | 1769 | EXPORT_SYMBOL(in_egroup_p); |
1773 | 1770 | ||
1774 | DECLARE_RWSEM(uts_sem); | 1771 | DECLARE_RWSEM(uts_sem); |
1775 | 1772 | ||
1776 | EXPORT_SYMBOL(uts_sem); | 1773 | EXPORT_SYMBOL(uts_sem); |
1777 | 1774 | ||
1778 | asmlinkage long sys_newuname(struct new_utsname __user * name) | 1775 | asmlinkage long sys_newuname(struct new_utsname __user * name) |
1779 | { | 1776 | { |
1780 | int errno = 0; | 1777 | int errno = 0; |
1781 | 1778 | ||
1782 | down_read(&uts_sem); | 1779 | down_read(&uts_sem); |
1783 | if (copy_to_user(name, utsname(), sizeof *name)) | 1780 | if (copy_to_user(name, utsname(), sizeof *name)) |
1784 | errno = -EFAULT; | 1781 | errno = -EFAULT; |
1785 | up_read(&uts_sem); | 1782 | up_read(&uts_sem); |
1786 | return errno; | 1783 | return errno; |
1787 | } | 1784 | } |
1788 | 1785 | ||
1789 | asmlinkage long sys_sethostname(char __user *name, int len) | 1786 | asmlinkage long sys_sethostname(char __user *name, int len) |
1790 | { | 1787 | { |
1791 | int errno; | 1788 | int errno; |
1792 | char tmp[__NEW_UTS_LEN]; | 1789 | char tmp[__NEW_UTS_LEN]; |
1793 | 1790 | ||
1794 | if (!capable(CAP_SYS_ADMIN)) | 1791 | if (!capable(CAP_SYS_ADMIN)) |
1795 | return -EPERM; | 1792 | return -EPERM; |
1796 | if (len < 0 || len > __NEW_UTS_LEN) | 1793 | if (len < 0 || len > __NEW_UTS_LEN) |
1797 | return -EINVAL; | 1794 | return -EINVAL; |
1798 | down_write(&uts_sem); | 1795 | down_write(&uts_sem); |
1799 | errno = -EFAULT; | 1796 | errno = -EFAULT; |
1800 | if (!copy_from_user(tmp, name, len)) { | 1797 | if (!copy_from_user(tmp, name, len)) { |
1801 | memcpy(utsname()->nodename, tmp, len); | 1798 | memcpy(utsname()->nodename, tmp, len); |
1802 | utsname()->nodename[len] = 0; | 1799 | utsname()->nodename[len] = 0; |
1803 | errno = 0; | 1800 | errno = 0; |
1804 | } | 1801 | } |
1805 | up_write(&uts_sem); | 1802 | up_write(&uts_sem); |
1806 | return errno; | 1803 | return errno; |
1807 | } | 1804 | } |
1808 | 1805 | ||
1809 | #ifdef __ARCH_WANT_SYS_GETHOSTNAME | 1806 | #ifdef __ARCH_WANT_SYS_GETHOSTNAME |
1810 | 1807 | ||
1811 | asmlinkage long sys_gethostname(char __user *name, int len) | 1808 | asmlinkage long sys_gethostname(char __user *name, int len) |
1812 | { | 1809 | { |
1813 | int i, errno; | 1810 | int i, errno; |
1814 | 1811 | ||
1815 | if (len < 0) | 1812 | if (len < 0) |
1816 | return -EINVAL; | 1813 | return -EINVAL; |
1817 | down_read(&uts_sem); | 1814 | down_read(&uts_sem); |
1818 | i = 1 + strlen(utsname()->nodename); | 1815 | i = 1 + strlen(utsname()->nodename); |
1819 | if (i > len) | 1816 | if (i > len) |
1820 | i = len; | 1817 | i = len; |
1821 | errno = 0; | 1818 | errno = 0; |
1822 | if (copy_to_user(name, utsname()->nodename, i)) | 1819 | if (copy_to_user(name, utsname()->nodename, i)) |
1823 | errno = -EFAULT; | 1820 | errno = -EFAULT; |
1824 | up_read(&uts_sem); | 1821 | up_read(&uts_sem); |
1825 | return errno; | 1822 | return errno; |
1826 | } | 1823 | } |
1827 | 1824 | ||
1828 | #endif | 1825 | #endif |
1829 | 1826 | ||
1830 | /* | 1827 | /* |
1831 | * Only setdomainname; getdomainname can be implemented by calling | 1828 | * Only setdomainname; getdomainname can be implemented by calling |
1832 | * uname() | 1829 | * uname() |
1833 | */ | 1830 | */ |
1834 | asmlinkage long sys_setdomainname(char __user *name, int len) | 1831 | asmlinkage long sys_setdomainname(char __user *name, int len) |
1835 | { | 1832 | { |
1836 | int errno; | 1833 | int errno; |
1837 | char tmp[__NEW_UTS_LEN]; | 1834 | char tmp[__NEW_UTS_LEN]; |
1838 | 1835 | ||
1839 | if (!capable(CAP_SYS_ADMIN)) | 1836 | if (!capable(CAP_SYS_ADMIN)) |
1840 | return -EPERM; | 1837 | return -EPERM; |
1841 | if (len < 0 || len > __NEW_UTS_LEN) | 1838 | if (len < 0 || len > __NEW_UTS_LEN) |
1842 | return -EINVAL; | 1839 | return -EINVAL; |
1843 | 1840 | ||
1844 | down_write(&uts_sem); | 1841 | down_write(&uts_sem); |
1845 | errno = -EFAULT; | 1842 | errno = -EFAULT; |
1846 | if (!copy_from_user(tmp, name, len)) { | 1843 | if (!copy_from_user(tmp, name, len)) { |
1847 | memcpy(utsname()->domainname, tmp, len); | 1844 | memcpy(utsname()->domainname, tmp, len); |
1848 | utsname()->domainname[len] = 0; | 1845 | utsname()->domainname[len] = 0; |
1849 | errno = 0; | 1846 | errno = 0; |
1850 | } | 1847 | } |
1851 | up_write(&uts_sem); | 1848 | up_write(&uts_sem); |
1852 | return errno; | 1849 | return errno; |
1853 | } | 1850 | } |
1854 | 1851 | ||
1855 | asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit __user *rlim) | 1852 | asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit __user *rlim) |
1856 | { | 1853 | { |
1857 | if (resource >= RLIM_NLIMITS) | 1854 | if (resource >= RLIM_NLIMITS) |
1858 | return -EINVAL; | 1855 | return -EINVAL; |
1859 | else { | 1856 | else { |
1860 | struct rlimit value; | 1857 | struct rlimit value; |
1861 | task_lock(current->group_leader); | 1858 | task_lock(current->group_leader); |
1862 | value = current->signal->rlim[resource]; | 1859 | value = current->signal->rlim[resource]; |
1863 | task_unlock(current->group_leader); | 1860 | task_unlock(current->group_leader); |
1864 | return copy_to_user(rlim, &value, sizeof(*rlim)) ? -EFAULT : 0; | 1861 | return copy_to_user(rlim, &value, sizeof(*rlim)) ? -EFAULT : 0; |
1865 | } | 1862 | } |
1866 | } | 1863 | } |
1867 | 1864 | ||
1868 | #ifdef __ARCH_WANT_SYS_OLD_GETRLIMIT | 1865 | #ifdef __ARCH_WANT_SYS_OLD_GETRLIMIT |
1869 | 1866 | ||
1870 | /* | 1867 | /* |
1871 | * Back compatibility for getrlimit. Needed for some apps. | 1868 | * Back compatibility for getrlimit. Needed for some apps. |
1872 | */ | 1869 | */ |
1873 | 1870 | ||
1874 | asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit __user *rlim) | 1871 | asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit __user *rlim) |
1875 | { | 1872 | { |
1876 | struct rlimit x; | 1873 | struct rlimit x; |
1877 | if (resource >= RLIM_NLIMITS) | 1874 | if (resource >= RLIM_NLIMITS) |
1878 | return -EINVAL; | 1875 | return -EINVAL; |
1879 | 1876 | ||
1880 | task_lock(current->group_leader); | 1877 | task_lock(current->group_leader); |
1881 | x = current->signal->rlim[resource]; | 1878 | x = current->signal->rlim[resource]; |
1882 | task_unlock(current->group_leader); | 1879 | task_unlock(current->group_leader); |
1883 | if (x.rlim_cur > 0x7FFFFFFF) | 1880 | if (x.rlim_cur > 0x7FFFFFFF) |
1884 | x.rlim_cur = 0x7FFFFFFF; | 1881 | x.rlim_cur = 0x7FFFFFFF; |
1885 | if (x.rlim_max > 0x7FFFFFFF) | 1882 | if (x.rlim_max > 0x7FFFFFFF) |
1886 | x.rlim_max = 0x7FFFFFFF; | 1883 | x.rlim_max = 0x7FFFFFFF; |
1887 | return copy_to_user(rlim, &x, sizeof(x))?-EFAULT:0; | 1884 | return copy_to_user(rlim, &x, sizeof(x))?-EFAULT:0; |
1888 | } | 1885 | } |
1889 | 1886 | ||
1890 | #endif | 1887 | #endif |
1891 | 1888 | ||
1892 | asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim) | 1889 | asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim) |
1893 | { | 1890 | { |
1894 | struct rlimit new_rlim, *old_rlim; | 1891 | struct rlimit new_rlim, *old_rlim; |
1895 | unsigned long it_prof_secs; | 1892 | unsigned long it_prof_secs; |
1896 | int retval; | 1893 | int retval; |
1897 | 1894 | ||
1898 | if (resource >= RLIM_NLIMITS) | 1895 | if (resource >= RLIM_NLIMITS) |
1899 | return -EINVAL; | 1896 | return -EINVAL; |
1900 | if (copy_from_user(&new_rlim, rlim, sizeof(*rlim))) | 1897 | if (copy_from_user(&new_rlim, rlim, sizeof(*rlim))) |
1901 | return -EFAULT; | 1898 | return -EFAULT; |
1902 | if (new_rlim.rlim_cur > new_rlim.rlim_max) | 1899 | if (new_rlim.rlim_cur > new_rlim.rlim_max) |
1903 | return -EINVAL; | 1900 | return -EINVAL; |
1904 | old_rlim = current->signal->rlim + resource; | 1901 | old_rlim = current->signal->rlim + resource; |
1905 | if ((new_rlim.rlim_max > old_rlim->rlim_max) && | 1902 | if ((new_rlim.rlim_max > old_rlim->rlim_max) && |
1906 | !capable(CAP_SYS_RESOURCE)) | 1903 | !capable(CAP_SYS_RESOURCE)) |
1907 | return -EPERM; | 1904 | return -EPERM; |
1908 | if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > NR_OPEN) | 1905 | if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > NR_OPEN) |
1909 | return -EPERM; | 1906 | return -EPERM; |
1910 | 1907 | ||
1911 | retval = security_task_setrlimit(resource, &new_rlim); | 1908 | retval = security_task_setrlimit(resource, &new_rlim); |
1912 | if (retval) | 1909 | if (retval) |
1913 | return retval; | 1910 | return retval; |
1914 | 1911 | ||
1915 | task_lock(current->group_leader); | 1912 | task_lock(current->group_leader); |
1916 | *old_rlim = new_rlim; | 1913 | *old_rlim = new_rlim; |
1917 | task_unlock(current->group_leader); | 1914 | task_unlock(current->group_leader); |
1918 | 1915 | ||
1919 | if (resource != RLIMIT_CPU) | 1916 | if (resource != RLIMIT_CPU) |
1920 | goto out; | 1917 | goto out; |
1921 | 1918 | ||
1922 | /* | 1919 | /* |
1923 | * RLIMIT_CPU handling. Note that the kernel fails to return an error | 1920 | * RLIMIT_CPU handling. Note that the kernel fails to return an error |
1924 | * code if it rejected the user's attempt to set RLIMIT_CPU. This is a | 1921 | * code if it rejected the user's attempt to set RLIMIT_CPU. This is a |
1925 | * very long-standing error, and fixing it now risks breakage of | 1922 | * very long-standing error, and fixing it now risks breakage of |
1926 | * applications, so we live with it | 1923 | * applications, so we live with it |
1927 | */ | 1924 | */ |
1928 | if (new_rlim.rlim_cur == RLIM_INFINITY) | 1925 | if (new_rlim.rlim_cur == RLIM_INFINITY) |
1929 | goto out; | 1926 | goto out; |
1930 | 1927 | ||
1931 | it_prof_secs = cputime_to_secs(current->signal->it_prof_expires); | 1928 | it_prof_secs = cputime_to_secs(current->signal->it_prof_expires); |
1932 | if (it_prof_secs == 0 || new_rlim.rlim_cur <= it_prof_secs) { | 1929 | if (it_prof_secs == 0 || new_rlim.rlim_cur <= it_prof_secs) { |
1933 | unsigned long rlim_cur = new_rlim.rlim_cur; | 1930 | unsigned long rlim_cur = new_rlim.rlim_cur; |
1934 | cputime_t cputime; | 1931 | cputime_t cputime; |
1935 | 1932 | ||
1936 | if (rlim_cur == 0) { | 1933 | if (rlim_cur == 0) { |
1937 | /* | 1934 | /* |
1938 | * The caller is asking for an immediate RLIMIT_CPU | 1935 | * The caller is asking for an immediate RLIMIT_CPU |
1939 | * expiry. But we use the zero value to mean "it was | 1936 | * expiry. But we use the zero value to mean "it was |
1940 | * never set". So let's cheat and make it one second | 1937 | * never set". So let's cheat and make it one second |
1941 | * instead | 1938 | * instead |
1942 | */ | 1939 | */ |
1943 | rlim_cur = 1; | 1940 | rlim_cur = 1; |
1944 | } | 1941 | } |
1945 | cputime = secs_to_cputime(rlim_cur); | 1942 | cputime = secs_to_cputime(rlim_cur); |
1946 | read_lock(&tasklist_lock); | 1943 | read_lock(&tasklist_lock); |
1947 | spin_lock_irq(¤t->sighand->siglock); | 1944 | spin_lock_irq(¤t->sighand->siglock); |
1948 | set_process_cpu_timer(current, CPUCLOCK_PROF, &cputime, NULL); | 1945 | set_process_cpu_timer(current, CPUCLOCK_PROF, &cputime, NULL); |
1949 | spin_unlock_irq(¤t->sighand->siglock); | 1946 | spin_unlock_irq(¤t->sighand->siglock); |
1950 | read_unlock(&tasklist_lock); | 1947 | read_unlock(&tasklist_lock); |
1951 | } | 1948 | } |
1952 | out: | 1949 | out: |
1953 | return 0; | 1950 | return 0; |
1954 | } | 1951 | } |
1955 | 1952 | ||
1956 | /* | 1953 | /* |
1957 | * It would make sense to put struct rusage in the task_struct, | 1954 | * It would make sense to put struct rusage in the task_struct, |
1958 | * except that would make the task_struct be *really big*. After | 1955 | * except that would make the task_struct be *really big*. After |
1959 | * task_struct gets moved into malloc'ed memory, it would | 1956 | * task_struct gets moved into malloc'ed memory, it would |
1960 | * make sense to do this. It will make moving the rest of the information | 1957 | * make sense to do this. It will make moving the rest of the information |
1961 | * a lot simpler! (Which we're not doing right now because we're not | 1958 | * a lot simpler! (Which we're not doing right now because we're not |
1962 | * measuring them yet). | 1959 | * measuring them yet). |
1963 | * | 1960 | * |
1964 | * When sampling multiple threads for RUSAGE_SELF, under SMP we might have | 1961 | * When sampling multiple threads for RUSAGE_SELF, under SMP we might have |
1965 | * races with threads incrementing their own counters. But since word | 1962 | * races with threads incrementing their own counters. But since word |
1966 | * reads are atomic, we either get new values or old values and we don't | 1963 | * reads are atomic, we either get new values or old values and we don't |
1967 | * care which for the sums. We always take the siglock to protect reading | 1964 | * care which for the sums. We always take the siglock to protect reading |
1968 | * the c* fields from p->signal from races with exit.c updating those | 1965 | * the c* fields from p->signal from races with exit.c updating those |
1969 | * fields when reaping, so a sample either gets all the additions of a | 1966 | * fields when reaping, so a sample either gets all the additions of a |
1970 | * given child after it's reaped, or none so this sample is before reaping. | 1967 | * given child after it's reaped, or none so this sample is before reaping. |
1971 | * | 1968 | * |
1972 | * Locking: | 1969 | * Locking: |
1973 | * We need to take the siglock for CHILDEREN, SELF and BOTH | 1970 | * We need to take the siglock for CHILDEREN, SELF and BOTH |
1974 | * for the cases current multithreaded, non-current single threaded | 1971 | * for the cases current multithreaded, non-current single threaded |
1975 | * non-current multithreaded. Thread traversal is now safe with | 1972 | * non-current multithreaded. Thread traversal is now safe with |
1976 | * the siglock held. | 1973 | * the siglock held. |
1977 | * Strictly speaking, we donot need to take the siglock if we are current and | 1974 | * Strictly speaking, we donot need to take the siglock if we are current and |
1978 | * single threaded, as no one else can take our signal_struct away, no one | 1975 | * single threaded, as no one else can take our signal_struct away, no one |
1979 | * else can reap the children to update signal->c* counters, and no one else | 1976 | * else can reap the children to update signal->c* counters, and no one else |
1980 | * can race with the signal-> fields. If we do not take any lock, the | 1977 | * can race with the signal-> fields. If we do not take any lock, the |
1981 | * signal-> fields could be read out of order while another thread was just | 1978 | * signal-> fields could be read out of order while another thread was just |
1982 | * exiting. So we should place a read memory barrier when we avoid the lock. | 1979 | * exiting. So we should place a read memory barrier when we avoid the lock. |
1983 | * On the writer side, write memory barrier is implied in __exit_signal | 1980 | * On the writer side, write memory barrier is implied in __exit_signal |
1984 | * as __exit_signal releases the siglock spinlock after updating the signal-> | 1981 | * as __exit_signal releases the siglock spinlock after updating the signal-> |
1985 | * fields. But we don't do this yet to keep things simple. | 1982 | * fields. But we don't do this yet to keep things simple. |
1986 | * | 1983 | * |
1987 | */ | 1984 | */ |
1988 | 1985 | ||
1989 | static void k_getrusage(struct task_struct *p, int who, struct rusage *r) | 1986 | static void k_getrusage(struct task_struct *p, int who, struct rusage *r) |
1990 | { | 1987 | { |
1991 | struct task_struct *t; | 1988 | struct task_struct *t; |
1992 | unsigned long flags; | 1989 | unsigned long flags; |
1993 | cputime_t utime, stime; | 1990 | cputime_t utime, stime; |
1994 | 1991 | ||
1995 | memset((char *) r, 0, sizeof *r); | 1992 | memset((char *) r, 0, sizeof *r); |
1996 | utime = stime = cputime_zero; | 1993 | utime = stime = cputime_zero; |
1997 | 1994 | ||
1998 | rcu_read_lock(); | 1995 | rcu_read_lock(); |
1999 | if (!lock_task_sighand(p, &flags)) { | 1996 | if (!lock_task_sighand(p, &flags)) { |
2000 | rcu_read_unlock(); | 1997 | rcu_read_unlock(); |
2001 | return; | 1998 | return; |
2002 | } | 1999 | } |
2003 | 2000 | ||
2004 | switch (who) { | 2001 | switch (who) { |
2005 | case RUSAGE_BOTH: | 2002 | case RUSAGE_BOTH: |
2006 | case RUSAGE_CHILDREN: | 2003 | case RUSAGE_CHILDREN: |
2007 | utime = p->signal->cutime; | 2004 | utime = p->signal->cutime; |
2008 | stime = p->signal->cstime; | 2005 | stime = p->signal->cstime; |
2009 | r->ru_nvcsw = p->signal->cnvcsw; | 2006 | r->ru_nvcsw = p->signal->cnvcsw; |
2010 | r->ru_nivcsw = p->signal->cnivcsw; | 2007 | r->ru_nivcsw = p->signal->cnivcsw; |
2011 | r->ru_minflt = p->signal->cmin_flt; | 2008 | r->ru_minflt = p->signal->cmin_flt; |
2012 | r->ru_majflt = p->signal->cmaj_flt; | 2009 | r->ru_majflt = p->signal->cmaj_flt; |
2013 | 2010 | ||
2014 | if (who == RUSAGE_CHILDREN) | 2011 | if (who == RUSAGE_CHILDREN) |
2015 | break; | 2012 | break; |
2016 | 2013 | ||
2017 | case RUSAGE_SELF: | 2014 | case RUSAGE_SELF: |
2018 | utime = cputime_add(utime, p->signal->utime); | 2015 | utime = cputime_add(utime, p->signal->utime); |
2019 | stime = cputime_add(stime, p->signal->stime); | 2016 | stime = cputime_add(stime, p->signal->stime); |
2020 | r->ru_nvcsw += p->signal->nvcsw; | 2017 | r->ru_nvcsw += p->signal->nvcsw; |
2021 | r->ru_nivcsw += p->signal->nivcsw; | 2018 | r->ru_nivcsw += p->signal->nivcsw; |
2022 | r->ru_minflt += p->signal->min_flt; | 2019 | r->ru_minflt += p->signal->min_flt; |
2023 | r->ru_majflt += p->signal->maj_flt; | 2020 | r->ru_majflt += p->signal->maj_flt; |
2024 | t = p; | 2021 | t = p; |
2025 | do { | 2022 | do { |
2026 | utime = cputime_add(utime, t->utime); | 2023 | utime = cputime_add(utime, t->utime); |
2027 | stime = cputime_add(stime, t->stime); | 2024 | stime = cputime_add(stime, t->stime); |
2028 | r->ru_nvcsw += t->nvcsw; | 2025 | r->ru_nvcsw += t->nvcsw; |
2029 | r->ru_nivcsw += t->nivcsw; | 2026 | r->ru_nivcsw += t->nivcsw; |
2030 | r->ru_minflt += t->min_flt; | 2027 | r->ru_minflt += t->min_flt; |
2031 | r->ru_majflt += t->maj_flt; | 2028 | r->ru_majflt += t->maj_flt; |
2032 | t = next_thread(t); | 2029 | t = next_thread(t); |
2033 | } while (t != p); | 2030 | } while (t != p); |
2034 | break; | 2031 | break; |
2035 | 2032 | ||
2036 | default: | 2033 | default: |
2037 | BUG(); | 2034 | BUG(); |
2038 | } | 2035 | } |
2039 | 2036 | ||
2040 | unlock_task_sighand(p, &flags); | 2037 | unlock_task_sighand(p, &flags); |
2041 | rcu_read_unlock(); | 2038 | rcu_read_unlock(); |
2042 | 2039 | ||
2043 | cputime_to_timeval(utime, &r->ru_utime); | 2040 | cputime_to_timeval(utime, &r->ru_utime); |
2044 | cputime_to_timeval(stime, &r->ru_stime); | 2041 | cputime_to_timeval(stime, &r->ru_stime); |
2045 | } | 2042 | } |
2046 | 2043 | ||
2047 | int getrusage(struct task_struct *p, int who, struct rusage __user *ru) | 2044 | int getrusage(struct task_struct *p, int who, struct rusage __user *ru) |
2048 | { | 2045 | { |
2049 | struct rusage r; | 2046 | struct rusage r; |
2050 | k_getrusage(p, who, &r); | 2047 | k_getrusage(p, who, &r); |
2051 | return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0; | 2048 | return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0; |
2052 | } | 2049 | } |
2053 | 2050 | ||
2054 | asmlinkage long sys_getrusage(int who, struct rusage __user *ru) | 2051 | asmlinkage long sys_getrusage(int who, struct rusage __user *ru) |
2055 | { | 2052 | { |
2056 | if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN) | 2053 | if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN) |
2057 | return -EINVAL; | 2054 | return -EINVAL; |
2058 | return getrusage(current, who, ru); | 2055 | return getrusage(current, who, ru); |
2059 | } | 2056 | } |
2060 | 2057 | ||
2061 | asmlinkage long sys_umask(int mask) | 2058 | asmlinkage long sys_umask(int mask) |
2062 | { | 2059 | { |
2063 | mask = xchg(¤t->fs->umask, mask & S_IRWXUGO); | 2060 | mask = xchg(¤t->fs->umask, mask & S_IRWXUGO); |
2064 | return mask; | 2061 | return mask; |
2065 | } | 2062 | } |
2066 | 2063 | ||
2067 | asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, | 2064 | asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, |
2068 | unsigned long arg4, unsigned long arg5) | 2065 | unsigned long arg4, unsigned long arg5) |
2069 | { | 2066 | { |
2070 | long error; | 2067 | long error; |
2071 | 2068 | ||
2072 | error = security_task_prctl(option, arg2, arg3, arg4, arg5); | 2069 | error = security_task_prctl(option, arg2, arg3, arg4, arg5); |
2073 | if (error) | 2070 | if (error) |
2074 | return error; | 2071 | return error; |
2075 | 2072 | ||
2076 | switch (option) { | 2073 | switch (option) { |
2077 | case PR_SET_PDEATHSIG: | 2074 | case PR_SET_PDEATHSIG: |
2078 | if (!valid_signal(arg2)) { | 2075 | if (!valid_signal(arg2)) { |
2079 | error = -EINVAL; | 2076 | error = -EINVAL; |
2080 | break; | 2077 | break; |
2081 | } | 2078 | } |
2082 | current->pdeath_signal = arg2; | 2079 | current->pdeath_signal = arg2; |
2083 | break; | 2080 | break; |
2084 | case PR_GET_PDEATHSIG: | 2081 | case PR_GET_PDEATHSIG: |
2085 | error = put_user(current->pdeath_signal, (int __user *)arg2); | 2082 | error = put_user(current->pdeath_signal, (int __user *)arg2); |
2086 | break; | 2083 | break; |
2087 | case PR_GET_DUMPABLE: | 2084 | case PR_GET_DUMPABLE: |
2088 | error = current->mm->dumpable; | 2085 | error = current->mm->dumpable; |
2089 | break; | 2086 | break; |
2090 | case PR_SET_DUMPABLE: | 2087 | case PR_SET_DUMPABLE: |
2091 | if (arg2 < 0 || arg2 > 1) { | 2088 | if (arg2 < 0 || arg2 > 1) { |
2092 | error = -EINVAL; | 2089 | error = -EINVAL; |
2093 | break; | 2090 | break; |
2094 | } | 2091 | } |
2095 | current->mm->dumpable = arg2; | 2092 | current->mm->dumpable = arg2; |
2096 | break; | 2093 | break; |
2097 | 2094 | ||
2098 | case PR_SET_UNALIGN: | 2095 | case PR_SET_UNALIGN: |
2099 | error = SET_UNALIGN_CTL(current, arg2); | 2096 | error = SET_UNALIGN_CTL(current, arg2); |
2100 | break; | 2097 | break; |
2101 | case PR_GET_UNALIGN: | 2098 | case PR_GET_UNALIGN: |
2102 | error = GET_UNALIGN_CTL(current, arg2); | 2099 | error = GET_UNALIGN_CTL(current, arg2); |
2103 | break; | 2100 | break; |
2104 | case PR_SET_FPEMU: | 2101 | case PR_SET_FPEMU: |
2105 | error = SET_FPEMU_CTL(current, arg2); | 2102 | error = SET_FPEMU_CTL(current, arg2); |
2106 | break; | 2103 | break; |
2107 | case PR_GET_FPEMU: | 2104 | case PR_GET_FPEMU: |
2108 | error = GET_FPEMU_CTL(current, arg2); | 2105 | error = GET_FPEMU_CTL(current, arg2); |
2109 | break; | 2106 | break; |
2110 | case PR_SET_FPEXC: | 2107 | case PR_SET_FPEXC: |
2111 | error = SET_FPEXC_CTL(current, arg2); | 2108 | error = SET_FPEXC_CTL(current, arg2); |
2112 | break; | 2109 | break; |
2113 | case PR_GET_FPEXC: | 2110 | case PR_GET_FPEXC: |
2114 | error = GET_FPEXC_CTL(current, arg2); | 2111 | error = GET_FPEXC_CTL(current, arg2); |
2115 | break; | 2112 | break; |
2116 | case PR_GET_TIMING: | 2113 | case PR_GET_TIMING: |
2117 | error = PR_TIMING_STATISTICAL; | 2114 | error = PR_TIMING_STATISTICAL; |
2118 | break; | 2115 | break; |
2119 | case PR_SET_TIMING: | 2116 | case PR_SET_TIMING: |
2120 | if (arg2 == PR_TIMING_STATISTICAL) | 2117 | if (arg2 == PR_TIMING_STATISTICAL) |
2121 | error = 0; | 2118 | error = 0; |
2122 | else | 2119 | else |
2123 | error = -EINVAL; | 2120 | error = -EINVAL; |
2124 | break; | 2121 | break; |
2125 | 2122 | ||
2126 | case PR_GET_KEEPCAPS: | 2123 | case PR_GET_KEEPCAPS: |
2127 | if (current->keep_capabilities) | 2124 | if (current->keep_capabilities) |
2128 | error = 1; | 2125 | error = 1; |
2129 | break; | 2126 | break; |
2130 | case PR_SET_KEEPCAPS: | 2127 | case PR_SET_KEEPCAPS: |
2131 | if (arg2 != 0 && arg2 != 1) { | 2128 | if (arg2 != 0 && arg2 != 1) { |
2132 | error = -EINVAL; | 2129 | error = -EINVAL; |
2133 | break; | 2130 | break; |
2134 | } | 2131 | } |
2135 | current->keep_capabilities = arg2; | 2132 | current->keep_capabilities = arg2; |
2136 | break; | 2133 | break; |
2137 | case PR_SET_NAME: { | 2134 | case PR_SET_NAME: { |
2138 | struct task_struct *me = current; | 2135 | struct task_struct *me = current; |
2139 | unsigned char ncomm[sizeof(me->comm)]; | 2136 | unsigned char ncomm[sizeof(me->comm)]; |
2140 | 2137 | ||
2141 | ncomm[sizeof(me->comm)-1] = 0; | 2138 | ncomm[sizeof(me->comm)-1] = 0; |
2142 | if (strncpy_from_user(ncomm, (char __user *)arg2, | 2139 | if (strncpy_from_user(ncomm, (char __user *)arg2, |
2143 | sizeof(me->comm)-1) < 0) | 2140 | sizeof(me->comm)-1) < 0) |
2144 | return -EFAULT; | 2141 | return -EFAULT; |
2145 | set_task_comm(me, ncomm); | 2142 | set_task_comm(me, ncomm); |
2146 | return 0; | 2143 | return 0; |
2147 | } | 2144 | } |
2148 | case PR_GET_NAME: { | 2145 | case PR_GET_NAME: { |
2149 | struct task_struct *me = current; | 2146 | struct task_struct *me = current; |
2150 | unsigned char tcomm[sizeof(me->comm)]; | 2147 | unsigned char tcomm[sizeof(me->comm)]; |
2151 | 2148 | ||
2152 | get_task_comm(tcomm, me); | 2149 | get_task_comm(tcomm, me); |
2153 | if (copy_to_user((char __user *)arg2, tcomm, sizeof(tcomm))) | 2150 | if (copy_to_user((char __user *)arg2, tcomm, sizeof(tcomm))) |
2154 | return -EFAULT; | 2151 | return -EFAULT; |
2155 | return 0; | 2152 | return 0; |
2156 | } | 2153 | } |
2157 | case PR_GET_ENDIAN: | 2154 | case PR_GET_ENDIAN: |
2158 | error = GET_ENDIAN(current, arg2); | 2155 | error = GET_ENDIAN(current, arg2); |
2159 | break; | 2156 | break; |
2160 | case PR_SET_ENDIAN: | 2157 | case PR_SET_ENDIAN: |
2161 | error = SET_ENDIAN(current, arg2); | 2158 | error = SET_ENDIAN(current, arg2); |
2162 | break; | 2159 | break; |
2163 | 2160 | ||
2164 | default: | 2161 | default: |
2165 | error = -EINVAL; | 2162 | error = -EINVAL; |
2166 | break; | 2163 | break; |
2167 | } | 2164 | } |
2168 | return error; | 2165 | return error; |
2169 | } | 2166 | } |
2170 | 2167 | ||
2171 | asmlinkage long sys_getcpu(unsigned __user *cpup, unsigned __user *nodep, | 2168 | asmlinkage long sys_getcpu(unsigned __user *cpup, unsigned __user *nodep, |
2172 | struct getcpu_cache __user *cache) | 2169 | struct getcpu_cache __user *cache) |
2173 | { | 2170 | { |
2174 | int err = 0; | 2171 | int err = 0; |
2175 | int cpu = raw_smp_processor_id(); | 2172 | int cpu = raw_smp_processor_id(); |
2176 | if (cpup) | 2173 | if (cpup) |
2177 | err |= put_user(cpu, cpup); | 2174 | err |= put_user(cpu, cpup); |
2178 | if (nodep) | 2175 | if (nodep) |
2179 | err |= put_user(cpu_to_node(cpu), nodep); | 2176 | err |= put_user(cpu_to_node(cpu), nodep); |
2180 | if (cache) { | 2177 | if (cache) { |
2181 | /* | 2178 | /* |
2182 | * The cache is not needed for this implementation, | 2179 | * The cache is not needed for this implementation, |
2183 | * but make sure user programs pass something | 2180 | * but make sure user programs pass something |
2184 | * valid. vsyscall implementations can instead make | 2181 | * valid. vsyscall implementations can instead make |
2185 | * good use of the cache. Only use t0 and t1 because | 2182 | * good use of the cache. Only use t0 and t1 because |
2186 | * these are available in both 32bit and 64bit ABI (no | 2183 | * these are available in both 32bit and 64bit ABI (no |
2187 | * need for a compat_getcpu). 32bit has enough | 2184 | * need for a compat_getcpu). 32bit has enough |
2188 | * padding | 2185 | * padding |
2189 | */ | 2186 | */ |
2190 | unsigned long t0, t1; | 2187 | unsigned long t0, t1; |
2191 | get_user(t0, &cache->blob[0]); | 2188 | get_user(t0, &cache->blob[0]); |
2192 | get_user(t1, &cache->blob[1]); | 2189 | get_user(t1, &cache->blob[1]); |
2193 | t0++; | 2190 | t0++; |
2194 | t1++; | 2191 | t1++; |
2195 | put_user(t0, &cache->blob[0]); | 2192 | put_user(t0, &cache->blob[0]); |
2196 | put_user(t1, &cache->blob[1]); | 2193 | put_user(t1, &cache->blob[1]); |
2197 | } | 2194 | } |
2198 | return err ? -EFAULT : 0; | 2195 | return err ? -EFAULT : 0; |
2199 | } | 2196 | } |