OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [kernel/] [sys.c] - Blame information for rev 1275

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  linux/kernel/sys.c
3
 *
4
 *  Copyright (C) 1991, 1992  Linus Torvalds
5
 */
6
 
7
#include <linux/module.h>
8
#include <linux/mm.h>
9
#include <linux/utsname.h>
10
#include <linux/mman.h>
11
#include <linux/smp_lock.h>
12
#include <linux/notifier.h>
13
#include <linux/reboot.h>
14
#include <linux/prctl.h>
15
#include <linux/init.h>
16
#include <linux/highuid.h>
17
 
18
#include <asm/uaccess.h>
19
#include <asm/io.h>
20
 
21
#ifndef SET_UNALIGN_CTL
22
# define SET_UNALIGN_CTL(a,b)   (-EINVAL)
23
#endif
24
#ifndef GET_UNALIGN_CTL
25
# define GET_UNALIGN_CTL(a,b)   (-EINVAL)
26
#endif
27
#ifndef SET_FPEMU_CTL
28
# define SET_FPEMU_CTL(a,b)     (-EINVAL)
29
#endif
30
#ifndef GET_FPEMU_CTL
31
# define GET_FPEMU_CTL(a,b)     (-EINVAL)
32
#endif
33
#ifndef SET_FPEXC_CTL
34
# define SET_FPEXC_CTL(a,b)     (-EINVAL)
35
#endif
36
#ifndef GET_FPEXC_CTL
37
# define GET_FPEXC_CTL(a,b)     (-EINVAL)
38
#endif
39
 
40
/*
41
 * this is where the system-wide overflow UID and GID are defined, for
42
 * architectures that now have 32-bit UID/GID but didn't in the past
43
 */
44
 
45
int overflowuid = DEFAULT_OVERFLOWUID;
46
int overflowgid = DEFAULT_OVERFLOWGID;
47
 
48
/*
49
 * the same as above, but for filesystems which can only store a 16-bit
50
 * UID and GID. as such, this is needed on all architectures
51
 */
52
 
53
int fs_overflowuid = DEFAULT_FS_OVERFLOWUID;
54
int fs_overflowgid = DEFAULT_FS_OVERFLOWUID;
55
 
56
/*
57
 * this indicates whether you can reboot with ctrl-alt-del: the default is yes
58
 */
59
 
60
int C_A_D = 1;
61
int cad_pid = 1;
62
 
63
 
64
/*
65
 *      Notifier list for kernel code which wants to be called
66
 *      at shutdown. This is used to stop any idling DMA operations
67
 *      and the like.
68
 */
69
 
70
static struct notifier_block *reboot_notifier_list;
71
rwlock_t notifier_lock = RW_LOCK_UNLOCKED;
72
 
73
/**
74
 *      notifier_chain_register - Add notifier to a notifier chain
75
 *      @list: Pointer to root list pointer
76
 *      @n: New entry in notifier chain
77
 *
78
 *      Adds a notifier to a notifier chain.
79
 *
80
 *      Currently always returns zero.
81
 */
82
 
83
int notifier_chain_register(struct notifier_block **list, struct notifier_block *n)
84
{
85
        write_lock(&notifier_lock);
86
        while(*list)
87
        {
88
                if(n->priority > (*list)->priority)
89
                        break;
90
                list= &((*list)->next);
91
        }
92
        n->next = *list;
93
        *list=n;
94
        write_unlock(&notifier_lock);
95
        return 0;
96
}
97
 
98
/**
99
 *      notifier_chain_unregister - Remove notifier from a notifier chain
100
 *      @nl: Pointer to root list pointer
101
 *      @n: New entry in notifier chain
102
 *
103
 *      Removes a notifier from a notifier chain.
104
 *
105
 *      Returns zero on success, or %-ENOENT on failure.
106
 */
107
 
108
int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n)
109
{
110
        write_lock(&notifier_lock);
111
        while((*nl)!=NULL)
112
        {
113
                if((*nl)==n)
114
                {
115
                        *nl=n->next;
116
                        write_unlock(&notifier_lock);
117
                        return 0;
118
                }
119
                nl=&((*nl)->next);
120
        }
121
        write_unlock(&notifier_lock);
122
        return -ENOENT;
123
}
124
 
125
/**
126
 *      notifier_call_chain - Call functions in a notifier chain
127
 *      @n: Pointer to root pointer of notifier chain
128
 *      @val: Value passed unmodified to notifier function
129
 *      @v: Pointer passed unmodified to notifier function
130
 *
131
 *      Calls each function in a notifier chain in turn.
132
 *
133
 *      If the return value of the notifier can be and'd
134
 *      with %NOTIFY_STOP_MASK, then notifier_call_chain
135
 *      will return immediately, with the return value of
136
 *      the notifier function which halted execution.
137
 *      Otherwise, the return value is the return value
138
 *      of the last notifier function called.
139
 */
140
 
141
int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v)
142
{
143
        int ret=NOTIFY_DONE;
144
        struct notifier_block *nb = *n;
145
 
146
        while(nb)
147
        {
148
                ret=nb->notifier_call(nb,val,v);
149
                if(ret&NOTIFY_STOP_MASK)
150
                {
151
                        return ret;
152
                }
153
                nb=nb->next;
154
        }
155
        return ret;
156
}
157
 
158
/**
159
 *      register_reboot_notifier - Register function to be called at reboot time
160
 *      @nb: Info about notifier function to be called
161
 *
162
 *      Registers a function with the list of functions
163
 *      to be called at reboot time.
164
 *
165
 *      Currently always returns zero, as notifier_chain_register
166
 *      always returns zero.
167
 */
