diff options
Diffstat (limited to 'fs/exec.c')
-rw-r--r-- | fs/exec.c | 82 |
1 files changed, 56 insertions, 26 deletions
@@ -59,10 +59,13 @@ | |||
59 | #include <asm/uaccess.h> | 59 | #include <asm/uaccess.h> |
60 | #include <asm/mmu_context.h> | 60 | #include <asm/mmu_context.h> |
61 | #include <asm/tlb.h> | 61 | #include <asm/tlb.h> |
62 | #include <asm/exec.h> | ||
62 | 63 | ||
63 | #include <trace/events/task.h> | 64 | #include <trace/events/task.h> |
64 | #include "internal.h" | 65 | #include "internal.h" |
65 | 66 | ||
67 | #include <trace/events/sched.h> | ||
68 | |||
66 | int core_uses_pid; | 69 | int core_uses_pid; |
67 | char core_pattern[CORENAME_MAX_SIZE] = "core"; | 70 | char core_pattern[CORENAME_MAX_SIZE] = "core"; |
68 | unsigned int core_pipe_limit; | 71 | unsigned int core_pipe_limit; |
@@ -79,15 +82,13 @@ static atomic_t call_count = ATOMIC_INIT(1); | |||
79 | static LIST_HEAD(formats); | 82 | static LIST_HEAD(formats); |
80 | static DEFINE_RWLOCK(binfmt_lock); | 83 | static DEFINE_RWLOCK(binfmt_lock); |
81 | 84 | ||
82 | int __register_binfmt(struct linux_binfmt * fmt, int insert) | 85 | void __register_binfmt(struct linux_binfmt * fmt, int insert) |
83 | { | 86 | { |
84 | if (!fmt) | 87 | BUG_ON(!fmt); |
85 | return -EINVAL; | ||
86 | write_lock(&binfmt_lock); | 88 | write_lock(&binfmt_lock); |
87 | insert ? list_add(&fmt->lh, &formats) : | 89 | insert ? list_add(&fmt->lh, &formats) : |
88 | list_add_tail(&fmt->lh, &formats); | 90 | list_add_tail(&fmt->lh, &formats); |
89 | write_unlock(&binfmt_lock); | 91 | write_unlock(&binfmt_lock); |
90 | return 0; | ||
91 | } | 92 | } |
92 | 93 | ||
93 | EXPORT_SYMBOL(__register_binfmt); | 94 | EXPORT_SYMBOL(__register_binfmt); |
@@ -822,7 +823,7 @@ static int exec_mmap(struct mm_struct *mm) | |||
822 | /* Notify parent that we're no longer interested in the old VM */ | 823 | /* Notify parent that we're no longer interested in the old VM */ |
823 | tsk = current; | 824 | tsk = current; |
824 | old_mm = current->mm; | 825 | old_mm = current->mm; |
825 | sync_mm_rss(tsk, old_mm); | 826 | sync_mm_rss(old_mm); |
826 | mm_release(tsk, old_mm); | 827 | mm_release(tsk, old_mm); |
827 | 828 | ||
828 | if (old_mm) { | 829 | if (old_mm) { |
@@ -848,6 +849,7 @@ static int exec_mmap(struct mm_struct *mm) | |||
848 | if (old_mm) { | 849 | if (old_mm) { |
849 | up_read(&old_mm->mmap_sem); | 850 | up_read(&old_mm->mmap_sem); |
850 | BUG_ON(active_mm != old_mm); | 851 | BUG_ON(active_mm != old_mm); |
852 | setmax_mm_hiwater_rss(&tsk->signal->maxrss, old_mm); | ||
851 | mm_update_next_owner(old_mm); | 853 | mm_update_next_owner(old_mm); |
852 | mmput(old_mm); | 854 | mmput(old_mm); |
853 | return 0; | 855 | return 0; |
@@ -975,8 +977,8 @@ static int de_thread(struct task_struct *tsk) | |||
975 | sig->notify_count = 0; | 977 | sig->notify_count = 0; |
976 | 978 | ||
977 | no_thread_group: | 979 | no_thread_group: |
978 | if (current->mm) | 980 | /* we have changed execution domain */ |
979 | setmax_mm_hiwater_rss(&sig->maxrss, current->mm); | 981 | tsk->exit_signal = SIGCHLD; |
980 | 982 | ||
981 | exit_itimers(sig); | 983 | exit_itimers(sig); |
982 | flush_itimer_signals(); | 984 | flush_itimer_signals(); |
@@ -1026,10 +1028,10 @@ static void flush_old_files(struct files_struct * files) | |||
1026 | fdt = files_fdtable(files); | 1028 | fdt = files_fdtable(files); |
1027 | if (i >= fdt->max_fds) | 1029 | if (i >= fdt->max_fds) |
1028 | break; | 1030 | break; |
1029 | set = fdt->close_on_exec->fds_bits[j]; | 1031 | set = fdt->close_on_exec[j]; |
1030 | if (!set) | 1032 | if (!set) |
1031 | continue; | 1033 | continue; |
1032 | fdt->close_on_exec->fds_bits[j] = 0; | 1034 | fdt->close_on_exec[j] = 0; |
1033 | spin_unlock(&files->file_lock); | 1035 | spin_unlock(&files->file_lock); |
1034 | for ( ; set ; i++,set >>= 1) { | 1036 | for ( ; set ; i++,set >>= 1) { |
1035 | if (set & 1) { | 1037 | if (set & 1) { |
@@ -1112,7 +1114,7 @@ int flush_old_exec(struct linux_binprm * bprm) | |||
1112 | bprm->mm = NULL; /* We're using it now */ | 1114 | bprm->mm = NULL; /* We're using it now */ |
1113 | 1115 | ||
1114 | set_fs(USER_DS); | 1116 | set_fs(USER_DS); |
1115 | current->flags &= ~(PF_RANDOMIZE | PF_KTHREAD); | 1117 | current->flags &= ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD); |
1116 | flush_thread(); | 1118 | flush_thread(); |
1117 | current->personality &= ~bprm->per_clear; | 1119 | current->personality &= ~bprm->per_clear; |
1118 | 1120 | ||
@@ -1137,7 +1139,7 @@ void setup_new_exec(struct linux_binprm * bprm) | |||
1137 | /* This is the point of no return */ | 1139 | /* This is the point of no return */ |
1138 | current->sas_ss_sp = current->sas_ss_size = 0; | 1140 | current->sas_ss_sp = current->sas_ss_size = 0; |
1139 | 1141 | ||
1140 | if (current_euid() == current_uid() && current_egid() == current_gid()) | 1142 | if (uid_eq(current_euid(), current_uid()) && gid_eq(current_egid(), current_gid())) |
1141 | set_dumpable(current->mm, 1); | 1143 | set_dumpable(current->mm, 1); |
1142 | else | 1144 | else |
1143 | set_dumpable(current->mm, suid_dumpable); | 1145 | set_dumpable(current->mm, suid_dumpable); |
@@ -1151,8 +1153,8 @@ void setup_new_exec(struct linux_binprm * bprm) | |||
1151 | current->mm->task_size = TASK_SIZE; | 1153 | current->mm->task_size = TASK_SIZE; |
1152 | 1154 | ||
1153 | /* install the new credentials */ | 1155 | /* install the new credentials */ |
1154 | if (bprm->cred->uid != current_euid() || | 1156 | if (!uid_eq(bprm->cred->uid, current_euid()) || |
1155 | bprm->cred->gid != current_egid()) { | 1157 | !gid_eq(bprm->cred->gid, current_egid())) { |
1156 | current->pdeath_signal = 0; | 1158 | current->pdeath_signal = 0; |
1157 | } else { | 1159 | } else { |
1158 | would_dump(bprm, bprm->file); | 1160 | would_dump(bprm, bprm->file); |
@@ -1243,6 +1245,13 @@ static int check_unsafe_exec(struct linux_binprm *bprm) | |||
1243 | bprm->unsafe |= LSM_UNSAFE_PTRACE; | 1245 | bprm->unsafe |= LSM_UNSAFE_PTRACE; |
1244 | } | 1246 | } |
1245 | 1247 | ||
1248 | /* | ||
1249 | * This isn't strictly necessary, but it makes it harder for LSMs to | ||
1250 | * mess up. | ||
1251 | */ | ||
1252 | if (current->no_new_privs) | ||
1253 | bprm->unsafe |= LSM_UNSAFE_NO_NEW_PRIVS; | ||
1254 | |||
1246 | n_fs = 1; | 1255 | n_fs = 1; |
1247 | spin_lock(&p->fs->lock); | 1256 | spin_lock(&p->fs->lock); |
1248 | rcu_read_lock(); | 1257 | rcu_read_lock(); |
@@ -1286,11 +1295,15 @@ int prepare_binprm(struct linux_binprm *bprm) | |||
1286 | bprm->cred->euid = current_euid(); | 1295 | bprm->cred->euid = current_euid(); |
1287 | bprm->cred->egid = current_egid(); | 1296 | bprm->cred->egid = current_egid(); |
1288 | 1297 | ||
1289 | if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) { | 1298 | if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) && |
1299 | !current->no_new_privs) { | ||
1290 | /* Set-uid? */ | 1300 | /* Set-uid? */ |
1291 | if (mode & S_ISUID) { | 1301 | if (mode & S_ISUID) { |
1302 | if (!kuid_has_mapping(bprm->cred->user_ns, inode->i_uid)) | ||
1303 | return -EPERM; | ||
1292 | bprm->per_clear |= PER_CLEAR_ON_SETID; | 1304 | bprm->per_clear |= PER_CLEAR_ON_SETID; |
1293 | bprm->cred->euid = inode->i_uid; | 1305 | bprm->cred->euid = inode->i_uid; |
1306 | |||
1294 | } | 1307 | } |
1295 | 1308 | ||
1296 | /* Set-gid? */ | 1309 | /* Set-gid? */ |
@@ -1300,6 +1313,8 @@ int prepare_binprm(struct linux_binprm *bprm) | |||
1300 | * executable. | 1313 | * executable. |
1301 | */ | 1314 | */ |
1302 | if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { | 1315 | if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { |
1316 | if (!kgid_has_mapping(bprm->cred->user_ns, inode->i_gid)) | ||
1317 | return -EPERM; | ||
1303 | bprm->per_clear |= PER_CLEAR_ON_SETID; | 1318 | bprm->per_clear |= PER_CLEAR_ON_SETID; |
1304 | bprm->cred->egid = inode->i_gid; | 1319 | bprm->cred->egid = inode->i_gid; |
1305 | } | 1320 | } |
@@ -1339,13 +1354,13 @@ int remove_arg_zero(struct linux_binprm *bprm) | |||
1339 | ret = -EFAULT; | 1354 | ret = -EFAULT; |
1340 | goto out; | 1355 | goto out; |
1341 | } | 1356 | } |
1342 | kaddr = kmap_atomic(page, KM_USER0); | 1357 | kaddr = kmap_atomic(page); |
1343 | 1358 | ||
1344 | for (; offset < PAGE_SIZE && kaddr[offset]; | 1359 | for (; offset < PAGE_SIZE && kaddr[offset]; |
1345 | offset++, bprm->p++) | 1360 | offset++, bprm->p++) |
1346 | ; | 1361 | ; |
1347 | 1362 | ||
1348 | kunmap_atomic(kaddr, KM_USER0); | 1363 | kunmap_atomic(kaddr); |
1349 | put_arg_page(page); | 1364 | put_arg_page(page); |
1350 | 1365 | ||
1351 | if (offset == PAGE_SIZE) | 1366 | if (offset == PAGE_SIZE) |
@@ -1369,7 +1384,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) | |||
1369 | unsigned int depth = bprm->recursion_depth; | 1384 | unsigned int depth = bprm->recursion_depth; |
1370 | int try,retval; | 1385 | int try,retval; |
1371 | struct linux_binfmt *fmt; | 1386 | struct linux_binfmt *fmt; |
1372 | pid_t old_pid; | 1387 | pid_t old_pid, old_vpid; |
1373 | 1388 | ||
1374 | retval = security_bprm_check(bprm); | 1389 | retval = security_bprm_check(bprm); |
1375 | if (retval) | 1390 | if (retval) |
@@ -1380,8 +1395,9 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) | |||
1380 | return retval; | 1395 | return retval; |
1381 | 1396 | ||
1382 | /* Need to fetch pid before load_binary changes it */ | 1397 | /* Need to fetch pid before load_binary changes it */ |
1398 | old_pid = current->pid; | ||
1383 | rcu_read_lock(); | 1399 | rcu_read_lock(); |
1384 | old_pid = task_pid_nr_ns(current, task_active_pid_ns(current->parent)); | 1400 | old_vpid = task_pid_nr_ns(current, task_active_pid_ns(current->parent)); |
1385 | rcu_read_unlock(); | 1401 | rcu_read_unlock(); |
1386 | 1402 | ||
1387 | retval = -ENOENT; | 1403 | retval = -ENOENT; |
@@ -1402,9 +1418,10 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) | |||
1402 | */ | 1418 | */ |
1403 | bprm->recursion_depth = depth; | 1419 | bprm->recursion_depth = depth; |
1404 | if (retval >= 0) { | 1420 | if (retval >= 0) { |
1405 | if (depth == 0) | 1421 | if (depth == 0) { |
1406 | ptrace_event(PTRACE_EVENT_EXEC, | 1422 | trace_sched_process_exec(current, old_pid, bprm); |
1407 | old_pid); | 1423 | ptrace_event(PTRACE_EVENT_EXEC, old_vpid); |
1424 | } | ||
1408 | put_binfmt(fmt); | 1425 | put_binfmt(fmt); |
1409 | allow_write_access(bprm->file); | 1426 | allow_write_access(bprm->file); |
1410 | if (bprm->file) | 1427 | if (bprm->file) |
@@ -1926,8 +1943,21 @@ static int coredump_wait(int exit_code, struct core_state *core_state) | |||
1926 | core_waiters = zap_threads(tsk, mm, core_state, exit_code); | 1943 | core_waiters = zap_threads(tsk, mm, core_state, exit_code); |
1927 | up_write(&mm->mmap_sem); | 1944 | up_write(&mm->mmap_sem); |
1928 | 1945 | ||
1929 | if (core_waiters > 0) | 1946 | if (core_waiters > 0) { |
1947 | struct core_thread *ptr; | ||
1948 | |||
1930 | wait_for_completion(&core_state->startup); | 1949 | wait_for_completion(&core_state->startup); |
1950 | /* | ||
1951 | * Wait for all the threads to become inactive, so that | ||
1952 | * all the thread context (extended register state, like | ||
1953 | * fpu etc) gets copied to the memory. | ||
1954 | */ | ||
1955 | ptr = core_state->dumper.next; | ||
1956 | while (ptr != NULL) { | ||
1957 | wait_task_inactive(ptr->task, 0); | ||
1958 | ptr = ptr->next; | ||
1959 | } | ||
1960 | } | ||
1931 | 1961 | ||
1932 | return core_waiters; | 1962 | return core_waiters; |
1933 | } | 1963 | } |
@@ -2064,8 +2094,8 @@ static int umh_pipe_setup(struct subprocess_info *info, struct cred *new) | |||
2064 | fd_install(0, rp); | 2094 | fd_install(0, rp); |
2065 | spin_lock(&cf->file_lock); | 2095 | spin_lock(&cf->file_lock); |
2066 | fdt = files_fdtable(cf); | 2096 | fdt = files_fdtable(cf); |
2067 | FD_SET(0, fdt->open_fds); | 2097 | __set_open_fd(0, fdt); |
2068 | FD_CLR(0, fdt->close_on_exec); | 2098 | __clear_close_on_exec(0, fdt); |
2069 | spin_unlock(&cf->file_lock); | 2099 | spin_unlock(&cf->file_lock); |
2070 | 2100 | ||
2071 | /* and disallow core files too */ | 2101 | /* and disallow core files too */ |
@@ -2117,7 +2147,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
2117 | if (__get_dumpable(cprm.mm_flags) == 2) { | 2147 | if (__get_dumpable(cprm.mm_flags) == 2) { |
2118 | /* Setuid core dump mode */ | 2148 | /* Setuid core dump mode */ |
2119 | flag = O_EXCL; /* Stop rewrite attacks */ | 2149 | flag = O_EXCL; /* Stop rewrite attacks */ |
2120 | cred->fsuid = 0; /* Dump root private */ | 2150 | cred->fsuid = GLOBAL_ROOT_UID; /* Dump root private */ |
2121 | } | 2151 | } |
2122 | 2152 | ||
2123 | retval = coredump_wait(exit_code, &core_state); | 2153 | retval = coredump_wait(exit_code, &core_state); |
@@ -2218,7 +2248,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
2218 | * Dont allow local users get cute and trick others to coredump | 2248 | * Dont allow local users get cute and trick others to coredump |
2219 | * into their pre-created files. | 2249 | * into their pre-created files. |
2220 | */ | 2250 | */ |
2221 | if (inode->i_uid != current_fsuid()) | 2251 | if (!uid_eq(inode->i_uid, current_fsuid())) |
2222 | goto close_fail; | 2252 | goto close_fail; |
2223 | if (!cprm.file->f_op || !cprm.file->f_op->write) | 2253 | if (!cprm.file->f_op || !cprm.file->f_op->write) |
2224 | goto close_fail; | 2254 | goto close_fail; |