diff options
Diffstat (limited to 'fs/exec.c')
-rw-r--r-- | fs/exec.c | 183 |
1 files changed, 109 insertions, 74 deletions
@@ -56,6 +56,7 @@ | |||
56 | #include <asm/uaccess.h> | 56 | #include <asm/uaccess.h> |
57 | #include <asm/mmu_context.h> | 57 | #include <asm/mmu_context.h> |
58 | #include <asm/tlb.h> | 58 | #include <asm/tlb.h> |
59 | #include "internal.h" | ||
59 | 60 | ||
60 | #ifdef __alpha__ | 61 | #ifdef __alpha__ |
61 | /* for /sbin/loader handling in search_binary_handler() */ | 62 | /* for /sbin/loader handling in search_binary_handler() */ |
@@ -981,7 +982,7 @@ int flush_old_exec(struct linux_binprm * bprm) | |||
981 | /* This is the point of no return */ | 982 | /* This is the point of no return */ |
982 | current->sas_ss_sp = current->sas_ss_size = 0; | 983 | current->sas_ss_sp = current->sas_ss_size = 0; |
983 | 984 | ||
984 | if (current->euid == current->uid && current->egid == current->gid) | 985 | if (current_euid() == current_uid() && current_egid() == current_gid()) |
985 | set_dumpable(current->mm, 1); | 986 | set_dumpable(current->mm, 1); |
986 | else | 987 | else |
987 | set_dumpable(current->mm, suid_dumpable); | 988 | set_dumpable(current->mm, suid_dumpable); |
@@ -1008,16 +1009,17 @@ int flush_old_exec(struct linux_binprm * bprm) | |||
1008 | */ | 1009 | */ |
1009 | current->mm->task_size = TASK_SIZE; | 1010 | current->mm->task_size = TASK_SIZE; |
1010 | 1011 | ||
1011 | if (bprm->e_uid != current->euid || bprm->e_gid != current->egid) { | 1012 | /* install the new credentials */ |
1012 | suid_keys(current); | 1013 | if (bprm->cred->uid != current_euid() || |
1013 | set_dumpable(current->mm, suid_dumpable); | 1014 | bprm->cred->gid != current_egid()) { |
1014 | current->pdeath_signal = 0; | 1015 | current->pdeath_signal = 0; |
1015 | } else if (file_permission(bprm->file, MAY_READ) || | 1016 | } else if (file_permission(bprm->file, MAY_READ) || |
1016 | (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) { | 1017 | bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) { |
1017 | suid_keys(current); | ||
1018 | set_dumpable(current->mm, suid_dumpable); | 1018 | set_dumpable(current->mm, suid_dumpable); |
1019 | } | 1019 | } |
1020 | 1020 | ||
1021 | current->personality &= ~bprm->per_clear; | ||
1022 | |||
1021 | /* | 1023 | /* |
1022 | * Flush performance counters when crossing a | 1024 | * Flush performance counters when crossing a |
1023 | * security domain: | 1025 | * security domain: |
@@ -1041,13 +1043,50 @@ out: | |||
1041 | 1043 | ||
1042 | EXPORT_SYMBOL(flush_old_exec); | 1044 | EXPORT_SYMBOL(flush_old_exec); |
1043 | 1045 | ||
1046 | /* | ||
1047 | * install the new credentials for this executable | ||
1048 | */ | ||
1049 | void install_exec_creds(struct linux_binprm *bprm) | ||
1050 | { | ||
1051 | security_bprm_committing_creds(bprm); | ||
1052 | |||
1053 | commit_creds(bprm->cred); | ||
1054 | bprm->cred = NULL; | ||
1055 | |||
1056 | /* cred_exec_mutex must be held at least to this point to prevent | ||
1057 | * ptrace_attach() from altering our determination of the task's | ||
1058 | * credentials; any time after this it may be unlocked */ | ||
1059 | |||
1060 | security_bprm_committed_creds(bprm); | ||
1061 | } | ||
1062 | EXPORT_SYMBOL(install_exec_creds); | ||
1063 | |||
1064 | /* | ||
1065 | * determine how safe it is to execute the proposed program | ||
1066 | * - the caller must hold current->cred_exec_mutex to protect against | ||
1067 | * PTRACE_ATTACH | ||
1068 | */ | ||
1069 | void check_unsafe_exec(struct linux_binprm *bprm) | ||
1070 | { | ||
1071 | struct task_struct *p = current; | ||
1072 | |||
1073 | bprm->unsafe = tracehook_unsafe_exec(p); | ||
1074 | |||
1075 | if (atomic_read(&p->fs->count) > 1 || | ||
1076 | atomic_read(&p->files->count) > 1 || | ||
1077 | atomic_read(&p->sighand->count) > 1) | ||
1078 | bprm->unsafe |= LSM_UNSAFE_SHARE; | ||
1079 | } | ||
1080 | |||
1044 | /* | 1081 | /* |
1045 | * Fill the binprm structure from the inode. | 1082 | * Fill the binprm structure from the inode. |
1046 | * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes | 1083 | * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes |
1084 | * | ||
1085 | * This may be called multiple times for binary chains (scripts for example). | ||
1047 | */ | 1086 | */ |
1048 | int prepare_binprm(struct linux_binprm *bprm) | 1087 | int prepare_binprm(struct linux_binprm *bprm) |
1049 | { | 1088 | { |
1050 | int mode; | 1089 | umode_t mode; |
1051 | struct inode * inode = bprm->file->f_path.dentry->d_inode; | 1090 | struct inode * inode = bprm->file->f_path.dentry->d_inode; |
1052 | int retval; | 1091 | int retval; |
1053 | 1092 | ||
@@ -1055,14 +1094,15 @@ int prepare_binprm(struct linux_binprm *bprm) | |||
1055 | if (bprm->file->f_op == NULL) | 1094 | if (bprm->file->f_op == NULL) |
1056 | return -EACCES; | 1095 | return -EACCES; |
1057 | 1096 | ||
1058 | bprm->e_uid = current->euid; | 1097 | /* clear any previous set[ug]id data from a previous binary */ |
1059 | bprm->e_gid = current->egid; | 1098 | bprm->cred->euid = current_euid(); |
1099 | bprm->cred->egid = current_egid(); | ||
1060 | 1100 | ||
1061 | if(!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) { | 1101 | if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) { |
1062 | /* Set-uid? */ | 1102 | /* Set-uid? */ |
1063 | if (mode & S_ISUID) { | 1103 | if (mode & S_ISUID) { |
1064 | current->personality &= ~PER_CLEAR_ON_SETID; | 1104 | bprm->per_clear |= PER_CLEAR_ON_SETID; |
1065 | bprm->e_uid = inode->i_uid; | 1105 | bprm->cred->euid = inode->i_uid; |
1066 | } | 1106 | } |
1067 | 1107 | ||
1068 | /* Set-gid? */ | 1108 | /* Set-gid? */ |
@@ -1072,52 +1112,23 @@ int prepare_binprm(struct linux_binprm *bprm) | |||
1072 | * executable. | 1112 | * executable. |
1073 | */ | 1113 | */ |
1074 | if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { | 1114 | if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { |
1075 | current->personality &= ~PER_CLEAR_ON_SETID; | 1115 | bprm->per_clear |= PER_CLEAR_ON_SETID; |
1076 | bprm->e_gid = inode->i_gid; | 1116 | bprm->cred->egid = inode->i_gid; |
1077 | } | 1117 | } |
1078 | } | 1118 | } |
1079 | 1119 | ||
1080 | /* fill in binprm security blob */ | 1120 | /* fill in binprm security blob */ |
1081 | retval = security_bprm_set(bprm); | 1121 | retval = security_bprm_set_creds(bprm); |
1082 | if (retval) | 1122 | if (retval) |
1083 | return retval; | 1123 | return retval; |
1124 | bprm->cred_prepared = 1; | ||
1084 | 1125 | ||
1085 | memset(bprm->buf,0,BINPRM_BUF_SIZE); | 1126 | memset(bprm->buf, 0, BINPRM_BUF_SIZE); |
1086 | return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE); | 1127 | return kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE); |
1087 | } | 1128 | } |
1088 | 1129 | ||
1089 | EXPORT_SYMBOL(prepare_binprm); | 1130 | EXPORT_SYMBOL(prepare_binprm); |
1090 | 1131 | ||
1091 | static int unsafe_exec(struct task_struct *p) | ||
1092 | { | ||
1093 | int unsafe = tracehook_unsafe_exec(p); | ||
1094 | |||
1095 | if (atomic_read(&p->fs->count) > 1 || | ||
1096 | atomic_read(&p->files->count) > 1 || | ||
1097 | atomic_read(&p->sighand->count) > 1) | ||
1098 | unsafe |= LSM_UNSAFE_SHARE; | ||
1099 | |||
1100 | return unsafe; | ||
1101 | } | ||
1102 | |||
1103 | void compute_creds(struct linux_binprm *bprm) | ||
1104 | { | ||
1105 | int unsafe; | ||
1106 | |||
1107 | if (bprm->e_uid != current->uid) { | ||
1108 | suid_keys(current); | ||
1109 | current->pdeath_signal = 0; | ||
1110 | } | ||
1111 | exec_keys(current); | ||
1112 | |||
1113 | task_lock(current); | ||
1114 | unsafe = unsafe_exec(current); | ||
1115 | security_bprm_apply_creds(bprm, unsafe); | ||
1116 | task_unlock(current); | ||
1117 | security_bprm_post_apply_creds(bprm); | ||
1118 | } | ||
1119 | EXPORT_SYMBOL(compute_creds); | ||
1120 | |||
1121 | /* | 1132 | /* |
1122 | * Arguments are '\0' separated strings found at the location bprm->p | 1133 | * Arguments are '\0' separated strings found at the location bprm->p |
1123 | * points to; chop off the first by relocating brpm->p to right after | 1134 | * points to; chop off the first by relocating brpm->p to right after |
@@ -1278,6 +1289,8 @@ EXPORT_SYMBOL(search_binary_handler); | |||
1278 | void free_bprm(struct linux_binprm *bprm) | 1289 | void free_bprm(struct linux_binprm *bprm) |
1279 | { | 1290 | { |
1280 | free_arg_pages(bprm); | 1291 | free_arg_pages(bprm); |
1292 | if (bprm->cred) | ||
1293 | abort_creds(bprm->cred); | ||
1281 | kfree(bprm); | 1294 | kfree(bprm); |
1282 | } | 1295 | } |
1283 | 1296 | ||
@@ -1303,10 +1316,20 @@ int do_execve(char * filename, | |||
1303 | if (!bprm) | 1316 | if (!bprm) |
1304 | goto out_files; | 1317 | goto out_files; |
1305 | 1318 | ||
1319 | retval = mutex_lock_interruptible(¤t->cred_exec_mutex); | ||
1320 | if (retval < 0) | ||
1321 | goto out_free; | ||
1322 | |||
1323 | retval = -ENOMEM; | ||
1324 | bprm->cred = prepare_exec_creds(); | ||
1325 | if (!bprm->cred) | ||
1326 | goto out_unlock; | ||
1327 | check_unsafe_exec(bprm); | ||
1328 | |||
1306 | file = open_exec(filename); | 1329 | file = open_exec(filename); |
1307 | retval = PTR_ERR(file); | 1330 | retval = PTR_ERR(file); |
1308 | if (IS_ERR(file)) | 1331 | if (IS_ERR(file)) |
1309 | goto out_kfree; | 1332 | goto out_unlock; |
1310 | 1333 | ||
1311 | sched_exec(); | 1334 | sched_exec(); |
1312 | 1335 | ||
@@ -1320,14 +1343,10 @@ int do_execve(char * filename, | |||
1320 | 1343 | ||
1321 | bprm->argc = count(argv, MAX_ARG_STRINGS); | 1344 | bprm->argc = count(argv, MAX_ARG_STRINGS); |
1322 | if ((retval = bprm->argc) < 0) | 1345 | if ((retval = bprm->argc) < 0) |
1323 | goto out_mm; | 1346 | goto out; |
1324 | 1347 | ||
1325 | bprm->envc = count(envp, MAX_ARG_STRINGS); | 1348 | bprm->envc = count(envp, MAX_ARG_STRINGS); |
1326 | if ((retval = bprm->envc) < 0) | 1349 | if ((retval = bprm->envc) < 0) |
1327 | goto out_mm; | ||
1328 | |||
1329 | retval = security_bprm_alloc(bprm); | ||
1330 | if (retval) | ||
1331 | goto out; | 1350 | goto out; |
1332 | 1351 | ||
1333 | retval = prepare_binprm(bprm); | 1352 | retval = prepare_binprm(bprm); |
@@ -1349,21 +1368,18 @@ int do_execve(char * filename, | |||
1349 | 1368 | ||
1350 | current->flags &= ~PF_KTHREAD; | 1369 | current->flags &= ~PF_KTHREAD; |
1351 | retval = search_binary_handler(bprm,regs); | 1370 | retval = search_binary_handler(bprm,regs); |
1352 | if (retval >= 0) { | 1371 | if (retval < 0) |
1353 | /* execve success */ | 1372 | goto out; |
1354 | security_bprm_free(bprm); | ||
1355 | acct_update_integrals(current); | ||
1356 | free_bprm(bprm); | ||
1357 | if (displaced) | ||
1358 | put_files_struct(displaced); | ||
1359 | return retval; | ||
1360 | } | ||
1361 | 1373 | ||
1362 | out: | 1374 | /* execve succeeded */ |
1363 | if (bprm->security) | 1375 | mutex_unlock(¤t->cred_exec_mutex); |
1364 | security_bprm_free(bprm); | 1376 | acct_update_integrals(current); |
1377 | free_bprm(bprm); | ||
1378 | if (displaced) | ||
1379 | put_files_struct(displaced); | ||
1380 | return retval; | ||
1365 | 1381 | ||
1366 | out_mm: | 1382 | out: |
1367 | if (bprm->mm) | 1383 | if (bprm->mm) |
1368 | mmput (bprm->mm); | 1384 | mmput (bprm->mm); |
1369 | 1385 | ||
@@ -1372,7 +1388,11 @@ out_file: | |||
1372 | allow_write_access(bprm->file); | 1388 | allow_write_access(bprm->file); |
1373 | fput(bprm->file); | 1389 | fput(bprm->file); |
1374 | } | 1390 | } |
1375 | out_kfree: | 1391 | |
1392 | out_unlock: | ||
1393 | mutex_unlock(¤t->cred_exec_mutex); | ||
1394 | |||
1395 | out_free: | ||
1376 | free_bprm(bprm); | 1396 | free_bprm(bprm); |
1377 | 1397 | ||
1378 | out_files: | 1398 | out_files: |
@@ -1404,6 +1424,7 @@ EXPORT_SYMBOL(set_binfmt); | |||
1404 | */ | 1424 | */ |
1405 | static int format_corename(char *corename, long signr) | 1425 | static int format_corename(char *corename, long signr) |
1406 | { | 1426 | { |
1427 | const struct cred *cred = current_cred(); | ||
1407 | const char *pat_ptr = core_pattern; | 1428 | const char *pat_ptr = core_pattern; |
1408 | int ispipe = (*pat_ptr == '|'); | 1429 | int ispipe = (*pat_ptr == '|'); |
1409 | char *out_ptr = corename; | 1430 | char *out_ptr = corename; |
@@ -1440,7 +1461,7 @@ static int format_corename(char *corename, long signr) | |||
1440 | /* uid */ | 1461 | /* uid */ |
1441 | case 'u': | 1462 | case 'u': |
1442 | rc = snprintf(out_ptr, out_end - out_ptr, | 1463 | rc = snprintf(out_ptr, out_end - out_ptr, |
1443 | "%d", current->uid); | 1464 | "%d", cred->uid); |
1444 | if (rc > out_end - out_ptr) | 1465 | if (rc > out_end - out_ptr) |
1445 | goto out; | 1466 | goto out; |
1446 | out_ptr += rc; | 1467 | out_ptr += rc; |
@@ -1448,7 +1469,7 @@ static int format_corename(char *corename, long signr) | |||
1448 | /* gid */ | 1469 | /* gid */ |
1449 | case 'g': | 1470 | case 'g': |
1450 | rc = snprintf(out_ptr, out_end - out_ptr, | 1471 | rc = snprintf(out_ptr, out_end - out_ptr, |
1451 | "%d", current->gid); | 1472 | "%d", cred->gid); |
1452 | if (rc > out_end - out_ptr) | 1473 | if (rc > out_end - out_ptr) |
1453 | goto out; | 1474 | goto out; |
1454 | out_ptr += rc; | 1475 | out_ptr += rc; |
@@ -1724,8 +1745,9 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
1724 | struct linux_binfmt * binfmt; | 1745 | struct linux_binfmt * binfmt; |
1725 | struct inode * inode; | 1746 | struct inode * inode; |
1726 | struct file * file; | 1747 | struct file * file; |
1748 | const struct cred *old_cred; | ||
1749 | struct cred *cred; | ||
1727 | int retval = 0; | 1750 | int retval = 0; |
1728 | int fsuid = current->fsuid; | ||
1729 | int flag = 0; | 1751 | int flag = 0; |
1730 | int ispipe = 0; | 1752 | int ispipe = 0; |
1731 | unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; | 1753 | unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; |
@@ -1738,12 +1760,20 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
1738 | binfmt = current->binfmt; | 1760 | binfmt = current->binfmt; |
1739 | if (!binfmt || !binfmt->core_dump) | 1761 | if (!binfmt || !binfmt->core_dump) |
1740 | goto fail; | 1762 | goto fail; |
1763 | |||
1764 | cred = prepare_creds(); | ||
1765 | if (!cred) { | ||
1766 | retval = -ENOMEM; | ||
1767 | goto fail; | ||
1768 | } | ||
1769 | |||
1741 | down_write(&mm->mmap_sem); | 1770 | down_write(&mm->mmap_sem); |
1742 | /* | 1771 | /* |
1743 | * If another thread got here first, or we are not dumpable, bail out. | 1772 | * If another thread got here first, or we are not dumpable, bail out. |
1744 | */ | 1773 | */ |
1745 | if (mm->core_state || !get_dumpable(mm)) { | 1774 | if (mm->core_state || !get_dumpable(mm)) { |
1746 | up_write(&mm->mmap_sem); | 1775 | up_write(&mm->mmap_sem); |
1776 | put_cred(cred); | ||
1747 | goto fail; | 1777 | goto fail; |
1748 | } | 1778 | } |
1749 | 1779 | ||
@@ -1754,12 +1784,16 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
1754 | */ | 1784 | */ |
1755 | if (get_dumpable(mm) == 2) { /* Setuid core dump mode */ | 1785 | if (get_dumpable(mm) == 2) { /* Setuid core dump mode */ |
1756 | flag = O_EXCL; /* Stop rewrite attacks */ | 1786 | flag = O_EXCL; /* Stop rewrite attacks */ |
1757 | current->fsuid = 0; /* Dump root private */ | 1787 | cred->fsuid = 0; /* Dump root private */ |
1758 | } | 1788 | } |
1759 | 1789 | ||
1760 | retval = coredump_wait(exit_code, &core_state); | 1790 | retval = coredump_wait(exit_code, &core_state); |
1761 | if (retval < 0) | 1791 | if (retval < 0) { |
1792 | put_cred(cred); | ||
1762 | goto fail; | 1793 | goto fail; |
1794 | } | ||
1795 | |||
1796 | old_cred = override_creds(cred); | ||
1763 | 1797 | ||
1764 | /* | 1798 | /* |
1765 | * Clear any false indication of pending signals that might | 1799 | * Clear any false indication of pending signals that might |
@@ -1831,7 +1865,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
1831 | * Dont allow local users get cute and trick others to coredump | 1865 | * Dont allow local users get cute and trick others to coredump |
1832 | * into their pre-created files: | 1866 | * into their pre-created files: |
1833 | */ | 1867 | */ |
1834 | if (inode->i_uid != current->fsuid) | 1868 | if (inode->i_uid != current_fsuid()) |
1835 | goto close_fail; | 1869 | goto close_fail; |
1836 | if (!file->f_op) | 1870 | if (!file->f_op) |
1837 | goto close_fail; | 1871 | goto close_fail; |
@@ -1850,7 +1884,8 @@ fail_unlock: | |||
1850 | if (helper_argv) | 1884 | if (helper_argv) |
1851 | argv_free(helper_argv); | 1885 | argv_free(helper_argv); |
1852 | 1886 | ||
1853 | current->fsuid = fsuid; | 1887 | revert_creds(old_cred); |
1888 | put_cred(cred); | ||
1854 | coredump_finish(mm); | 1889 | coredump_finish(mm); |
1855 | fail: | 1890 | fail: |
1856 | return retval; | 1891 | return retval; |