From 44c4fb8925b008621aeb9e7758c4777d5a956a5c Mon Sep 17 00:00:00 2001 From: Seth Rohit Date: Mon, 18 Oct 2004 08:52:07 -0700 Subject: [PATCH] [PATCH] add sys_setaltroot() Add a new system call setaltroot(2). Currently, using the altroot feature is accessible only via the set_personality() system call. It is accessible to user space only if there is more than one exec domain in the system. This patch allows using the altroot feature on systems where there is only one exec domain. It is possible to work around the issue by adding a dummy exec domain, but it was rejected for not being very elegant. If this feature is implemented in userspace, it adds a 16% overhead on a test case which greps for a single word in the kernel source tree. Signed-off-by: Zou Nanhai Signed-off-by: Gordon Jin Signed-off-by: Arun Sharma Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/entry.S | 1 + arch/ia64/kernel/entry.S | 2 +- fs/namei.c | 62 +++++++++++++++++++++++++++++++++++---- include/asm-i386/unistd.h | 3 +- include/asm-ia64/unistd.h | 1 + include/linux/syscalls.h | 1 + 6 files changed, 63 insertions(+), 7 deletions(-) diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index 3a8c31eda60d8..5c1f205e589bd 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -901,5 +901,6 @@ ENTRY(sys_call_table) .long sys_mq_getsetattr .long sys_ni_syscall /* reserved for kexec */ .long sys_waitid + .long sys_setaltroot syscall_table_size=(.-sys_call_table) diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 1fe9575c7f7b5..f9f71a58814b6 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -1527,7 +1527,7 @@ sys_call_table: data8 sys_mq_getsetattr data8 sys_ni_syscall // reserved for kexec_load data8 sys_ni_syscall - data8 sys_ni_syscall // 1270 + data8 sys_setaltroot // 1270 data8 sys_ni_syscall data8 sys_ni_syscall data8 sys_ni_syscall diff --git a/fs/namei.c b/fs/namei.c index 0a7647e41d9e6..32244e239583f 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -897,20 +897,20 @@ static int __emul_lookup_dentry(const char *name, struct nameidata *nd) return 1; } -void set_fs_altroot(void) +int __set_fs_altroot(const char *altroot) { - char *emul = __emul_prefix(); struct nameidata nd; struct vfsmount *mnt = NULL, *oldmnt; struct dentry *dentry = NULL, *olddentry; int err; - - if (!emul) + if (!altroot) goto set_it; - err = path_lookup(emul, LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_NOALT, &nd); + err = path_lookup(altroot, LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_NOALT, &nd); if (!err) { mnt = nd.mnt; dentry = nd.dentry; + } else { + return err; } set_it: write_lock(¤t->fs->lock); @@ -923,6 +923,58 @@ set_it: dput(olddentry); mntput(oldmnt); } + return 0; +} + +void set_fs_altroot() +{ + char *emul = __emul_prefix(); + + __set_fs_altroot(emul); +} + +asmlinkage long sys_setaltroot(const char __user * altroot) +{ + char *emul = NULL; + int ret; + + if (altroot) { + emul = getname(altroot); + if (IS_ERR(emul)) { + ret = PTR_ERR(emul); + goto out; + } + } + + if (atomic_read(¤t->fs->count) != 1) { + struct fs_struct *fsp, *ofsp; + + fsp = copy_fs_struct(current->fs); + if (fsp == NULL) { + ret = -ENOMEM; + goto out_putname; + } + + task_lock(current); + ofsp = current->fs; + current->fs = fsp; + task_unlock(current); + + put_fs_struct(ofsp); + } + + /* + * At that point we are guaranteed to be the sole owner of + * current->fs. + */ + + ret = __set_fs_altroot(emul); + +out_putname: + if (emul) + putname(emul); +out: + return ret; } int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata *nd) diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index be8c6ac56c7c5..2d9e45d2d5f89 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h @@ -290,8 +290,9 @@ #define __NR_mq_getsetattr (__NR_mq_open+5) #define __NR_sys_kexec_load 283 #define __NR_waitid 284 +#define __NR_sys_setaltroot 285 -#define NR_syscalls 285 +#define NR_syscalls 286 /* user-visible error numbers are in the range -1 - -124: see */ diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h index 84e6989d6ea0f..6384693300fd5 100644 --- a/include/asm-ia64/unistd.h +++ b/include/asm-ia64/unistd.h @@ -259,6 +259,7 @@ #define __NR_mq_getsetattr 1267 #define __NR_kexec_load 1268 #define __NR_vserver 1269 +#define __NR_setaltroot 1270 #ifdef __KERNEL__ diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index bd26cf298d9a9..2a8c7faf2dcc6 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -489,6 +489,7 @@ asmlinkage long sys_nfsservctl(int cmd, void __user *res); asmlinkage long sys_syslog(int type, char __user *buf, int len); asmlinkage long sys_uselib(const char __user *library); +asmlinkage long sys_setaltroot(const char __user *altroot); asmlinkage long sys_ni_syscall(void); #endif -- 2.53.0