168
 
169
int register_reboot_notifier(struct notifier_block * nb)
170
{
171
        return notifier_chain_register(&reboot_notifier_list, nb);
172
}
173
 
174
/**
175
 *      unregister_reboot_notifier - Unregister previously registered reboot notifier
176
 *      @nb: Hook to be unregistered
177
 *
178
 *      Unregisters a previously registered reboot
179
 *      notifier function.
180
 *
181
 *      Returns zero on success, or %-ENOENT on failure.
182
 */
183
 
184
int unregister_reboot_notifier(struct notifier_block * nb)
185
{
186
        return notifier_chain_unregister(&reboot_notifier_list, nb);
187
}
188
 
189
asmlinkage long sys_ni_syscall(void)
190
{
191
        return -ENOSYS;
192
}
193
 
194
static int proc_sel(struct task_struct *p, int which, int who)
195
{
196
        if(p->pid)
197
        {
198
                switch (which) {
199
                        case PRIO_PROCESS:
200
                                if (!who && p == current)
201
                                        return 1;
202
                                return(p->pid == who);
203
                        case PRIO_PGRP:
204
                                if (!who)
205
                                        who = current->pgrp;
206
                                return(p->pgrp == who);
207
                        case PRIO_USER:
208
                                if (!who)
209
                                        who = current->uid;
210
                                return(p->uid == who);
211
                }
212
        }
213
        return 0;
214
}
215
 
216
asmlinkage long sys_setpriority(int which, int who, int niceval)
217
{
218
        struct task_struct *p;
219
        int error;
220
 
221
        if (which > 2 || which < 0)
222
                return -EINVAL;
223
 
224
        /* normalize: avoid signed division (rounding problems) */
225
        error = -ESRCH;
226
        if (niceval < -20)
227
                niceval = -20;
228
        if (niceval > 19)
229
                niceval = 19;
230
 
231
        read_lock(&tasklist_lock);
232
        for_each_task(p) {
233
                if (!proc_sel(p, which, who))
234
                        continue;
235
                if (p->uid != current->euid &&
236
                        p->uid != current->uid && !capable(CAP_SYS_NICE)) {
237
                        error = -EPERM;
238
                        continue;
239
                }
240
                if (error == -ESRCH)
241
                        error = 0;
242
                if (niceval < p->nice && !capable(CAP_SYS_NICE))
243
                        error = -EACCES;
244
                else
245
                        p->nice = niceval;
246
        }
247
        read_unlock(&tasklist_lock);
248
 
249
        return error;
250
}
251
 
252
/*
253
 * Ugh. To avoid negative return values, "getpriority()" will
254
 * not return the normal nice-value, but a negated value that
255
 * has been offset by 20 (ie it returns 40..1 instead of -20..19)
256
 * to stay compatible.
257
 */
258
asmlinkage long sys_getpriority(int which, int who)
259
{
260
        struct task_struct *p;
261
        long retval = -ESRCH;
262
 
263
        if (which > 2 || which < 0)
264
                return -EINVAL;
265
 
266
        read_lock(&tasklist_lock);
267
        for_each_task (p) {
268
                long niceval;
269
                if (!proc_sel(p, which, who))
270
                        continue;
271
                niceval = 20 - p->nice;
272
                if (niceval > retval)
273
                        retval = niceval;
274
        }
275
        read_unlock(&tasklist_lock);
276
 
277
        return retval;
278
}
279
 
280
 
281
/*
282
 * Reboot system call: for obvious reasons only root may call it,
283
 * and even root needs to set up some magic numbers in the registers
284
 * so that some mistake won't make this reboot the whole machine.
285
 * You can also set the meaning of the ctrl-alt-del-key here.
286
 *
287
 * reboot doesn't sync: do that yourself before calling this.
288
 */
289
asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void * arg)
290
{
291
        char buffer[256];
292
 
293
        /* We only trust the superuser with rebooting the system. */
294
        if (!capable(CAP_SYS_BOOT))
295
                return -EPERM;
296
 
297
        /* For safety, we require "magic" arguments. */
298
        if (magic1 != LINUX_REBOOT_MAGIC1 ||
299
            (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A &&
300
                        magic2 != LINUX_REBOOT_MAGIC2B))
301
                return -EINVAL;
302
 
303
        lock_kernel();
304
        switch (cmd) {
305
        case LINUX_REBOOT_CMD_RESTART:
306
                notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
307
                printk(KERN_EMERG "Restarting system.\n");
308
                machine_restart(NULL);
309
                break;
310
 
311
        case LINUX_REBOOT_CMD_CAD_ON:
312
                C_A_D = 1;
313
                break;
314
 
315
        case LINUX_REBOOT_CMD_CAD_OFF:
316
                C_A_D = 0;
317
                break;
318
 
319
        case LINUX_REBOOT_CMD_HALT:
320
                notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL);
321
                printk(KERN_EMERG "System halted.\n");
322
                machine_halt();
323
                do_exit(0);
324
                break;
325
 
326
        case LINUX_REBOOT_CMD_POWER_OFF:
327
                notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL);
328
                printk(KERN_EMERG "Power down.\n");
329
                machine_power_off();
330
                do_exit(0);
331
                break;
332
 
333
        case LINUX_REBOOT_CMD_RESTART2:
334
                if (strncpy_from_user(&buffer[0], (char *)arg, sizeof(buffer) - 1) < 0) {
335
                        unlock_kernel();
336
                        return -EFAULT;
337
                }
