diff options
Diffstat (limited to 'fs/exec.c')
-rw-r--r-- | fs/exec.c | 149 |
1 files changed, 86 insertions, 63 deletions
@@ -55,6 +55,7 @@ | |||
55 | #include <asm/uaccess.h> | 55 | #include <asm/uaccess.h> |
56 | #include <asm/mmu_context.h> | 56 | #include <asm/mmu_context.h> |
57 | #include <asm/tlb.h> | 57 | #include <asm/tlb.h> |
58 | #include "internal.h" | ||
58 | 59 | ||
59 | #ifdef __alpha__ | 60 | #ifdef __alpha__ |
60 | /* for /sbin/loader handling in search_binary_handler() */ | 61 | /* for /sbin/loader handling in search_binary_handler() */ |
@@ -1007,15 +1008,17 @@ int flush_old_exec(struct linux_binprm * bprm) | |||
1007 | */ | 1008 | */ |
1008 | current->mm->task_size = TASK_SIZE; | 1009 | current->mm->task_size = TASK_SIZE; |
1009 | 1010 | ||
1010 | if (bprm->e_uid != current_euid() || | 1011 | /* install the new credentials */ |
1011 | bprm->e_gid != current_egid()) { | 1012 | if (bprm->cred->uid != current_euid() || |
1012 | set_dumpable(current->mm, suid_dumpable); | 1013 | bprm->cred->gid != current_egid()) { |
1013 | current->pdeath_signal = 0; | 1014 | current->pdeath_signal = 0; |
1014 | } else if (file_permission(bprm->file, MAY_READ) || | 1015 | } else if (file_permission(bprm->file, MAY_READ) || |
1015 | (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) { | 1016 | bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) { |
1016 | set_dumpable(current->mm, suid_dumpable); | 1017 | set_dumpable(current->mm, suid_dumpable); |
1017 | } | 1018 | } |
1018 | 1019 | ||
1020 | current->personality &= ~bprm->per_clear; | ||
1021 | |||
1019 | /* An exec changes our domain. We are no longer part of the thread | 1022 | /* An exec changes our domain. We are no longer part of the thread |
1020 | group */ | 1023 | group */ |
1021 | 1024 | ||
@@ -1032,13 +1035,50 @@ out: | |||
1032 | 1035 | ||
1033 | EXPORT_SYMBOL(flush_old_exec); | 1036 | EXPORT_SYMBOL(flush_old_exec); |
1034 | 1037 | ||
1038 | /* | ||
1039 | * install the new credentials for this executable | ||
1040 | */ | ||
1041 | void install_exec_creds(struct linux_binprm *bprm) | ||
1042 | { | ||
1043 | security_bprm_committing_creds(bprm); | ||
1044 | |||
1045 | commit_creds(bprm->cred); | ||
1046 | bprm->cred = NULL; | ||
1047 | |||
1048 | /* cred_exec_mutex must be held at least to this point to prevent | ||
1049 | * ptrace_attach() from altering our determination of the task's | ||
1050 | * credentials; any time after this it may be unlocked */ | ||
1051 | |||
1052 | security_bprm_committed_creds(bprm); | ||
1053 | } | ||
1054 | EXPORT_SYMBOL(install_exec_creds); | ||
1055 | |||
1056 | /* | ||
1057 | * determine how safe it is to execute the proposed program | ||
1058 | * - the caller must hold current->cred_exec_mutex to protect against | ||
1059 | * PTRACE_ATTACH | ||
1060 | */ | ||
1061 | void check_unsafe_exec(struct linux_binprm *bprm) | ||
1062 | { | ||
1063 | struct task_struct *p = current; | ||
1064 | |||
1065 | bprm->unsafe = tracehook_unsafe_exec(p); | ||
1066 | |||
1067 | if (atomic_read(&p->fs->count) > 1 || | ||
1068 | atomic_read(&p->files->count) > 1 || | ||
1069 | atomic_read(&p->sighand->count) > 1) | ||
1070 | bprm->unsafe |= LSM_UNSAFE_SHARE; | ||
1071 | } | ||
1072 | |||
1035 | /* | 1073 | /* |
1036 | * Fill the binprm structure from the inode. | 1074 | * Fill the binprm structure from the inode. |
1037 | * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes | 1075 | * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes |
1076 | * | ||
1077 | * This may be called multiple times for binary chains (scripts for example). | ||
1038 | */ | 1078 | */ |
1039 | int prepare_binprm(struct linux_binprm *bprm) | 1079 | int prepare_binprm(struct linux_binprm *bprm) |
1040 | { | 1080 | { |
1041 | int mode; | 1081 | umode_t mode; |
1042 | struct inode * inode = bprm->file->f_path.dentry->d_inode; | 1082 | struct inode * inode = bprm->file->f_path.dentry->d_inode; |
1043 | int retval; | 1083 | int retval; |
1044 | 1084 | ||
@@ -1046,14 +1086,15 @@ int prepare_binprm(struct linux_binprm *bprm) | |||
1046 | if (bprm->file->f_op == NULL) | 1086 | if (bprm->file->f_op == NULL) |
1047 | return -EACCES; | 1087 | return -EACCES; |
1048 | 1088 | ||
1049 | bprm->e_uid = current_euid(); | 1089 | /* clear any previous set[ug]id data from a previous binary */ |
1050 | bprm->e_gid = current_egid(); | 1090 | bprm->cred->euid = current_euid(); |
1091 | bprm->cred->egid = current_egid(); | ||
1051 | 1092 | ||
1052 | if(!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) { | 1093 | if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) { |
1053 | /* Set-uid? */ | 1094 | /* Set-uid? */ |
1054 | if (mode & S_ISUID) { | 1095 | if (mode & S_ISUID) { |
1055 | current->personality &= ~PER_CLEAR_ON_SETID; | 1096 | bprm->per_clear |= PER_CLEAR_ON_SETID; |
1056 | bprm->e_uid = inode->i_uid; | 1097 | bprm->cred->euid = inode->i_uid; |
1057 | } | 1098 | } |
1058 | 1099 | ||
1059 | /* Set-gid? */ | 1100 | /* Set-gid? */ |
@@ -1063,50 +1104,23 @@ int prepare_binprm(struct linux_binprm *bprm) | |||
1063 | * executable. | 1104 | * executable. |
1064 | */ | 1105 | */ |
1065 | if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { | 1106 | if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { |
1066 | current->personality &= ~PER_CLEAR_ON_SETID; | 1107 | bprm->per_clear |= PER_CLEAR_ON_SETID; |
1067 | bprm->e_gid = inode->i_gid; | 1108 | bprm->cred->egid = inode->i_gid; |
1068 | } | 1109 | } |
1069 | } | 1110 | } |
1070 | 1111 | ||
1071 | /* fill in binprm security blob */ | 1112 | /* fill in binprm security blob */ |
1072 | retval = security_bprm_set(bprm); | 1113 | retval = security_bprm_set_creds(bprm); |
1073 | if (retval) | 1114 | if (retval) |
1074 | return retval; | 1115 | return retval; |
1116 | bprm->cred_prepared = 1; | ||
1075 | 1117 | ||
1076 | memset(bprm->buf,0,BINPRM_BUF_SIZE); | 1118 | memset(bprm->buf, 0, BINPRM_BUF_SIZE); |
1077 | return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE); | 1119 | return kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE); |
1078 | } | 1120 | } |
1079 | 1121 | ||
1080 | EXPORT_SYMBOL(prepare_binprm); | 1122 | EXPORT_SYMBOL(prepare_binprm); |
1081 | 1123 | ||
1082 | static int unsafe_exec(struct task_struct *p) | ||
1083 | { | ||
1084 | int unsafe = tracehook_unsafe_exec(p); | ||
1085 | |||
1086 | if (atomic_read(&p->fs->count) > 1 || | ||
1087 | atomic_read(&p->files->count) > 1 || | ||
1088 | atomic_read(&p->sighand->count) > 1) | ||
1089 | unsafe |= LSM_UNSAFE_SHARE; | ||
1090 | |||
1091 | return unsafe; | ||
1092 | } | ||
1093 | |||
1094 | void compute_creds(struct linux_binprm *bprm) | ||
1095 | { | ||
1096 | int unsafe; | ||
1097 | |||
1098 | if (bprm->e_uid != current_uid()) | ||
1099 | current->pdeath_signal = 0; | ||
1100 | exec_keys(current); | ||
1101 | |||
1102 | task_lock(current); | ||
1103 | unsafe = unsafe_exec(current); | ||
1104 | security_bprm_apply_creds(bprm, unsafe); | ||
1105 | task_unlock(current); | ||
1106 | security_bprm_post_apply_creds(bprm); | ||
1107 | } | ||
1108 | EXPORT_SYMBOL(compute_creds); | ||
1109 | |||
1110 | /* | 1124 | /* |
1111 | * Arguments are '\0' separated strings found at the location bprm->p | 1125 | * Arguments are '\0' separated strings found at the location bprm->p |
1112 | * points to; chop off the first by relocating brpm->p to right after | 1126 | * points to; chop off the first by relocating brpm->p to right after |
@@ -1259,6 +1273,8 @@ EXPORT_SYMBOL(search_binary_handler); | |||
1259 | void free_bprm(struct linux_binprm *bprm) | 1273 | void free_bprm(struct linux_binprm *bprm) |
1260 | { | 1274 | { |
1261 | free_arg_pages(bprm); | 1275 | free_arg_pages(bprm); |
1276 | if (bprm->cred) | ||
1277 | abort_creds(bprm->cred); | ||
1262 | kfree(bprm); | 1278 | kfree(bprm); |
1263 | } | 1279 | } |
1264 | 1280 | ||
@@ -1284,10 +1300,20 @@ int do_execve(char * filename, | |||
1284 | if (!bprm) | 1300 | if (!bprm) |
1285 | goto out_files; | 1301 | goto out_files; |
1286 | 1302 | ||
1303 | retval = mutex_lock_interruptible(¤t->cred_exec_mutex); | ||
1304 | if (retval < 0) | ||
1305 | goto out_free; | ||
1306 | |||
1307 | retval = -ENOMEM; | ||
1308 | bprm->cred = prepare_exec_creds(); | ||
1309 | if (!bprm->cred) | ||
1310 | goto out_unlock; | ||
1311 | check_unsafe_exec(bprm); | ||
1312 | |||
1287 | file = open_exec(filename); | 1313 | file = open_exec(filename); |
1288 | retval = PTR_ERR(file); | 1314 | retval = PTR_ERR(file); |
1289 | if (IS_ERR(file)) | 1315 | if (IS_ERR(file)) |
1290 | goto out_kfree; | 1316 | goto out_unlock; |
1291 | 1317 | ||
1292 | sched_exec(); | 1318 | sched_exec(); |
1293 | 1319 | ||
@@ -1301,14 +1327,10 @@ int do_execve(char * filename, | |||
1301 | 1327 | ||
1302 | bprm->argc = count(argv, MAX_ARG_STRINGS); | 1328 | bprm->argc = count(argv, MAX_ARG_STRINGS); |
1303 | if ((retval = bprm->argc) < 0) | 1329 | if ((retval = bprm->argc) < 0) |
1304 | goto out_mm; | 1330 | goto out; |
1305 | 1331 | ||
1306 | bprm->envc = count(envp, MAX_ARG_STRINGS); | 1332 | bprm->envc = count(envp, MAX_ARG_STRINGS); |
1307 | if ((retval = bprm->envc) < 0) | 1333 | if ((retval = bprm->envc) < 0) |
1308 | goto out_mm; | ||
1309 | |||
1310 | retval = security_bprm_alloc(bprm); | ||
1311 | if (retval) | ||
1312 | goto out; | 1334 | goto out; |
1313 | 1335 | ||
1314 | retval = prepare_binprm(bprm); | 1336 | retval = prepare_binprm(bprm); |
@@ -1330,21 +1352,18 @@ int do_execve(char * filename, | |||
1330 | 1352 | ||
1331 | current->flags &= ~PF_KTHREAD; | 1353 | current->flags &= ~PF_KTHREAD; |
1332 | retval = search_binary_handler(bprm,regs); | 1354 | retval = search_binary_handler(bprm,regs); |
1333 | if (retval >= 0) { | 1355 | if (retval < 0) |
1334 | /* execve success */ | 1356 | goto out; |
1335 | security_bprm_free(bprm); | ||
1336 | acct_update_integrals(current); | ||
1337 | free_bprm(bprm); | ||
1338 | if (displaced) | ||
1339 | put_files_struct(displaced); | ||
1340 | return retval; | ||
1341 | } | ||
1342 | 1357 | ||
1343 | out: | 1358 | /* execve succeeded */ |
1344 | if (bprm->security) | 1359 | mutex_unlock(¤t->cred_exec_mutex); |
1345 | security_bprm_free(bprm); | 1360 | acct_update_integrals(current); |
1361 | free_bprm(bprm); | ||
1362 | if (displaced) | ||
1363 | put_files_struct(displaced); | ||
1364 | return retval; | ||
1346 | 1365 | ||
1347 | out_mm: | 1366 | out: |
1348 | if (bprm->mm) | 1367 | if (bprm->mm) |
1349 | mmput (bprm->mm); | 1368 | mmput (bprm->mm); |
1350 | 1369 | ||
@@ -1353,7 +1372,11 @@ out_file: | |||
1353 | allow_write_access(bprm->file); | 1372 | allow_write_access(bprm->file); |
1354 | fput(bprm->file); | 1373 | fput(bprm->file); |
1355 | } | 1374 | } |
1356 | out_kfree: | 1375 | |
1376 | out_unlock: | ||
1377 | mutex_unlock(¤t->cred_exec_mutex); | ||
1378 | |||
1379 | out_free: | ||
1357 | free_bprm(bprm); | 1380 | free_bprm(bprm); |
1358 | 1381 | ||
1359 | out_files: | 1382 | out_files: |