aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2018-10-12 09:28:09 -0400
committerTheodore Ts'o <tytso@mit.edu>2018-10-12 09:28:09 -0400
commit33458eaba4dfe778a426df6a19b7aad2ff9f7eec (patch)
treef4732bd54c93bd877209855b3148db771da85b55
parent6fd941784b8ac3e74313f7112f0586076dc36544 (diff)
ext4: fix use-after-free race in ext4_remount()'s error path
It's possible for ext4_show_quota_options() to try reading s_qf_names[i] while it is being modified by ext4_remount() --- most notably, in ext4_remount's error path when the original values of the quota file name gets restored. Reported-by: syzbot+a2872d6feea6918008a9@syzkaller.appspotmail.com Signed-off-by: Theodore Ts'o <tytso@mit.edu> Cc: stable@kernel.org # 3.2+
-rw-r--r--fs/ext4/ext4.h3
-rw-r--r--fs/ext4/super.c73
2 files changed, 50 insertions, 26 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 86e1bacac757..12f90d48ba61 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1405,7 +1405,8 @@ struct ext4_sb_info {
1405 u32 s_min_batch_time; 1405 u32 s_min_batch_time;
1406 struct block_device *journal_bdev; 1406 struct block_device *journal_bdev;
1407#ifdef CONFIG_QUOTA 1407#ifdef CONFIG_QUOTA
1408 char *s_qf_names[EXT4_MAXQUOTAS]; /* Names of quota files with journalled quota */ 1408 /* Names of quota files with journalled quota */
1409 char __rcu *s_qf_names[EXT4_MAXQUOTAS];
1409 int s_jquota_fmt; /* Format of quota to use */ 1410 int s_jquota_fmt; /* Format of quota to use */
1410#endif 1411#endif
1411 unsigned int s_want_extra_isize; /* New inodes should reserve # bytes */ 1412 unsigned int s_want_extra_isize; /* New inodes should reserve # bytes */
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index faf293ed8060..a221f1cdf704 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -914,6 +914,18 @@ static inline void ext4_quota_off_umount(struct super_block *sb)
914 for (type = 0; type < EXT4_MAXQUOTAS; type++) 914 for (type = 0; type < EXT4_MAXQUOTAS; type++)
915 ext4_quota_off(sb, type); 915 ext4_quota_off(sb, type);
916} 916}
917
918/*
919 * This is a helper function which is used in the mount/remount
920 * codepaths (which holds s_umount) to fetch the quota file name.
921 */
922static inline char *get_qf_name(struct super_block *sb,
923 struct ext4_sb_info *sbi,
924 int type)
925{
926 return rcu_dereference_protected(sbi->s_qf_names[type],
927 lockdep_is_held(&sb->s_umount));
928}
917#else 929#else
918static inline void ext4_quota_off_umount(struct super_block *sb) 930static inline void ext4_quota_off_umount(struct super_block *sb)
919{ 931{
@@ -965,7 +977,7 @@ static void ext4_put_super(struct super_block *sb)
965 percpu_free_rwsem(&sbi->s_journal_flag_rwsem); 977 percpu_free_rwsem(&sbi->s_journal_flag_rwsem);
966#ifdef CONFIG_QUOTA 978#ifdef CONFIG_QUOTA
967 for (i = 0; i < EXT4_MAXQUOTAS; i++) 979 for (i = 0; i < EXT4_MAXQUOTAS; i++)
968 kfree(sbi->s_qf_names[i]); 980 kfree(get_qf_name(sb, sbi, i));
969#endif 981#endif
970 982
971 /* Debugging code just in case the in-memory inode orphan list 983 /* Debugging code just in case the in-memory inode orphan list
@@ -1531,11 +1543,10 @@ static const char deprecated_msg[] =
1531static int set_qf_name(struct super_block *sb, int qtype, substring_t *args) 1543static int set_qf_name(struct super_block *sb, int qtype, substring_t *args)
1532{ 1544{
1533 struct ext4_sb_info *sbi = EXT4_SB(sb); 1545 struct ext4_sb_info *sbi = EXT4_SB(sb);
1534 char *qname; 1546 char *qname, *old_qname = get_qf_name(sb, sbi, qtype);
1535 int ret = -1; 1547 int ret = -1;
1536 1548
1537 if (sb_any_quota_loaded(sb) && 1549 if (sb_any_quota_loaded(sb) && !old_qname) {
1538 !sbi->s_qf_names[qtype]) {
1539 ext4_msg(sb, KERN_ERR, 1550 ext4_msg(sb, KERN_ERR,
1540 "Cannot change journaled " 1551 "Cannot change journaled "
1541 "quota options when quota turned on"); 1552 "quota options when quota turned on");
@@ -1552,8 +1563,8 @@ static int set_qf_name(struct super_block *sb, int qtype, substring_t *args)
1552 "Not enough memory for storing quotafile name"); 1563 "Not enough memory for storing quotafile name");
1553 return -1; 1564 return -1;
1554 } 1565 }
1555 if (sbi->s_qf_names[qtype]) { 1566 if (old_qname) {
1556 if (strcmp(sbi->s_qf_names[qtype], qname) == 0) 1567 if (strcmp(old_qname, qname) == 0)
1557 ret = 1; 1568 ret = 1;
1558 else 1569 else
1559 ext4_msg(sb, KERN_ERR, 1570 ext4_msg(sb, KERN_ERR,
@@ -1566,7 +1577,7 @@ static int set_qf_name(struct super_block *sb, int qtype, substring_t *args)
1566 "quotafile must be on filesystem root"); 1577 "quotafile must be on filesystem root");
1567 goto errout; 1578 goto errout;
1568 } 1579 }
1569 sbi->s_qf_names[qtype] = qname; 1580 rcu_assign_pointer(sbi->s_qf_names[qtype], qname);
1570 set_opt(sb, QUOTA); 1581 set_opt(sb, QUOTA);
1571 return 1; 1582 return 1;
1572errout: 1583errout:
@@ -1578,15 +1589,16 @@ static int clear_qf_name(struct super_block *sb, int qtype)
1578{ 1589{
1579 1590
1580 struct ext4_sb_info *sbi = EXT4_SB(sb); 1591 struct ext4_sb_info *sbi = EXT4_SB(sb);
1592 char *old_qname = get_qf_name(sb, sbi, qtype);
1581 1593
1582 if (sb_any_quota_loaded(sb) && 1594 if (sb_any_quota_loaded(sb) && old_qname) {
1583 sbi->s_qf_names[qtype]) {
1584 ext4_msg(sb, KERN_ERR, "Cannot change journaled quota options" 1595 ext4_msg(sb, KERN_ERR, "Cannot change journaled quota options"
1585 " when quota turned on"); 1596 " when quota turned on");
1586 return -1; 1597 return -1;
1587 } 1598 }
1588 kfree(sbi->s_qf_names[qtype]); 1599 rcu_assign_pointer(sbi->s_qf_names[qtype], NULL);
1589 sbi->s_qf_names[qtype] = NULL; 1600 synchronize_rcu();
1601 kfree(old_qname);
1590 return 1; 1602 return 1;
1591} 1603}
1592#endif 1604#endif
@@ -1961,7 +1973,7 @@ static int parse_options(char *options, struct super_block *sb,
1961 int is_remount) 1973 int is_remount)
1962{ 1974{
1963 struct ext4_sb_info *sbi = EXT4_SB(sb); 1975 struct ext4_sb_info *sbi = EXT4_SB(sb);
1964 char *p; 1976 char *p, __maybe_unused *usr_qf_name, __maybe_unused *grp_qf_name;
1965 substring_t args[MAX_OPT_ARGS]; 1977 substring_t args[MAX_OPT_ARGS];
1966 int token; 1978 int token;
1967 1979
@@ -1992,11 +2004,13 @@ static int parse_options(char *options, struct super_block *sb,
1992 "Cannot enable project quota enforcement."); 2004 "Cannot enable project quota enforcement.");
1993 return 0; 2005 return 0;
1994 } 2006 }
1995 if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) { 2007 usr_qf_name = get_qf_name(sb, sbi, USRQUOTA);
1996 if (test_opt(sb, USRQUOTA) && sbi->s_qf_names[USRQUOTA]) 2008 grp_qf_name = get_qf_name(sb, sbi, GRPQUOTA);
2009 if (usr_qf_name || grp_qf_name) {
2010 if (test_opt(sb, USRQUOTA) && usr_qf_name)
1997 clear_opt(sb, USRQUOTA); 2011 clear_opt(sb, USRQUOTA);
1998 2012
1999 if (test_opt(sb, GRPQUOTA) && sbi->s_qf_names[GRPQUOTA]) 2013 if (test_opt(sb, GRPQUOTA) && grp_qf_name)
2000 clear_opt(sb, GRPQUOTA); 2014 clear_opt(sb, GRPQUOTA);
2001 2015
2002 if (test_opt(sb, GRPQUOTA) || test_opt(sb, USRQUOTA)) { 2016 if (test_opt(sb, GRPQUOTA) || test_opt(sb, USRQUOTA)) {
@@ -2030,6 +2044,7 @@ static inline void ext4_show_quota_options(struct seq_file *seq,
2030{ 2044{
2031#if defined(CONFIG_QUOTA) 2045#if defined(CONFIG_QUOTA)
2032 struct ext4_sb_info *sbi = EXT4_SB(sb); 2046 struct ext4_sb_info *sbi = EXT4_SB(sb);
2047 char *usr_qf_name, *grp_qf_name;
2033 2048
2034 if (sbi->s_jquota_fmt) { 2049 if (sbi->s_jquota_fmt) {
2035 char *fmtname = ""; 2050 char *fmtname = "";
@@ -2048,11 +2063,14 @@ static inline void ext4_show_quota_options(struct seq_file *seq,
2048 seq_printf(seq, ",jqfmt=%s", fmtname); 2063 seq_printf(seq, ",jqfmt=%s", fmtname);
2049 } 2064 }
2050 2065
2051 if (sbi->s_qf_names[USRQUOTA]) 2066 rcu_read_lock();
2052 seq_show_option(seq, "usrjquota", sbi->s_qf_names[USRQUOTA]); 2067 usr_qf_name = rcu_dereference(sbi->s_qf_names[USRQUOTA]);
2053 2068 grp_qf_name = rcu_dereference(sbi->s_qf_names[GRPQUOTA]);
2054 if (sbi->s_qf_names[GRPQUOTA]) 2069 if (usr_qf_name)
2055 seq_show_option(seq, "grpjquota", sbi->s_qf_names[GRPQUOTA]); 2070 seq_show_option(seq, "usrjquota", usr_qf_name);
2071 if (grp_qf_name)
2072 seq_show_option(seq, "grpjquota", grp_qf_name);
2073 rcu_read_unlock();
2056#endif 2074#endif
2057} 2075}
2058 2076
@@ -5104,6 +5122,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
5104 int err = 0; 5122 int err = 0;
5105#ifdef CONFIG_QUOTA 5123#ifdef CONFIG_QUOTA
5106 int i, j; 5124 int i, j;
5125 char *to_free[EXT4_MAXQUOTAS];
5107#endif 5126#endif
5108 char *orig_data = kstrdup(data, GFP_KERNEL); 5127 char *orig_data = kstrdup(data, GFP_KERNEL);
5109 5128
@@ -5123,8 +5142,9 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
5123 old_opts.s_jquota_fmt = sbi->s_jquota_fmt; 5142 old_opts.s_jquota_fmt = sbi->s_jquota_fmt;
5124 for (i = 0; i < EXT4_MAXQUOTAS; i++) 5143 for (i = 0; i < EXT4_MAXQUOTAS; i++)
5125 if (sbi->s_qf_names[i]) { 5144 if (sbi->s_qf_names[i]) {
5126 old_opts.s_qf_names[i] = kstrdup(sbi->s_qf_names[i], 5145 char *qf_name = get_qf_name(sb, sbi, i);
5127 GFP_KERNEL); 5146
5147 old_opts.s_qf_names[i] = kstrdup(qf_name, GFP_KERNEL);
5128 if (!old_opts.s_qf_names[i]) { 5148 if (!old_opts.s_qf_names[i]) {
5129 for (j = 0; j < i; j++) 5149 for (j = 0; j < i; j++)
5130 kfree(old_opts.s_qf_names[j]); 5150 kfree(old_opts.s_qf_names[j]);
@@ -5353,9 +5373,12 @@ restore_opts:
5353#ifdef CONFIG_QUOTA 5373#ifdef CONFIG_QUOTA
5354 sbi->s_jquota_fmt = old_opts.s_jquota_fmt; 5374 sbi->s_jquota_fmt = old_opts.s_jquota_fmt;
5355 for (i = 0; i < EXT4_MAXQUOTAS; i++) { 5375 for (i = 0; i < EXT4_MAXQUOTAS; i++) {
5356 kfree(sbi->s_qf_names[i]); 5376 to_free[i] = get_qf_name(sb, sbi, i);
5357 sbi->s_qf_names[i] = old_opts.s_qf_names[i]; 5377 rcu_assign_pointer(sbi->s_qf_names[i], old_opts.s_qf_names[i]);
5358 } 5378 }
5379 synchronize_rcu();
5380 for (i = 0; i < EXT4_MAXQUOTAS; i++)
5381 kfree(to_free[i]);
5359#endif 5382#endif
5360 kfree(orig_data); 5383 kfree(orig_data);
5361 return err; 5384 return err;
@@ -5546,7 +5569,7 @@ static int ext4_write_info(struct super_block *sb, int type)
5546 */ 5569 */
5547static int ext4_quota_on_mount(struct super_block *sb, int type) 5570static int ext4_quota_on_mount(struct super_block *sb, int type)
5548{ 5571{
5549 return dquot_quota_on_mount(sb, EXT4_SB(sb)->s_qf_names[type], 5572 return dquot_quota_on_mount(sb, get_qf_name(sb, EXT4_SB(sb), type),
5550 EXT4_SB(sb)->s_jquota_fmt, type); 5573 EXT4_SB(sb)->s_jquota_fmt, type);
5551} 5574}
5552 5575
769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864
/*
 *  linux/kernel/sys.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 */

#include <linux/config.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/utsname.h>
#include <linux/mman.h>
#include <linux/smp_lock.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/prctl.h>
#include <linux/init.h>
#include <linux/highuid.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/kexec.h>
#include <linux/workqueue.h>
#include <linux/capability.h>
#include <linux/device.h>
#include <linux/key.h>
#include <linux/times.h>
#include <linux/posix-timers.h>
#include <linux/security.h>
#include <linux/dcookies.h>
#include <linux/suspend.h>
#include <linux/tty.h>
#include <linux/signal.h>
#include <linux/cn_proc.h>

#include <linux/compat.h>
#include <linux/syscalls.h>
#include <linux/kprobes.h>

#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/unistd.h>

#ifndef SET_UNALIGN_CTL
# define SET_UNALIGN_CTL(a,b)	(-EINVAL)
#endif
#ifndef GET_UNALIGN_CTL
# define GET_UNALIGN_CTL(a,b)	(-EINVAL)
#endif
#ifndef SET_FPEMU_CTL
# define SET_FPEMU_CTL(a,b)	(-EINVAL)
#endif
#ifndef GET_FPEMU_CTL
# define GET_FPEMU_CTL(a,b)	(-EINVAL)
#endif
#ifndef SET_FPEXC_CTL
# define SET_FPEXC_CTL(a,b)	(-EINVAL)
#endif
#ifndef GET_FPEXC_CTL
# define GET_FPEXC_CTL(a,b)	(-EINVAL)
#endif

/*
 * this is where the system-wide overflow UID and GID are defined, for
 * architectures that now have 32-bit UID/GID but didn't in the past
 */

int overflowuid = DEFAULT_OVERFLOWUID;
int overflowgid = DEFAULT_OVERFLOWGID;

#ifdef CONFIG_UID16
EXPORT_SYMBOL(overflowuid);
EXPORT_SYMBOL(overflowgid);
#endif

/*
 * the same as above, but for filesystems which can only store a 16-bit
 * UID and GID. as such, this is needed on all architectures
 */

int fs_overflowuid = DEFAULT_FS_OVERFLOWUID;
int fs_overflowgid = DEFAULT_FS_OVERFLOWUID;

EXPORT_SYMBOL(fs_overflowuid);
EXPORT_SYMBOL(fs_overflowgid);

/*
 * this indicates whether you can reboot with ctrl-alt-del: the default is yes
 */

int C_A_D = 1;
int cad_pid = 1;

/*
 *	Notifier list for kernel code which wants to be called
 *	at shutdown. This is used to stop any idling DMA operations
 *	and the like. 
 */

static struct notifier_block *reboot_notifier_list;
static DEFINE_RWLOCK(notifier_lock);

/**
 *	notifier_chain_register	- Add notifier to a notifier chain
 *	@list: Pointer to root list pointer
 *	@n: New entry in notifier chain
 *
 *	Adds a notifier to a notifier chain.
 *
 *	Currently always returns zero.
 */
 
int notifier_chain_register(struct notifier_block **list, struct notifier_block *n)
{
	write_lock(&notifier_lock);
	while(*list)
	{
		if(n->priority > (*list)->priority)
			break;
		list= &((*list)->next);
	}
	n->next = *list;
	*list=n;
	write_unlock(&notifier_lock);
	return 0;
}

EXPORT_SYMBOL(notifier_chain_register);

/**
 *	notifier_chain_unregister - Remove notifier from a notifier chain
 *	@nl: Pointer to root list pointer
 *	@n: New entry in notifier chain
 *
 *	Removes a notifier from a notifier chain.
 *
 *	Returns zero on success, or %-ENOENT on failure.
 */
 
int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n)
{
	write_lock(&notifier_lock);
	while((*nl)!=NULL)
	{
		if((*nl)==n)
		{
			*nl=n->next;
			write_unlock(&notifier_lock);
			return 0;
		}
		nl=&((*nl)->next);
	}
	write_unlock(&notifier_lock);
	return -ENOENT;
}

EXPORT_SYMBOL(notifier_chain_unregister);

/**
 *	notifier_call_chain - Call functions in a notifier chain
 *	@n: Pointer to root pointer of notifier chain
 *	@val: Value passed unmodified to notifier function
 *	@v: Pointer passed unmodified to notifier function
 *
 *	Calls each function in a notifier chain in turn.
 *
 *	If the return value of the notifier can be and'd
 *	with %NOTIFY_STOP_MASK, then notifier_call_chain
 *	will return immediately, with the return value of
 *	the notifier function which halted execution.
 *	Otherwise, the return value is the return value
 *	of the last notifier function called.
 */
 
int __kprobes notifier_call_chain(struct notifier_block **n, unsigned long val, void *v)
{
	int ret=NOTIFY_DONE;
	struct notifier_block *nb = *n;

	while(nb)
	{
		ret=nb->notifier_call(nb,val,v);
		if(ret&NOTIFY_STOP_MASK)
		{
			return ret;
		}
		nb=nb->next;
	}
	return ret;
}

EXPORT_SYMBOL(notifier_call_chain);

/**
 *	register_reboot_notifier - Register function to be called at reboot time
 *	@nb: Info about notifier function to be called
 *
 *	Registers a function with the list of functions
 *	to be called at reboot time.
 *
 *	Currently always returns zero, as notifier_chain_register
 *	always returns zero.
 */
 
int register_reboot_notifier(struct notifier_block * nb)
{
	return notifier_chain_register(&reboot_notifier_list, nb);
}

EXPORT_SYMBOL(register_reboot_notifier);

/**
 *	unregister_reboot_notifier - Unregister previously registered reboot notifier
 *	@nb: Hook to be unregistered
 *
 *	Unregisters a previously registered reboot
 *	notifier function.
 *
 *	Returns zero on success, or %-ENOENT on failure.
 */
 
int unregister_reboot_notifier(struct notifier_block * nb)
{
	return notifier_chain_unregister(&reboot_notifier_list, nb);
}

EXPORT_SYMBOL(unregister_reboot_notifier);

#ifndef CONFIG_SECURITY
int capable(int cap)
{
        if (cap_raised(current->cap_effective, cap)) {
	       current->flags |= PF_SUPERPRIV;
	       return 1;
        }
        return 0;
}
EXPORT_SYMBOL(capable);
#endif

static int set_one_prio(struct task_struct *p, int niceval, int error)
{
	int no_nice;

	if (p->uid != current->euid &&
		p->euid != current->euid && !capable(CAP_SYS_NICE)) {
		error = -EPERM;
		goto out;
	}
	if (niceval < task_nice(p) && !can_nice(p, niceval)) {
		error = -EACCES;
		goto out;
	}
	no_nice = security_task_setnice(p, niceval);
	if (no_nice) {
		error = no_nice;
		goto out;
	}
	if (error == -ESRCH)
		error = 0;
	set_user_nice(p, niceval);
out:
	return error;
}

asmlinkage long sys_setpriority(int which, int who, int niceval)
{
	struct task_struct *g, *p;
	struct user_struct *user;
	int error = -EINVAL;

	if (which > 2 || which < 0)
		goto out;

	/* normalize: avoid signed division (rounding problems) */
	error = -ESRCH;
	if (niceval < -20)
		niceval = -20;
	if (niceval > 19)
		niceval = 19;

	read_lock(&tasklist_lock);
	switch (which) {
		case PRIO_PROCESS:
			if (!who)
				who = current->pid;
			p = find_task_by_pid(who);
			if (p)
				error = set_one_prio(p, niceval, error);
			break;
		case PRIO_PGRP:
			if (!who)
				who = process_group(current);
			do_each_task_pid(who, PIDTYPE_PGID, p) {
				error = set_one_prio(p, niceval, error);
			} while_each_task_pid(who, PIDTYPE_PGID, p);
			break;
		case PRIO_USER:
			user = current->user;
			if (!who)
				who = current->uid;
			else
				if ((who != current->uid) && !(user = find_user(who)))
					goto out_unlock;	/* No processes for this user */

			do_each_thread(g, p)
				if (p->uid == who)
					error = set_one_prio(p, niceval, error);
			while_each_thread(g, p);
			if (who != current->uid)
				free_uid(user);		/* For find_user() */
			break;
	}
out_unlock:
	read_unlock(&tasklist_lock);
out:
	return error;
}

/*
 * Ugh. To avoid negative return values, "getpriority()" will
 * not return the normal nice-value, but a negated value that
 * has been offset by 20 (ie it returns 40..1 instead of -20..19)
 * to stay compatible.
 */
asmlinkage long sys_getpriority(int which, int who)
{
	struct task_struct *g, *p;
	struct user_struct *user;
	long niceval, retval = -ESRCH;

	if (which > 2 || which < 0)
		return -EINVAL;

	read_lock(&tasklist_lock);
	switch (which) {
		case PRIO_PROCESS:
			if (!who)
				who = current->pid;
			p = find_task_by_pid(who);
			if (p) {
				niceval = 20 - task_nice(p);
				if (niceval > retval)
					retval = niceval;
			}
			break;
		case PRIO_PGRP:
			if (!who)
				who = process_group(current);
			do_each_task_pid(who, PIDTYPE_PGID, p) {
				niceval = 20 - task_nice(p);
				if (niceval > retval)
					retval = niceval;
			} while_each_task_pid(who, PIDTYPE_PGID, p);
			break;
		case PRIO_USER:
			user = current->user;
			if (!who)
				who = current->uid;
			else
				if ((who != current->uid) && !(user = find_user(who)))
					goto out_unlock;	/* No processes for this user */

			do_each_thread(g, p)
				if (p->uid == who) {
					niceval = 20 - task_nice(p);
					if (niceval > retval)
						retval = niceval;
				}
			while_each_thread(g, p);
			if (who != current->uid)
				free_uid(user);		/* for find_user() */
			break;
	}
out_unlock:
	read_unlock(&tasklist_lock);

	return retval;
}

/**
 *	emergency_restart - reboot the system
 *
 *	Without shutting down any hardware or taking any locks
 *	reboot the system.  This is called when we know we are in
 *	trouble so this is our best effort to reboot.  This is
 *	safe to call in interrupt context.
 */
void emergency_restart(void)
{
	machine_emergency_restart();
}
EXPORT_SYMBOL_GPL(emergency_restart);

void kernel_restart_prepare(char *cmd)
{
	notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
	system_state = SYSTEM_RESTART;
	device_shutdown();
}

/**
 *	kernel_restart - reboot the system
 *	@cmd: pointer to buffer containing command to execute for restart
 *		or %NULL
 *
 *	Shutdown everything and perform a clean reboot.
 *	This is not safe to call in interrupt context.
 */
void kernel_restart(char *cmd)
{
	kernel_restart_prepare(cmd);
	if (!cmd) {
		printk(KERN_EMERG "Restarting system.\n");
	} else {
		printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd);
	}
	printk(".\n");
	machine_restart(cmd);
}
EXPORT_SYMBOL_GPL(kernel_restart);

/**
 *	kernel_kexec - reboot the system
 *
 *	Move into place and start executing a preloaded standalone
 *	executable.  If nothing was preloaded return an error.
 */
void kernel_kexec(void)
{
#ifdef CONFIG_KEXEC
	struct kimage *image;
	image = xchg(&kexec_image, NULL);
	if (!image) {
		return;
	}
	kernel_restart_prepare(NULL);
	printk(KERN_EMERG "Starting new kernel\n");
	machine_shutdown();
	machine_kexec(image);
#endif
}
EXPORT_SYMBOL_GPL(kernel_kexec);

void kernel_shutdown_prepare(enum system_states state)
{
	notifier_call_chain(&reboot_notifier_list,
		(state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL);
	system_state = state;
	device_shutdown();
}
/**
 *	kernel_halt - halt the system
 *
 *	Shutdown everything and perform a clean system halt.
 */
void kernel_halt(void)
{
	kernel_shutdown_prepare(SYSTEM_HALT);
	printk(KERN_EMERG "System halted.\n");