338
                buffer[sizeof(buffer) - 1] = '\0';
339
 
340
                notifier_call_chain(&reboot_notifier_list, SYS_RESTART, buffer);
341
                printk(KERN_EMERG "Restarting system with command '%s'.\n", buffer);
342
                machine_restart(buffer);
343
                break;
344
 
345
        default:
346
                unlock_kernel();
347
                return -EINVAL;
348
        }
349
        unlock_kernel();
350
        return 0;
351
}
352
 
353
static void deferred_cad(void *dummy)
354
{
355
        notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
356
        machine_restart(NULL);
357
}
358
 
359
/*
360
 * This function gets called by ctrl-alt-del - ie the keyboard interrupt.
361
 * As it's called within an interrupt, it may NOT sync: the only choice
362
 * is whether to reboot at once, or just ignore the ctrl-alt-del.
363
 */
364
void ctrl_alt_del(void)
365
{
366
        static struct tq_struct cad_tq = {
367
                routine: deferred_cad,
368
        };
369
 
370
        if (C_A_D)
371
                schedule_task(&cad_tq);
372
        else
373
                kill_proc(cad_pid, SIGINT, 1);
374
}
375
 
376
 
377
/*
378
 * Unprivileged users may change the real gid to the effective gid
379
 * or vice versa.  (BSD-style)
380
 *
381
 * If you set the real gid at all, or set the effective gid to a value not
382
 * equal to the real gid, then the saved gid is set to the new effective gid.
383
 *
384
 * This makes it possible for a setgid program to completely drop its
385
 * privileges, which is often a useful assertion to make when you are doing
386
 * a security audit over a program.
387
 *
388
 * The general idea is that a program which uses just setregid() will be
389
 * 100% compatible with BSD.  A program which uses just setgid() will be
390
 * 100% compatible with POSIX with saved IDs.
391
 *
392
 * SMP: There are not races, the GIDs are checked only by filesystem
393
 *      operations (as far as semantic preservation is concerned).
394
 */
395
asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
396
{
397
        int old_rgid = current->gid;
398
        int old_egid = current->egid;
399
        int new_rgid = old_rgid;
400
        int new_egid = old_egid;
401
 
402
        if (rgid != (gid_t) -1) {
403
                if ((old_rgid == rgid) ||
404
                    (current->egid==rgid) ||
405
                    capable(CAP_SETGID))
406
                        new_rgid = rgid;
407
                else
408
                        return -EPERM;
409
        }
410
        if (egid != (gid_t) -1) {
411
                if ((old_rgid == egid) ||
412
                    (current->egid == egid) ||
413
                    (current->sgid == egid) ||
414
                    capable(CAP_SETGID))
415
                        new_egid = egid;
416
                else {
417
                        return -EPERM;
418
                }
419
        }
420
        if (new_egid != old_egid)
421
        {
422
                current->mm->dumpable = 0;
423
                wmb();
424
        }
425
        if (rgid != (gid_t) -1 ||
426
            (egid != (gid_t) -1 && egid != old_rgid))
427
                current->sgid = new_egid;
428
        current->fsgid = new_egid;
429
        current->egid = new_egid;
430
        current->gid = new_rgid;
431
        return 0;
432
}
433
 
434
/*
435
 * setgid() is implemented like SysV w/ SAVED_IDS
436
 *
437
 * SMP: Same implicit races as above.
438
 */
439
asmlinkage long sys_setgid(gid_t gid)
440
{
441
        int old_egid = current->egid;
442
 
443
        if (capable(CAP_SETGID))
444
        {
445
                if(old_egid != gid)
446
                {
447
                        current->mm->dumpable=0;
448
                        wmb();
449
                }
450
                current->gid = current->egid = current->sgid = current->fsgid = gid;
451
        }
452
        else if ((gid == current->gid) || (gid == current->sgid))
453
        {
454
                if(old_egid != gid)
455
                {
456
                        current->mm->dumpable=0;
457
                        wmb();
458
                }
459
                current->egid = current->fsgid = gid;
460
        }
461
        else
462
                return -EPERM;
463
        return 0;
464
}
465
 
466
/*
467
 * cap_emulate_setxuid() fixes the effective / permitted capabilities of
468
 * a process after a call to setuid, setreuid, or setresuid.
469
 *
470
 *  1) When set*uiding _from_ one of {r,e,s}uid == 0 _to_ all of
471
 *  {r,e,s}uid != 0, the permitted and effective capabilities are
472
 *  cleared.
473
 *
474
 *  2) When set*uiding _from_ euid == 0 _to_ euid != 0, the effective
475
 *  capabilities of the process are cleared.
476
 *
477
 *  3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective
478
 *  capabilities are set to the permitted capabilities.
479
 *
480
 *  fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should
481
 *  never happen.
482
 *
483
 *  -astor
484
 *
485
 * cevans - New behaviour, Oct '99
486
 * A process may, via prctl(), elect to keep its capabilities when it
487
 * calls setuid() and switches away from uid==0. Both permitted and
488
 * effective sets will be retained.
489
 * Without this change, it was impossible for a daemon to drop only some
490
 * of its privilege. The call to setuid(!=0) would drop all privileges!
491
 * Keeping uid 0 is not an option because uid 0 owns too many vital
492
 * files..
493
 * Thanks to Olaf Kirch and Peter Benie for spotting this.
494
 */
