diff options
Diffstat (limited to 'fs/exec.c')
-rw-r--r-- | fs/exec.c | 40 |
1 files changed, 33 insertions, 7 deletions
@@ -1139,7 +1139,7 @@ void setup_new_exec(struct linux_binprm * bprm) | |||
1139 | /* This is the point of no return */ | 1139 | /* This is the point of no return */ |
1140 | current->sas_ss_sp = current->sas_ss_size = 0; | 1140 | current->sas_ss_sp = current->sas_ss_size = 0; |
1141 | 1141 | ||
1142 | if (current_euid() == current_uid() && current_egid() == current_gid()) | 1142 | if (uid_eq(current_euid(), current_uid()) && gid_eq(current_egid(), current_gid())) |
1143 | set_dumpable(current->mm, 1); | 1143 | set_dumpable(current->mm, 1); |
1144 | else | 1144 | else |
1145 | set_dumpable(current->mm, suid_dumpable); | 1145 | set_dumpable(current->mm, suid_dumpable); |
@@ -1153,8 +1153,8 @@ void setup_new_exec(struct linux_binprm * bprm) | |||
1153 | current->mm->task_size = TASK_SIZE; | 1153 | current->mm->task_size = TASK_SIZE; |
1154 | 1154 | ||
1155 | /* install the new credentials */ | 1155 | /* install the new credentials */ |
1156 | if (bprm->cred->uid != current_euid() || | 1156 | if (!uid_eq(bprm->cred->uid, current_euid()) || |
1157 | bprm->cred->gid != current_egid()) { | 1157 | !gid_eq(bprm->cred->gid, current_egid())) { |
1158 | current->pdeath_signal = 0; | 1158 | current->pdeath_signal = 0; |
1159 | } else { | 1159 | } else { |
1160 | would_dump(bprm, bprm->file); | 1160 | would_dump(bprm, bprm->file); |
@@ -1245,6 +1245,13 @@ static int check_unsafe_exec(struct linux_binprm *bprm) | |||
1245 | bprm->unsafe |= LSM_UNSAFE_PTRACE; | 1245 | bprm->unsafe |= LSM_UNSAFE_PTRACE; |
1246 | } | 1246 | } |
1247 | 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 | |||
1248 | n_fs = 1; | 1255 | n_fs = 1; |
1249 | spin_lock(&p->fs->lock); | 1256 | spin_lock(&p->fs->lock); |
1250 | rcu_read_lock(); | 1257 | rcu_read_lock(); |
@@ -1288,11 +1295,15 @@ int prepare_binprm(struct linux_binprm *bprm) | |||
1288 | bprm->cred->euid = current_euid(); | 1295 | bprm->cred->euid = current_euid(); |
1289 | bprm->cred->egid = current_egid(); | 1296 | bprm->cred->egid = current_egid(); |
1290 | 1297 | ||
1291 | 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) { | ||
1292 | /* Set-uid? */ | 1300 | /* Set-uid? */ |
1293 | if (mode & S_ISUID) { | 1301 | if (mode & S_ISUID) { |
1302 | if (!kuid_has_mapping(bprm->cred->user_ns, inode->i_uid)) | ||
1303 | return -EPERM; | ||
1294 | bprm->per_clear |= PER_CLEAR_ON_SETID; | 1304 | bprm->per_clear |= PER_CLEAR_ON_SETID; |
1295 | bprm->cred->euid = inode->i_uid; | 1305 | bprm->cred->euid = inode->i_uid; |
1306 | |||
1296 | } | 1307 | } |
1297 | 1308 | ||
1298 | /* Set-gid? */ | 1309 | /* Set-gid? */ |
@@ -1302,6 +1313,8 @@ int prepare_binprm(struct linux_binprm *bprm) | |||
1302 | * executable. | 1313 | * executable. |
1303 | */ | 1314 | */ |
1304 | 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; | ||
1305 | bprm->per_clear |= PER_CLEAR_ON_SETID; | 1318 | bprm->per_clear |= PER_CLEAR_ON_SETID; |
1306 | bprm->cred->egid = inode->i_gid; | 1319 | bprm->cred->egid = inode->i_gid; |
1307 | } | 1320 | } |
@@ -1930,8 +1943,21 @@ static int coredump_wait(int exit_code, struct core_state *core_state) | |||
1930 | core_waiters = zap_threads(tsk, mm, core_state, exit_code); | 1943 | core_waiters = zap_threads(tsk, mm, core_state, exit_code); |
1931 | up_write(&mm->mmap_sem); | 1944 | up_write(&mm->mmap_sem); |
1932 | 1945 | ||
1933 | if (core_waiters > 0) | 1946 | if (core_waiters > 0) { |
1947 | struct core_thread *ptr; | ||
1948 | |||
1934 | 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 | } | ||
1935 | 1961 | ||
1936 | return core_waiters; | 1962 | return core_waiters; |
1937 | } | 1963 | } |
@@ -2121,7 +2147,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
2121 | if (__get_dumpable(cprm.mm_flags) == 2) { | 2147 | if (__get_dumpable(cprm.mm_flags) == 2) { |
2122 | /* Setuid core dump mode */ | 2148 | /* Setuid core dump mode */ |
2123 | flag = O_EXCL; /* Stop rewrite attacks */ | 2149 | flag = O_EXCL; /* Stop rewrite attacks */ |
2124 | cred->fsuid = 0; /* Dump root private */ | 2150 | cred->fsuid = GLOBAL_ROOT_UID; /* Dump root private */ |
2125 | } | 2151 | } |
2126 | 2152 | ||
2127 | retval = coredump_wait(exit_code, &core_state); | 2153 | retval = coredump_wait(exit_code, &core_state); |
@@ -2222,7 +2248,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
2222 | * Dont allow local users get cute and trick others to coredump | 2248 | * Dont allow local users get cute and trick others to coredump |
2223 | * into their pre-created files. | 2249 | * into their pre-created files. |
2224 | */ | 2250 | */ |
2225 | if (inode->i_uid != current_fsuid()) | 2251 | if (!uid_eq(inode->i_uid, current_fsuid())) |
2226 | goto close_fail; | 2252 | goto close_fail; |
2227 | if (!cprm.file->f_op || !cprm.file->f_op->write) | 2253 | if (!cprm.file->f_op || !cprm.file->f_op->write) |
2228 | goto close_fail; | 2254 | goto close_fail; |