patch-2.4.0-test3 linux/fs/exec.c
Next file: linux/fs/ext2/fsync.c
Previous file: linux/fs/efs/symlink.c
Back to the patch index
Back to the overall index
- Lines: 188
- Date:
Wed Jul 5 11:31:01 2000
- Orig file:
v2.4.0-test2/linux/fs/exec.c
- Orig date:
Fri Jun 23 21:55:10 2000
diff -u --recursive --new-file v2.4.0-test2/linux/fs/exec.c linux/fs/exec.c
@@ -101,37 +101,52 @@
*/
asmlinkage long sys_uselib(const char * library)
{
- int fd, retval;
struct file * file;
+ struct nameidata nd;
+ int error;
- fd = sys_open(library, 0, 0);
- if (fd < 0)
- return fd;
- file = fget(fd);
- retval = -ENOEXEC;
- if (file) {
- if(file->f_op && file->f_op->read) {
- struct linux_binfmt * fmt;
+ error = user_path_walk(library, &nd);
+ if (error)
+ goto out;
+
+ error = -EINVAL;
+ if (!S_ISREG(nd.dentry->d_inode->i_mode))
+ goto exit;
+
+ error = permission(nd.dentry->d_inode, MAY_READ | MAY_EXEC);
+ if (error)
+ goto exit;
- read_lock(&binfmt_lock);
- for (fmt = formats ; fmt ; fmt = fmt->next) {
- if (!fmt->load_shlib)
- continue;
- if (!try_inc_mod_count(fmt->module))
- continue;
- read_unlock(&binfmt_lock);
- retval = fmt->load_shlib(file);
- read_lock(&binfmt_lock);
- put_binfmt(fmt);
- if (retval != -ENOEXEC)
- break;
- }
+ file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
+ error = PTR_ERR(file);
+ if (IS_ERR(file))
+ goto out;
+
+ error = -ENOEXEC;
+ if(file->f_op && file->f_op->read) {
+ struct linux_binfmt * fmt;
+
+ read_lock(&binfmt_lock);
+ for (fmt = formats ; fmt ; fmt = fmt->next) {
+ if (!fmt->load_shlib)
+ continue;
+ if (!try_inc_mod_count(fmt->module))
+ continue;
read_unlock(&binfmt_lock);
+ error = fmt->load_shlib(file);
+ read_lock(&binfmt_lock);
+ put_binfmt(fmt);
+ if (error != -ENOEXEC)
+ break;
}
- fput(file);
+ read_unlock(&binfmt_lock);
}
- sys_close(fd);
- return retval;
+ fput(file);
+out:
+ return error;
+exit:
+ path_release(&nd);
+ goto out;
}
/*
@@ -319,23 +334,28 @@
struct file *open_exec(const char *name)
{
struct nameidata nd;
+ struct inode *inode;
struct file *file;
int err = 0;
- lock_kernel();
if (path_init(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
err = path_walk(name, &nd);
- unlock_kernel();
file = ERR_PTR(err);
if (!err) {
+ inode = nd.dentry->d_inode;
file = ERR_PTR(-EACCES);
- if (S_ISREG(nd.dentry->d_inode->i_mode)) {
- int err = permission(nd.dentry->d_inode, MAY_EXEC);
+ if (!IS_NOEXEC(inode) && S_ISREG(inode->i_mode)) {
+ int err = permission(inode, MAY_EXEC);
file = ERR_PTR(err);
if (!err) {
- lock_kernel();
file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
- unlock_kernel();
+ if (!IS_ERR(file)) {
+ err = deny_write_access(file);
+ if (err) {
+ fput(file);
+ file = ERR_PTR(err);
+ }
+ }
out:
return file;
}
@@ -540,23 +560,13 @@
int prepare_binprm(struct linux_binprm *bprm)
{
int mode;
- int retval,id_change,cap_raised;
+ int id_change,cap_raised;
struct inode * inode = bprm->file->f_dentry->d_inode;
mode = inode->i_mode;
- if (!S_ISREG(mode)) /* must be regular file */
- return -EACCES;
- if (!(mode & 0111)) /* with at least _one_ execute bit set */
- return -EACCES;
- if (IS_NOEXEC(inode)) /* FS mustn't be mounted noexec */
- return -EACCES;
- if (!inode->i_sb)
+ /* Huh? We had already checked for MAY_EXEC, WTF do we check this? */
+ if (!(mode & 0111)) /* with at least _one_ execute bit set */
return -EACCES;
- if ((retval = permission(inode, MAY_EXEC)) != 0)
- return retval;
- /* better not execute files which are being written to */
- if (atomic_read(&inode->i_writecount) > 0)
- return -ETXTBSY;
bprm->e_uid = current->euid;
bprm->e_gid = current->egid;
@@ -728,6 +738,7 @@
char * dynloader[] = { "/sbin/loader" };
struct file * file;
+ allow_write_access(bprm->file);
fput(bprm->file);
bprm->file = NULL;
@@ -761,6 +772,7 @@
retval = fn(bprm, regs);
if (retval >= 0) {
put_binfmt(fmt);
+ allow_write_access(bprm->file);
if (bprm->file)
fput(bprm->file);
bprm->file = NULL;
@@ -822,11 +834,13 @@
bprm.loader = 0;
bprm.exec = 0;
if ((bprm.argc = count(argv, bprm.p / sizeof(void *))) < 0) {
+ allow_write_access(file);
fput(file);
return bprm.argc;
}
if ((bprm.envc = count(envp, bprm.p / sizeof(void *))) < 0) {
+ allow_write_access(file);
fput(file);
return bprm.envc;
}
@@ -855,6 +869,7 @@
out:
/* Something went wrong, return the inode and free the argument pages*/
+ allow_write_access(bprm.file);
if (bprm.file)
fput(bprm.file);
@@ -915,8 +930,8 @@
goto close_fail;
if (!binfmt->core_dump(signr, regs, file))
goto close_fail;
- filp_close(file, NULL);
unlock_kernel();
+ filp_close(file, NULL);
return 1;
close_fail:
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)