495
static inline void cap_emulate_setxuid(int old_ruid, int old_euid,
496
                                       int old_suid)
497
{
498
        if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
499
            (current->uid != 0 && current->euid != 0 && current->suid != 0) &&
500
            !current->keep_capabilities) {
501
                cap_clear(current->cap_permitted);
502
                cap_clear(current->cap_effective);
503
        }
504
        if (old_euid == 0 && current->euid != 0) {
505
                cap_clear(current->cap_effective);
506
        }
507
        if (old_euid != 0 && current->euid == 0) {
508
                current->cap_effective = current->cap_permitted;
509
        }
510
}
511
 
512
static int set_user(uid_t new_ruid, int dumpclear)
513
{
514
        struct user_struct *new_user;
515
 
516
        new_user = alloc_uid(new_ruid);
517
        if (!new_user)
518
                return -EAGAIN;
519
        switch_uid(new_user);
520
 
521
        if(dumpclear)
522
        {
523
                current->mm->dumpable = 0;
524
                wmb();
525
        }
526
        current->uid = new_ruid;
527
        return 0;
528
}
529
 
530
/*
531
 * Unprivileged users may change the real uid to the effective uid
532
 * or vice versa.  (BSD-style)
533
 *
534
 * If you set the real uid at all, or set the effective uid to a value not
535
 * equal to the real uid, then the saved uid is set to the new effective uid.
536
 *
537
 * This makes it possible for a setuid program to completely drop its
538
 * privileges, which is often a useful assertion to make when you are doing
539
 * a security audit over a program.
540
 *
541
 * The general idea is that a program which uses just setreuid() will be
542
 * 100% compatible with BSD.  A program which uses just setuid() will be
543
 * 100% compatible with POSIX with saved IDs.
544
 */
545
asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
546
{
547
        int old_ruid, old_euid, old_suid, new_ruid, new_euid;
548
 
549
        new_ruid = old_ruid = current->uid;
550
        new_euid = old_euid = current->euid;
551
        old_suid = current->suid;
552
 
553
        if (ruid != (uid_t) -1) {
554
                new_ruid = ruid;
555
                if ((old_ruid != ruid) &&
556
                    (current->euid != ruid) &&
557
                    !capable(CAP_SETUID))
558
                        return -EPERM;
559
        }
560
 
561
        if (euid != (uid_t) -1) {
562
                new_euid = euid;
563
                if ((old_ruid != euid) &&
564
                    (current->euid != euid) &&
565
                    (current->suid != euid) &&
566
                    !capable(CAP_SETUID))
567
                        return -EPERM;
568
        }
569
 
570
        if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0)
571
                return -EAGAIN;
572
 
573
        if (new_euid != old_euid)
574
        {
575
                current->mm->dumpable=0;
576
                wmb();
577
        }
578
        current->fsuid = current->euid = new_euid;
579
        if (ruid != (uid_t) -1 ||
580
            (euid != (uid_t) -1 && euid != old_ruid))
581
                current->suid = current->euid;
582
        current->fsuid = current->euid;
583
 
584
        if (!issecure(SECURE_NO_SETUID_FIXUP)) {
585
                cap_emulate_setxuid(old_ruid, old_euid, old_suid);
586
        }
587
 
588
        return 0;
589
}
590
 
591
 
592
 
593
/*
594
 * setuid() is implemented like SysV with SAVED_IDS
595
 *
596
 * Note that SAVED_ID's is deficient in that a setuid root program
597
 * like sendmail, for example, cannot set its uid to be a normal
598
 * user and then switch back, because if you're root, setuid() sets
599
 * the saved uid too.  If you don't like this, blame the bright people
600
 * in the POSIX committee and/or USG.  Note that the BSD-style setreuid()
601
 * will allow a root program to temporarily drop privileges and be able to
602
 * regain them by swapping the real and effective uid.
603
 */
604
asmlinkage long sys_setuid(uid_t uid)
605
{
606
        int old_euid = current->euid;
607
        int old_ruid, old_suid, new_ruid, new_suid;
608
 
609
        old_ruid = new_ruid = current->uid;
610
        old_suid = current->suid;
611
        new_suid = old_suid;
612
 
613
        if (capable(CAP_SETUID)) {
614
                if (uid != old_ruid && set_user(uid, old_euid != uid) < 0)
615
                        return -EAGAIN;
616
                new_suid = uid;
617
        } else if ((uid != current->uid) && (uid != new_suid))
618
                return -EPERM;
619
 
620
        if (old_euid != uid)
621
        {
622
                current->mm->dumpable = 0;
623
                wmb();
624
        }
625
        current->fsuid = current->euid = uid;
626
        current->suid = new_suid;
627
 
628
        if (!issecure(SECURE_NO_SETUID_FIXUP)) {
629
                cap_emulate_setxuid(old_ruid, old_euid, old_suid);
630
        }
631
 
632
        return 0;
633
}
634
 
635
 
636
/*
637
 * This function implements a generic ability to update ruid, euid,
638
 * and suid.  This allows you to implement the 4.4 compatible seteuid().
639
 */
