diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/compat.c | 14 | ||||
| -rw-r--r-- | fs/exec.c | 10 | ||||
| -rw-r--r-- | fs/internal.h | 2 | ||||
| -rw-r--r-- | fs/proc/base.c | 50 |
4 files changed, 32 insertions, 44 deletions
diff --git a/fs/compat.c b/fs/compat.c index 5e374aad33f7..55efdfebdf5a 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
| @@ -1420,12 +1420,17 @@ int compat_do_execve(char * filename, | |||
| 1420 | { | 1420 | { |
| 1421 | struct linux_binprm *bprm; | 1421 | struct linux_binprm *bprm; |
| 1422 | struct file *file; | 1422 | struct file *file; |
| 1423 | struct files_struct *displaced; | ||
| 1423 | int retval; | 1424 | int retval; |
| 1424 | 1425 | ||
| 1426 | retval = unshare_files(&displaced); | ||
| 1427 | if (retval) | ||
| 1428 | goto out_ret; | ||
| 1429 | |||
| 1425 | retval = -ENOMEM; | 1430 | retval = -ENOMEM; |
| 1426 | bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); | 1431 | bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); |
| 1427 | if (!bprm) | 1432 | if (!bprm) |
| 1428 | goto out_ret; | 1433 | goto out_files; |
| 1429 | 1434 | ||
| 1430 | retval = mutex_lock_interruptible(¤t->cred_exec_mutex); | 1435 | retval = mutex_lock_interruptible(¤t->cred_exec_mutex); |
| 1431 | if (retval < 0) | 1436 | if (retval < 0) |
| @@ -1436,7 +1441,7 @@ int compat_do_execve(char * filename, | |||
| 1436 | bprm->cred = prepare_exec_creds(); | 1441 | bprm->cred = prepare_exec_creds(); |
| 1437 | if (!bprm->cred) | 1442 | if (!bprm->cred) |
| 1438 | goto out_unlock; | 1443 | goto out_unlock; |
| 1439 | check_unsafe_exec(bprm, current->files); | 1444 | check_unsafe_exec(bprm); |
| 1440 | 1445 | ||
| 1441 | file = open_exec(filename); | 1446 | file = open_exec(filename); |
| 1442 | retval = PTR_ERR(file); | 1447 | retval = PTR_ERR(file); |
| @@ -1487,6 +1492,8 @@ int compat_do_execve(char * filename, | |||
| 1487 | mutex_unlock(¤t->cred_exec_mutex); | 1492 | mutex_unlock(¤t->cred_exec_mutex); |
| 1488 | acct_update_integrals(current); | 1493 | acct_update_integrals(current); |
| 1489 | free_bprm(bprm); | 1494 | free_bprm(bprm); |
| 1495 | if (displaced) | ||
| 1496 | put_files_struct(displaced); | ||
| 1490 | return retval; | 1497 | return retval; |
| 1491 | 1498 | ||
| 1492 | out: | 1499 | out: |
| @@ -1506,6 +1513,9 @@ out_unlock: | |||
| 1506 | out_free: | 1513 | out_free: |
| 1507 | free_bprm(bprm); | 1514 | free_bprm(bprm); |
| 1508 | 1515 | ||
| 1516 | out_files: | ||
| 1517 | if (displaced) | ||
| 1518 | reset_files_struct(displaced); | ||
| 1509 | out_ret: | 1519 | out_ret: |
| 1510 | return retval; | 1520 | return retval; |
| 1511 | } | 1521 | } |
| @@ -1056,28 +1056,24 @@ EXPORT_SYMBOL(install_exec_creds); | |||
| 1056 | * - the caller must hold current->cred_exec_mutex to protect against | 1056 | * - the caller must hold current->cred_exec_mutex to protect against |
| 1057 | * PTRACE_ATTACH | 1057 | * PTRACE_ATTACH |
| 1058 | */ | 1058 | */ |
| 1059 | void check_unsafe_exec(struct linux_binprm *bprm, struct files_struct *files) | 1059 | void check_unsafe_exec(struct linux_binprm *bprm) |
| 1060 | { | 1060 | { |
| 1061 | struct task_struct *p = current, *t; | 1061 | struct task_struct *p = current, *t; |
| 1062 | unsigned long flags; | 1062 | unsigned long flags; |
| 1063 | unsigned n_fs, n_files, n_sighand; | 1063 | unsigned n_fs, n_sighand; |
| 1064 | 1064 | ||
| 1065 | bprm->unsafe = tracehook_unsafe_exec(p); | 1065 | bprm->unsafe = tracehook_unsafe_exec(p); |
| 1066 | 1066 | ||
| 1067 | n_fs = 1; | 1067 | n_fs = 1; |
| 1068 | n_files = 1; | ||
| 1069 | n_sighand = 1; | 1068 | n_sighand = 1; |
| 1070 | lock_task_sighand(p, &flags); | 1069 | lock_task_sighand(p, &flags); |
| 1071 | for (t = next_thread(p); t != p; t = next_thread(t)) { | 1070 | for (t = next_thread(p); t != p; t = next_thread(t)) { |
| 1072 | if (t->fs == p->fs) | 1071 | if (t->fs == p->fs) |
| 1073 | n_fs++; | 1072 | n_fs++; |
| 1074 | if (t->files == files) | ||
| 1075 | n_files++; | ||
| 1076 | n_sighand++; | 1073 | n_sighand++; |
| 1077 | } | 1074 | } |
| 1078 | 1075 | ||
| 1079 | if (atomic_read(&p->fs->count) > n_fs || | 1076 | if (atomic_read(&p->fs->count) > n_fs || |
| 1080 | atomic_read(&p->files->count) > n_files || | ||
| 1081 | atomic_read(&p->sighand->count) > n_sighand) | 1077 | atomic_read(&p->sighand->count) > n_sighand) |
| 1082 | bprm->unsafe |= LSM_UNSAFE_SHARE; | 1078 | bprm->unsafe |= LSM_UNSAFE_SHARE; |
| 1083 | 1079 | ||
| @@ -1300,7 +1296,7 @@ int do_execve(char * filename, | |||
| 1300 | bprm->cred = prepare_exec_creds(); | 1296 | bprm->cred = prepare_exec_creds(); |
| 1301 | if (!bprm->cred) | 1297 | if (!bprm->cred) |
| 1302 | goto out_unlock; | 1298 | goto out_unlock; |
| 1303 | check_unsafe_exec(bprm, displaced); | 1299 | check_unsafe_exec(bprm); |
| 1304 | 1300 | ||
| 1305 | file = open_exec(filename); | 1301 | file = open_exec(filename); |
| 1306 | retval = PTR_ERR(file); | 1302 | retval = PTR_ERR(file); |
diff --git a/fs/internal.h b/fs/internal.h index 0d8ac497b3d5..53af885f1732 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
| @@ -43,7 +43,7 @@ extern void __init chrdev_init(void); | |||
| 43 | /* | 43 | /* |
| 44 | * exec.c | 44 | * exec.c |
| 45 | */ | 45 | */ |
| 46 | extern void check_unsafe_exec(struct linux_binprm *, struct files_struct *); | 46 | extern void check_unsafe_exec(struct linux_binprm *); |
| 47 | 47 | ||
| 48 | /* | 48 | /* |
| 49 | * namespace.c | 49 | * namespace.c |
diff --git a/fs/proc/base.c b/fs/proc/base.c index aef6d55b7de6..e0afd326b688 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
| @@ -146,15 +146,22 @@ static unsigned int pid_entry_count_dirs(const struct pid_entry *entries, | |||
| 146 | return count; | 146 | return count; |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | static struct fs_struct *get_fs_struct(struct task_struct *task) | 149 | static int get_fs_path(struct task_struct *task, struct path *path, bool root) |
| 150 | { | 150 | { |
| 151 | struct fs_struct *fs; | 151 | struct fs_struct *fs; |
| 152 | int result = -ENOENT; | ||
| 153 | |||
| 152 | task_lock(task); | 154 | task_lock(task); |
| 153 | fs = task->fs; | 155 | fs = task->fs; |
| 154 | if(fs) | 156 | if (fs) { |
| 155 | atomic_inc(&fs->count); | 157 | read_lock(&fs->lock); |
| 158 | *path = root ? fs->root : fs->pwd; | ||
| 159 | path_get(path); | ||
| 160 | read_unlock(&fs->lock); | ||
| 161 | result = 0; | ||
| 162 | } | ||
| 156 | task_unlock(task); | 163 | task_unlock(task); |
| 157 | return fs; | 164 | return result; |
| 158 | } | 165 | } |
| 159 | 166 | ||
| 160 | static int get_nr_threads(struct task_struct *tsk) | 167 | static int get_nr_threads(struct task_struct *tsk) |
| @@ -172,42 +179,24 @@ static int get_nr_threads(struct task_struct *tsk) | |||
| 172 | static int proc_cwd_link(struct inode *inode, struct path *path) | 179 | static int proc_cwd_link(struct inode *inode, struct path *path) |
| 173 | { | 180 | { |
| 174 | struct task_struct *task = get_proc_task(inode); | 181 | struct task_struct *task = get_proc_task(inode); |
| 175 | struct fs_struct *fs = NULL; | ||
| 176 | int result = -ENOENT; | 182 | int result = -ENOENT; |
| 177 | 183 | ||
| 178 | if (task) { | 184 | if (task) { |
| 179 | fs = get_fs_struct(task); | 185 | result = get_fs_path(task, path, 0); |
| 180 | put_task_struct(task); | 186 | put_task_struct(task); |
| 181 | } | 187 | } |
| 182 | if (fs) { | ||
| 183 | read_lock(&fs->lock); | ||
| 184 | *path = fs->pwd; | ||
| 185 | path_get(&fs->pwd); | ||
| 186 | read_unlock(&fs->lock); | ||
| 187 | result = 0; | ||
| 188 | put_fs_struct(fs); | ||
| 189 | } | ||
| 190 | return result; | 188 | return result; |
| 191 | } | 189 | } |
| 192 | 190 | ||
| 193 | static int proc_root_link(struct inode *inode, struct path *path) | 191 | static int proc_root_link(struct inode *inode, struct path *path) |
| 194 | { | 192 | { |
| 195 | struct task_struct *task = get_proc_task(inode); | 193 | struct task_struct *task = get_proc_task(inode); |
| 196 | struct fs_struct *fs = NULL; | ||
| 197 | int result = -ENOENT; | 194 | int result = -ENOENT; |
| 198 | 195 | ||
| 199 | if (task) { | 196 | if (task) { |
| 200 | fs = get_fs_struct(task); | 197 | result = get_fs_path(task, path, 1); |
| 201 | put_task_struct(task); | 198 | put_task_struct(task); |
| 202 | } | 199 | } |
| 203 | if (fs) { | ||
| 204 | read_lock(&fs->lock); | ||
| 205 | *path = fs->root; | ||
| 206 | path_get(&fs->root); | ||
| 207 | read_unlock(&fs->lock); | ||
| 208 | result = 0; | ||
| 209 | put_fs_struct(fs); | ||
| 210 | } | ||
| 211 | return result; | 200 | return result; |
| 212 | } | 201 | } |
| 213 | 202 | ||
| @@ -596,7 +585,6 @@ static int mounts_open_common(struct inode *inode, struct file *file, | |||
| 596 | struct task_struct *task = get_proc_task(inode); | 585 | struct task_struct *task = get_proc_task(inode); |
| 597 | struct nsproxy *nsp; | 586 | struct nsproxy *nsp; |
| 598 | struct mnt_namespace *ns = NULL; | 587 | struct mnt_namespace *ns = NULL; |
| 599 | struct fs_struct *fs = NULL; | ||
| 600 | struct path root; | 588 | struct path root; |
| 601 | struct proc_mounts *p; | 589 | struct proc_mounts *p; |
| 602 | int ret = -EINVAL; | 590 | int ret = -EINVAL; |
| @@ -610,22 +598,16 @@ static int mounts_open_common(struct inode *inode, struct file *file, | |||
| 610 | get_mnt_ns(ns); | 598 | get_mnt_ns(ns); |
| 611 | } | 599 | } |
| 612 | rcu_read_unlock(); | 600 | rcu_read_unlock(); |
| 613 | if (ns) | 601 | if (ns && get_fs_path(task, &root, 1) == 0) |
| 614 | fs = get_fs_struct(task); | 602 | ret = 0; |
| 615 | put_task_struct(task); | 603 | put_task_struct(task); |
| 616 | } | 604 | } |
| 617 | 605 | ||
| 618 | if (!ns) | 606 | if (!ns) |
| 619 | goto err; | 607 | goto err; |
| 620 | if (!fs) | 608 | if (ret) |
| 621 | goto err_put_ns; | 609 | goto err_put_ns; |
| 622 | 610 | ||
| 623 | read_lock(&fs->lock); | ||
| 624 | root = fs->root; | ||
| 625 | path_get(&root); | ||
| 626 | read_unlock(&fs->lock); | ||
| 627 | put_fs_struct(fs); | ||
| 628 | |||
| 629 | ret = -ENOMEM; | 611 | ret = -ENOMEM; |
| 630 | p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); | 612 | p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); |
| 631 | if (!p) | 613 | if (!p) |