640
asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
641
{
642
        int old_ruid = current->uid;
643
        int old_euid = current->euid;
644
        int old_suid = current->suid;
645
 
646
        if (!capable(CAP_SETUID)) {
647
                if ((ruid != (uid_t) -1) && (ruid != current->uid) &&
648
                    (ruid != current->euid) && (ruid != current->suid))
649
                        return -EPERM;
650
                if ((euid != (uid_t) -1) && (euid != current->uid) &&
651
                    (euid != current->euid) && (euid != current->suid))
652
                        return -EPERM;
653
                if ((suid != (uid_t) -1) && (suid != current->uid) &&
654
                    (suid != current->euid) && (suid != current->suid))
655
                        return -EPERM;
656
        }
657
        if (ruid != (uid_t) -1) {
658
                if (ruid != current->uid && set_user(ruid, euid != current->euid) < 0)
659
                        return -EAGAIN;
660
        }
661
        if (euid != (uid_t) -1) {
662
                if (euid != current->euid)
663
                {
664
                        current->mm->dumpable = 0;
665
                        wmb();
666
                }
667
                current->euid = euid;
668
        }
669
        current->fsuid = current->euid;
670
        if (suid != (uid_t) -1)
671
                current->suid = suid;
672
 
673
        if (!issecure(SECURE_NO_SETUID_FIXUP)) {
674
                cap_emulate_setxuid(old_ruid, old_euid, old_suid);
675
        }
676
 
677
        return 0;
678
}
679
 
680
asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
681
{
682
        int retval;
683
 
684
        if (!(retval = put_user(current->uid, ruid)) &&
685
            !(retval = put_user(current->euid, euid)))
686
                retval = put_user(current->suid, suid);
687
 
688
        return retval;
689
}
690
 
691
/*
692
 * Same as above, but for rgid, egid, sgid.
693
 */
694
asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
695
{
696
        if (!capable(CAP_SETGID)) {
697
                if ((rgid != (gid_t) -1) && (rgid != current->gid) &&
698
                    (rgid != current->egid) && (rgid != current->sgid))
699
                        return -EPERM;
700
                if ((egid != (gid_t) -1) && (egid != current->gid) &&
701
                    (egid != current->egid) && (egid != current->sgid))
702
                        return -EPERM;
703
                if ((sgid != (gid_t) -1) && (sgid != current->gid) &&
704
                    (sgid != current->egid) && (sgid != current->sgid))
705
                        return -EPERM;
706
        }
707
        if (egid != (gid_t) -1) {
708
                if (egid != current->egid)
709
                {
710
                        current->mm->dumpable = 0;
711
                        wmb();
712
                }
713
                current->egid = egid;
714
        }
715
        current->fsgid = current->egid;
716
        if (rgid != (gid_t) -1)
717
                current->gid = rgid;
718
        if (sgid != (gid_t) -1)
719
                current->sgid = sgid;
720
        return 0;
721
}
722
 
723
asmlinkage long sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
724
{
725
        int retval;
726
 
727
        if (!(retval = put_user(current->gid, rgid)) &&
728
            !(retval = put_user(current->egid, egid)))
729
                retval = put_user(current->sgid, sgid);
730
 
731
        return retval;
732
}
733
 
734
 
735
/*
736
 * "setfsuid()" sets the fsuid - the uid used for filesystem checks. This
737
 * is used for "access()" and for the NFS daemon (letting nfsd stay at
738
 * whatever uid it wants to). It normally shadows "euid", except when
739
 * explicitly set by setfsuid() or for access..
740
 */
741
asmlinkage long sys_setfsuid(uid_t uid)
742
{
743
        int old_fsuid;
744
 
745
        old_fsuid = current->fsuid;
746
        if (uid == current->uid || uid == current->euid ||
747
            uid == current->suid || uid == current->fsuid ||
748
            capable(CAP_SETUID))
749
        {
750
                if (uid != old_fsuid)
751
                {
752
                        current->mm->dumpable = 0;
753
                        wmb();
754
                }
755
                current->fsuid = uid;
756
        }
757
 
758
        /* We emulate fsuid by essentially doing a scaled-down version
759
         * of what we did in setresuid and friends. However, we only
760
         * operate on the fs-specific bits of the process' effective
761
         * capabilities
762
         *
763
         * FIXME - is fsuser used for all CAP_FS_MASK capabilities?
764
         *          if not, we might be a bit too harsh here.
765
         */
766
 
767
        if (!issecure(SECURE_NO_SETUID_FIXUP)) {
768
                if (old_fsuid == 0 && current->fsuid != 0) {
769
                        cap_t(current->cap_effective) &= ~CAP_FS_MASK;
770
                }
771
                if (old_fsuid != 0 && current->fsuid == 0) {
772
                        cap_t(current->cap_effective) |=
773
                                (cap_t(current->cap_permitted) & CAP_FS_MASK);
774
                }
775
        }
776
 
777
        return old_fsuid;
778
}
779
 
780
/*
781
 * Samma på svenska..
782
 */
783
asmlinkage long sys_setfsgid(gid_t gid)
784
{
785
        int old_fsgid;
786
 
787
        old_fsgid = current->fsgid;
788
        if (gid == current->gid || gid == current->egid ||
789
            gid == current->sgid || gid == current->fsgid ||
790
            capable(CAP_SETGID))
791
        {
792
                if (gid != old_fsgid)
793
                {
794
                        current->mm->dumpable = 0;
795
                        wmb();
796
                }
797
                current->fsgid = gid;
798
        }
799
        return old_fsgid;
800
}
801
 
802
asmlinkage long sys_times(struct tms * tbuf)
803
{
804
        /*
805
         *      In the SMP world we might just be unlucky and have one of
806
         *      the times increment as we use it. Since the value is an
807
         *      atomically safe type this is just fine. Conceptually its
808
         *      as if the syscall took an instant longer to occur.
809
         */
810
        if (tbuf)
811
                if (copy_to_user(tbuf, &current->times, sizeof(struct tms)))
812
                        return -EFAULT;
813
        return jiffies;
814
}
815
 
816
/*
817
 * This needs some heavy checking ...
818
 * I just haven't the stomach for it. I also don't fully
819
 * understand sessions/pgrp etc. Let somebody who does explain it.
820
 *
821
 * OK, I think I have the protection semantics right.... this is really
822
 * only important on a multi-user system anyway, to make sure one user
823
 * can't send a signal to a process owned by another.  -TYT, 12/12/91
824
 *
825
 * Auch. Had to add the 'did_exec' flag to conform completely to POSIX.
826
 * LBT 04.03.94
827
 */
828
 
829
asmlinkage long sys_setpgid(pid_t pid, pid_t pgid)
830
{
831
        struct task_struct * p;
832
        int err = -EINVAL;
833
 
834
        if (!pid)
835
                pid = current->pid;
836
        if (!pgid)
837
                pgid = pid;
838
        if (pgid < 0)
839
                return -EINVAL;
840
 
841
        /* From this point forward we keep holding onto the tasklist lock
842
         * so that our parent does not change from under us. -DaveM
843
         */
844
        read_lock(&tasklist_lock);
845
 
846
        err = -ESRCH;
847
        p = find_task_by_pid(pid);
848
        if (!p)
849
                goto out;
850
 
851
        if (p->p_pptr == current || p->p_opptr == current) {
852
                err = -EPERM;
853
                if (p->session != current->session)
854
                        goto out;
855
                err = -EACCES;
856
                if (p->did_exec)
857
                        goto out;
858
        } else if (p != current)
859
                goto out;
860
        err = -EPERM;
861
        if (p->leader)
862
                goto out;
863
        if (pgid != pid) {
864
                struct task_struct * tmp;
865
                for_each_task (tmp) {
866
                        if (tmp->pgrp == pgid &&
867
                            tmp->session == current->session)
868
                                goto ok_pgid;
869
                }
870
                goto out;
871
        }
872
 
873
ok_pgid:
874
        p->pgrp = pgid;
875
        err = 0;
876
out:
877
        /* All paths lead to here, thus we are safe. -DaveM */
878
        read_unlock(&tasklist_lock);
879
        return err;
880
}
881
 
882
asmlinkage long sys_getpgid(pid_t pid)
883
{
884
        if (!pid) {
885
                return current->pgrp;
886
        } else {
887
                int retval;
888
                struct task_struct *p;
889
 
890
                read_lock(&tasklist_lock);
891
                p = find_task_by_pid(pid);
892
 
893
                retval = -ESRCH;
894
                if (p)
895
                        retval = p->pgrp;
896
                read_unlock(&tasklist_lock);
897
                return retval;
898
        }
899
}
900
 
901
asmlinkage long sys_getpgrp(void)
902
{
903
        /* SMP - assuming writes are word atomic this is fine */
904
        return current->pgrp;
905
}
906
 
907
asmlinkage long sys_getsid(pid_t pid)
908
{
909
        if (!pid) {
910
                return current->session;
911
        } else {
912
                int retval;
913
                struct task_struct *p;
914
 
915
                read_lock(&tasklist_lock);
916
                p = find_task_by_pid(pid);
917
 
918
                retval = -ESRCH;
919
                if(p)
920
                        retval = p->session;
921
                read_unlock(&tasklist_lock);
922
                return retval;
923
        }
924
}
925
 
926
asmlinkage long sys_setsid(void)
927
{
928
        struct task_struct * p;
929
        int err = -EPERM;
930
 
931
        read_lock(&tasklist_lock);
932
        for_each_task(p) {
933
                if (p->pgrp == current->pid)
934
                        goto out;
935
        }
936
 
937
        current->leader = 1;
938
        current->session = current->pgrp = current->pid;
939
        current->tty = NULL;
940
        current->tty_old_pgrp = 0;
941
        err = current->pgrp;
942
out:
943
        read_unlock(&tasklist_lock);
944
        return err;
945
}
946
 
947
/*
948
 * Supplementary group IDs
949
 */
950
asmlinkage long sys_getgroups(int gidsetsize, gid_t *grouplist)
951
{
952
        int i;
953
 
954
        /*
955
         *      SMP: Nobody else can change our grouplist. Thus we are
956
         *      safe.
957
         */
958
 
959
        if (gidsetsize < 0)
960
                return -EINVAL;
961
        i = current->ngroups;
962
        if (gidsetsize) {
963
                if (i > gidsetsize)
964
                        return -EINVAL;
965
                if (copy_to_user(grouplist, current->groups, sizeof(gid_t)*i))
966
                        return -EFAULT;
967
        }
968
        return i;
969
}
970
 
971
/*
972
 *      SMP: Our groups are not shared. We can copy to/from them safely
973
 *      without another task interfering.
974
 */
975
 
976
asmlinkage long sys_setgroups(int gidsetsize, gid_t *grouplist)
977
{
978
        if (!capable(CAP_SETGID))
979
                return -EPERM;
980
        if ((unsigned) gidsetsize > NGROUPS)
981
                return -EINVAL;
982
        if(copy_from_user(current->groups, grouplist, gidsetsize * sizeof(gid_t)))
983
                return -EFAULT;
984
        current->ngroups = gidsetsize;
985
        return 0;
986
}
987
 
988
static int supplemental_group_member(gid_t grp)
989
{
990
        int i = current->ngroups;
991
 
992
        if (i) {
993
                gid_t *groups = current->groups;
994
                do {
995
                        if (*groups == grp)
996
                                return 1;
997
                        groups++;
998
                        i--;
999
                } while (i);
1000
        }
1001
        return 0;
1002
}
1003
 
1004
/*
1005
 * Check whether we're fsgid/egid or in the supplemental group..
1006
 */
1007
int in_group_p(gid_t grp)
1008
{
1009
        int retval = 1;
1010
        if (grp != current->fsgid)
1011
                retval = supplemental_group_member(grp);
1012
        return retval;
1013
}
1014
 
1015
int in_egroup_p(gid_t grp)
1016
{
1017
        int retval = 1;
1018
        if (grp != current->egid)
1019
                retval = supplemental_group_member(grp);
1020
        return retval;
1021
}
1022
 
1023
DECLARE_RWSEM(uts_sem);
1024
 
1025
asmlinkage long sys_newuname(struct new_utsname * name)
1026
{
1027
        int errno = 0;
1028
 
1029
        down_read(&uts_sem);
1030
        if (copy_to_user(name,&system_utsname,sizeof *name))
1031
                errno = -EFAULT;
1032
        up_read(&uts_sem);
1033
        return errno;
1034
}
1035
 
1036
asmlinkage long sys_sethostname(char *name, int len)
1037
{
1038
        int errno;
1039
        char tmp[__NEW_UTS_LEN];
1040
 
1041
        if (!capable(CAP_SYS_ADMIN))
1042
                return -EPERM;
1043
        if (len < 0 || len > __NEW_UTS_LEN)
1044
                return -EINVAL;
1045
        down_write(&uts_sem);
1046
        errno = -EFAULT;
1047
        if (!copy_from_user(tmp, name, len)) {
1048
                memcpy(system_utsname.nodename, tmp, len);
1049
                system_utsname.nodename[len] = 0;
1050
                errno = 0;
1051
        }
1052
        up_write(&uts_sem);
1053
        return errno;
1054
}
1055
 
1056
asmlinkage long sys_gethostname(char *name, int len)
1057
{
1058
        int i, errno;
1059
 
1060
        if (len < 0)
1061
                return -EINVAL;
1062
        down_read(&uts_sem);
1063
        i = 1 + strlen(system_utsname.nodename);
1064
        if (i > len)
1065
                i = len;
1066
        errno = 0;
1067
        if (copy_to_user(name, system_utsname.nodename, i))
1068
                errno = -EFAULT;
1069
        up_read(&uts_sem);
1070
        return errno;
1071
}
1072
 
1073
/*
1074
 * Only setdomainname; getdomainname can be implemented by calling
1075
 * uname()
1076
 */
1077
asmlinkage long sys_setdomainname(char *name, int len)
1078
{
1079
        int errno;
1080
        char tmp[__NEW_UTS_LEN];
1081
 
1082
        if (!capable(CAP_SYS_ADMIN))
1083
                return -EPERM;
1084
        if (len < 0 || len > __NEW_UTS_LEN)
1085
                return -EINVAL;
1086
 
1087
        down_write(&uts_sem);
1088
        errno = -EFAULT;
1089
        if (!copy_from_user(tmp, name, len)) {
1090
                memcpy(system_utsname.domainname, tmp, len);
1091
                system_utsname.domainname[len] = 0;
1092
                errno = 0;
1093
        }
1094
        up_write(&uts_sem);
1095
        return errno;
1096
}
1097
 
1098
asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit *rlim)
1099
{
1100
        if (resource >= RLIM_NLIMITS)
1101
                return -EINVAL;
1102
        else
1103
                return copy_to_user(rlim, current->rlim + resource, sizeof(*rlim))
1104
                        ? -EFAULT : 0;
1105
}
1106
 
1107
#if !defined(__ia64__) 
1108
 
1109
/*
1110
 *      Back compatibility for getrlimit. Needed for some apps.
1111
 */
1112
 
1113
asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit *rlim)
1114
{
1115
        struct rlimit x;
1116
        if (resource >= RLIM_NLIMITS)
1117
                return -EINVAL;
1118
 
1119
        memcpy(&x, current->rlim + resource, sizeof(*rlim));
1120
        if(x.rlim_cur > 0x7FFFFFFF)
1121
                x.rlim_cur = 0x7FFFFFFF;
1122
        if(x.rlim_max > 0x7FFFFFFF)
1123
                x.rlim_max = 0x7FFFFFFF;
1124
        return copy_to_user(rlim, &x, sizeof(x))?-EFAULT:0;
1125
}
1126
 
1127
#endif
1128
 
1129
asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim)
1130
{
1131
        struct rlimit new_rlim, *old_rlim;
1132
 
1133
        if (resource >= RLIM_NLIMITS)
1134
                return -EINVAL;
1135
        if(copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
1136
                return -EFAULT;
1137
       if (new_rlim.rlim_cur > new_rlim.rlim_max)
1138
               return -EINVAL;
1139
        old_rlim = current->rlim + resource;
1140
        if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
1141
             (new_rlim.rlim_max > old_rlim->rlim_max)) &&
1142
            !capable(CAP_SYS_RESOURCE))
1143
                return -EPERM;
1144
        if (resource == RLIMIT_NOFILE) {
1145
                if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN)
1146
                        return -EPERM;
1147
        }
1148
        *old_rlim = new_rlim;
1149
        return 0;
1150
}
1151
 
1152
/*
1153
 * It would make sense to put struct rusage in the task_struct,
1154
 * except that would make the task_struct be *really big*.  After
1155
 * task_struct gets moved into malloc'ed memory, it would
1156
 * make sense to do this.  It will make moving the rest of the information
1157
 * a lot simpler!  (Which we're not doing right now because we're not
1158
 * measuring them yet).
1159
 *
1160
 * This is SMP safe.  Either we are called from sys_getrusage on ourselves
1161
 * below (we know we aren't going to exit/disappear and only we change our
1162
 * rusage counters), or we are called from wait4() on a process which is
1163
 * either stopped or zombied.  In the zombied case the task won't get
1164
 * reaped till shortly after the call to getrusage(), in both cases the
1165
 * task being examined is in a frozen state so the counters won't change.
1166
 *
1167
 * FIXME! Get the fault counts properly!
1168
 */
1169
int getrusage(struct task_struct *p, int who, struct rusage *ru)
1170
{
1171
        struct rusage r;
1172
 
1173
        memset((char *) &r, 0, sizeof(r));
1174
        switch (who) {
1175
                case RUSAGE_SELF:
1176
                        r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_utime);
1177
                        r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_utime);
1178
                        r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_stime);
1179
                        r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_stime);
1180
                        r.ru_minflt = p->min_flt;
1181
                        r.ru_majflt = p->maj_flt;
1182
                        r.ru_nswap = p->nswap;
1183
                        break;
1184
                case RUSAGE_CHILDREN:
1185
                        r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_cutime);
1186
                        r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_cutime);
1187
                        r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_cstime);
1188
                        r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_cstime);
1189
                        r.ru_minflt = p->cmin_flt;
1190
                        r.ru_majflt = p->cmaj_flt;
1191
                        r.ru_nswap = p->cnswap;
1192
                        break;
1193
                default:
1194
                        r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_utime + p->times.tms_cutime);
1195
                        r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_utime + p->times.tms_cutime);
1196
                        r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_stime + p->times.tms_cstime);
1197
                        r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_stime + p->times.tms_cstime);
1198
                        r.ru_minflt = p->min_flt + p->cmin_flt;
1199
                        r.ru_majflt = p->maj_flt + p->cmaj_flt;
1200
                        r.ru_nswap = p->nswap + p->cnswap;
1201
                        break;
1202
        }
1203
        return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
1204
}
1205
 
1206
asmlinkage long sys_getrusage(int who, struct rusage *ru)
1207
{
1208
        if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
1209
                return -EINVAL;
1210
        return getrusage(current, who, ru);
1211
}
1212
 
1213
asmlinkage long sys_umask(int mask)
1214
{
1215
        mask = xchg(&current->fs->umask, mask & S_IRWXUGO);
1216
        return mask;
1217
}
1218
 
1219
asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
1220
                          unsigned long arg4, unsigned long arg5)
1221
{
1222
        int error = 0;
1223
        int sig;
1224
 
1225
        switch (option) {
1226
                case PR_SET_PDEATHSIG:
1227
                        sig = arg2;
1228
                        if (sig < 0 || sig > _NSIG) {
1229
                                error = -EINVAL;
1230
                                break;
1231
                        }
1232
                        current->pdeath_signal = sig;
1233
                        break;
1234
                case PR_GET_PDEATHSIG:
1235
                        error = put_user(current->pdeath_signal, (int *)arg2);
1236
                        break;
1237
                case PR_GET_DUMPABLE:
1238
                        if (is_dumpable(current))
1239
                                error = 1;
1240
                        break;
1241
                case PR_SET_DUMPABLE:
1242
                        if (arg2 != 0 && arg2 != 1) {
1243
                                error = -EINVAL;
1244
                                break;
1245
                        }
1246
                        current->mm->dumpable = arg2;
1247
                        break;
1248
 
1249
                case PR_SET_UNALIGN:
1250
                        error = SET_UNALIGN_CTL(current, arg2);
1251
                        break;
1252
                case PR_GET_UNALIGN:
1253
                        error = GET_UNALIGN_CTL(current, arg2);
1254
                        break;
1255
                case PR_SET_FPEMU:
1256
                        error = SET_FPEMU_CTL(current, arg2);
1257
                        break;
1258
                case PR_GET_FPEMU:
1259
                        error = GET_FPEMU_CTL(current, arg2);
1260
                        break;
1261
                case PR_SET_FPEXC:
1262
                        error = SET_FPEXC_CTL(current, arg2);
1263
                        break;
1264
                case PR_GET_FPEXC:
1265
                        error = GET_FPEXC_CTL(current, arg2);
1266
                        break;
1267
 
1268
                case PR_GET_KEEPCAPS:
1269
                        if (current->keep_capabilities)
1270
                                error = 1;
1271
                        break;
1272
                case PR_SET_KEEPCAPS:
1273
                        if (arg2 != 0 && arg2 != 1) {
1274
                                error = -EINVAL;
1275
                                break;
1276
                        }
1277
                        current->keep_capabilities = arg2;
1278
                        break;
1279
                default:
1280
                        error = -EINVAL;
1281
                        break;
1282
        }
1283
        return error;
1284
}
1285
 
1286
EXPORT_SYMBOL(notifier_chain_register);
1287
EXPORT_SYMBOL(notifier_chain_unregister);
1288
EXPORT_SYMBOL(notifier_call_chain);
1289
EXPORT_SYMBOL(register_reboot_notifier);
1290
EXPORT_SYMBOL(unregister_reboot_notifier);
1291
EXPORT_SYMBOL(in_group_p);
1292
EXPORT_SYMBOL(in_egroup_p);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.