Newer
Older
set_dumpable(current->mm, suid_dumpable);
current->pdeath_signal = 0;
} else if (file_permission(bprm->file, MAY_READ) ||
(bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) {
set_dumpable(current->mm, suid_dumpable);
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
}
/* An exec changes our domain. We are no longer part of the thread
group */
current->self_exec_id++;
flush_signal_handlers(current, 0);
flush_old_files(current->files);
return 0;
out:
return retval;
}
EXPORT_SYMBOL(flush_old_exec);
/*
* Fill the binprm structure from the inode.
* Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes
*/
int prepare_binprm(struct linux_binprm *bprm)
{
int mode;
struct inode * inode = bprm->file->f_path.dentry->d_inode;
int retval;
mode = inode->i_mode;
if (bprm->file->f_op == NULL)
return -EACCES;
bprm->e_uid = current->euid;
bprm->e_gid = current->egid;
if(!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
/* Set-uid? */
if (mode & S_ISUID) {
current->personality &= ~PER_CLEAR_ON_SETID;
bprm->e_uid = inode->i_uid;
}
/* Set-gid? */
/*
* If setgid is set but no group execute bit then this
* is a candidate for mandatory locking, not a setgid
* executable.
*/
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
current->personality &= ~PER_CLEAR_ON_SETID;
bprm->e_gid = inode->i_gid;
}
}
/* fill in binprm security blob */
retval = security_bprm_set(bprm);
if (retval)
return retval;
memset(bprm->buf,0,BINPRM_BUF_SIZE);
return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE);
}
EXPORT_SYMBOL(prepare_binprm);
static int unsafe_exec(struct task_struct *p)
if (atomic_read(&p->fs->count) > 1 ||
atomic_read(&p->files->count) > 1 ||
atomic_read(&p->sighand->count) > 1)
unsafe |= LSM_UNSAFE_SHARE;
return unsafe;
}
void compute_creds(struct linux_binprm *bprm)
{
int unsafe;
if (bprm->e_uid != current->uid) {
current->pdeath_signal = 0;
}
exec_keys(current);
task_lock(current);
unsafe = unsafe_exec(current);
security_bprm_apply_creds(bprm, unsafe);
task_unlock(current);
security_bprm_post_apply_creds(bprm);
}
EXPORT_SYMBOL(compute_creds);
/*
* Arguments are '\0' separated strings found at the location bprm->p
* points to; chop off the first by relocating brpm->p to right after
* the first '\0' encountered.
*/
int remove_arg_zero(struct linux_binprm *bprm)
int ret = 0;
unsigned long offset;
char *kaddr;
struct page *page;
do {
offset = bprm->p & ~PAGE_MASK;
page = get_arg_page(bprm, bprm->p, 0);
if (!page) {
ret = -EFAULT;
goto out;
}
kaddr = kmap_atomic(page, KM_USER0);
for (; offset < PAGE_SIZE && kaddr[offset];
offset++, bprm->p++)
;
kunmap_atomic(kaddr, KM_USER0);
put_arg_page(page);
if (offset == PAGE_SIZE)
free_arg_page(bprm, (bprm->p >> PAGE_SHIFT) - 1);
} while (offset == PAGE_SIZE);
bprm->p++;
bprm->argc--;
ret = 0;
}
EXPORT_SYMBOL(remove_arg_zero);
/*
* cycle the list of binary formats handler, until one recognizes the image
*/
int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
{
int try,retval;
struct linux_binfmt *fmt;
/* handle /sbin/loader.. */
{
struct exec * eh = (struct exec *) bprm->buf;
if (!bprm->loader && eh->fh.f_magic == 0x183 &&
(eh->fh.f_flags & 0x3000) == 0x3000)
{
struct file * file;
unsigned long loader;
allow_write_access(bprm->file);
fput(bprm->file);
bprm->file = NULL;
loader = bprm->vma->vm_end - sizeof(void *);
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
file = open_exec("/sbin/loader");
retval = PTR_ERR(file);
if (IS_ERR(file))
return retval;
/* Remember if the application is TASO. */
bprm->sh_bang = eh->ah.entry < 0x100000000UL;
bprm->file = file;
bprm->loader = loader;
retval = prepare_binprm(bprm);
if (retval<0)
return retval;
/* should call search_binary_handler recursively here,
but it does not matter */
}
}
#endif
retval = security_bprm_check(bprm);
if (retval)
return retval;
/* kernel module loader fixup */
/* so we don't try to load run modprobe in kernel space. */
set_fs(USER_DS);
retval = audit_bprm(bprm);
if (retval)
return retval;
retval = -ENOENT;
for (try=0; try<2; try++) {
read_lock(&binfmt_lock);
list_for_each_entry(fmt, &formats, lh) {
int (*fn)(struct linux_binprm *, struct pt_regs *) = fmt->load_binary;
if (!fn)
continue;
if (!try_module_get(fmt->module))
continue;
read_unlock(&binfmt_lock);
retval = fn(bprm, regs);
if (retval >= 0) {
put_binfmt(fmt);
allow_write_access(bprm->file);
if (bprm->file)
fput(bprm->file);
bprm->file = NULL;
current->did_exec = 1;
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
return retval;
}
read_lock(&binfmt_lock);
put_binfmt(fmt);
if (retval != -ENOEXEC || bprm->mm == NULL)
break;
if (!bprm->file) {
read_unlock(&binfmt_lock);
return retval;
}
}
read_unlock(&binfmt_lock);
if (retval != -ENOEXEC || bprm->mm == NULL) {
break;
#ifdef CONFIG_KMOD
}else{
#define printable(c) (((c)=='\t') || ((c)=='\n') || (0x20<=(c) && (c)<=0x7e))
if (printable(bprm->buf[0]) &&
printable(bprm->buf[1]) &&
printable(bprm->buf[2]) &&
printable(bprm->buf[3]))
break; /* -ENOEXEC */
request_module("binfmt-%04x", *(unsigned short *)(&bprm->buf[2]));
#endif
}
}
return retval;
}
EXPORT_SYMBOL(search_binary_handler);
void free_bprm(struct linux_binprm *bprm)
{
free_arg_pages(bprm);
kfree(bprm);
}
/*
* sys_execve() executes a new program.
*/
int do_execve(char * filename,
char __user *__user *argv,
char __user *__user *envp,
struct pt_regs * regs)
{
struct linux_binprm *bprm;
struct file *file;
struct files_struct *displaced;
retval = unshare_files(&displaced);
if (retval)
goto out_ret;
bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
goto out_files;
file = open_exec(filename);
retval = PTR_ERR(file);
if (IS_ERR(file))
goto out_kfree;
sched_exec();
bprm->file = file;
bprm->filename = filename;
bprm->interp = filename;
retval = bprm_mm_init(bprm);
if (retval)
goto out_file;
bprm->argc = count(argv, MAX_ARG_STRINGS);
if ((retval = bprm->argc) < 0)
goto out_mm;
bprm->envc = count(envp, MAX_ARG_STRINGS);
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
if ((retval = bprm->envc) < 0)
goto out_mm;
retval = security_bprm_alloc(bprm);
if (retval)
goto out;
retval = prepare_binprm(bprm);
if (retval < 0)
goto out;
retval = copy_strings_kernel(1, &bprm->filename, bprm);
if (retval < 0)
goto out;
bprm->exec = bprm->p;
retval = copy_strings(bprm->envc, envp, bprm);
if (retval < 0)
goto out;
retval = copy_strings(bprm->argc, argv, bprm);
if (retval < 0)
goto out;
retval = search_binary_handler(bprm,regs);
if (retval >= 0) {
/* execve success */
security_bprm_free(bprm);
acct_update_integrals(current);
if (displaced)
put_files_struct(displaced);
return retval;
}
out:
if (bprm->security)
security_bprm_free(bprm);
out_mm:
if (bprm->mm)
out_file:
if (bprm->file) {
allow_write_access(bprm->file);
fput(bprm->file);
}
out_kfree:
out_files:
if (displaced)
reset_files_struct(displaced);
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
out_ret:
return retval;
}
int set_binfmt(struct linux_binfmt *new)
{
struct linux_binfmt *old = current->binfmt;
if (new) {
if (!try_module_get(new->module))
return -1;
}
current->binfmt = new;
if (old)
module_put(old->module);
return 0;
}
EXPORT_SYMBOL(set_binfmt);
/* format_corename will inspect the pattern parameter, and output a
* name into corename, which must have space for at least
* CORENAME_MAX_SIZE bytes plus one byte for the zero terminator.
*/
static int format_corename(char *corename, int nr_threads, long signr)
const char *pat_ptr = core_pattern;
int ispipe = (*pat_ptr == '|');
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
char *out_ptr = corename;
char *const out_end = corename + CORENAME_MAX_SIZE;
int rc;
int pid_in_pattern = 0;
/* Repeat as long as we have more pattern to process and more output
space */
while (*pat_ptr) {
if (*pat_ptr != '%') {
if (out_ptr == out_end)
goto out;
*out_ptr++ = *pat_ptr++;
} else {
switch (*++pat_ptr) {
case 0:
goto out;
/* Double percent, output one percent */
case '%':
if (out_ptr == out_end)
goto out;
*out_ptr++ = '%';
break;
/* pid */
case 'p':
pid_in_pattern = 1;
rc = snprintf(out_ptr, out_end - out_ptr,
"%d", task_tgid_vnr(current));
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
if (rc > out_end - out_ptr)
goto out;
out_ptr += rc;
break;
/* uid */
case 'u':
rc = snprintf(out_ptr, out_end - out_ptr,
"%d", current->uid);
if (rc > out_end - out_ptr)
goto out;
out_ptr += rc;
break;
/* gid */
case 'g':
rc = snprintf(out_ptr, out_end - out_ptr,
"%d", current->gid);
if (rc > out_end - out_ptr)
goto out;
out_ptr += rc;
break;
/* signal that caused the coredump */
case 's':
rc = snprintf(out_ptr, out_end - out_ptr,
"%ld", signr);
if (rc > out_end - out_ptr)
goto out;
out_ptr += rc;
break;
/* UNIX time of coredump */
case 't': {
struct timeval tv;
do_gettimeofday(&tv);
rc = snprintf(out_ptr, out_end - out_ptr,
"%lu", tv.tv_sec);
if (rc > out_end - out_ptr)
goto out;
out_ptr += rc;
break;
}
/* hostname */
case 'h':
down_read(&uts_sem);
rc = snprintf(out_ptr, out_end - out_ptr,
"%s", utsname()->nodename);
up_read(&uts_sem);
if (rc > out_end - out_ptr)
goto out;
out_ptr += rc;
break;
/* executable */
case 'e':
rc = snprintf(out_ptr, out_end - out_ptr,
"%s", current->comm);
if (rc > out_end - out_ptr)
goto out;
out_ptr += rc;
break;

Neil Horman
committed
/* core limit size */
case 'c':
rc = snprintf(out_ptr, out_end - out_ptr,
"%lu", current->signal->rlim[RLIMIT_CORE].rlim_cur);
if (rc > out_end - out_ptr)
goto out;
out_ptr += rc;
break;
default:
break;
}
++pat_ptr;
}
}
/* Backward compatibility with core_uses_pid:
*
* If core_pattern does not include a %p (as is the default)
* and core_uses_pid is set, then .%pid will be appended to
* the filename. Do not do this for piped commands. */
if (!ispipe && !pid_in_pattern
&& (core_uses_pid || nr_threads)) {
".%d", task_tgid_vnr(current));
if (rc > out_end - out_ptr)
goto out;
out_ptr += rc;
}
return ispipe;
static int zap_process(struct task_struct *start)
{
struct task_struct *t;
start->signal->flags = SIGNAL_GROUP_EXIT;
start->signal->group_stop_count = 0;
t = start;
do {
if (t != current && t->mm) {
sigaddset(&t->pending.signal, SIGKILL);
signal_wake_up(t, 1);
} while_each_thread(start, t);
static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
struct core_state *core_state, int exit_code)
int nr = -EAGAIN;
spin_lock_irq(&tsk->sighand->siglock);
if (!signal_group_exit(tsk->signal)) {
mm->core_state = core_state;
tsk->signal->group_exit_code = exit_code;
nr = zap_process(tsk);
spin_unlock_irq(&tsk->sighand->siglock);
if (unlikely(nr < 0))
return nr;
if (atomic_read(&mm->mm_users) == nr + 1)
/*
* We should find and kill all tasks which use this mm, and we should
* count them correctly into ->nr_threads. We don't take tasklist
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
* lock, but this is safe wrt:
*
* fork:
* None of sub-threads can fork after zap_process(leader). All
* processes which were created before this point should be
* visible to zap_threads() because copy_process() adds the new
* process to the tail of init_task.tasks list, and lock/unlock
* of ->siglock provides a memory barrier.
*
* do_exit:
* The caller holds mm->mmap_sem. This means that the task which
* uses this mm can't pass exit_mm(), so it can't exit or clear
* its ->mm.
*
* de_thread:
* It does list_replace_rcu(&leader->tasks, ¤t->tasks),
* we must see either old or new leader, this does not matter.
* However, it can change p->sighand, so lock_task_sighand(p)
* must be used. Since p->mm != NULL and we hold ->mmap_sem
* it can't fail.
*
* Note also that "g" can be the old leader with ->mm == NULL
* and already unhashed and thus removed from ->thread_group.
* This is OK, __unhash_process()->list_del_rcu() does not
* clear the ->next pointer, we will find the new leader via
* next_thread().
*/
if (g == tsk->group_leader)
continue;
if (g->flags & PF_KTHREAD)
continue;
p = g;
do {
if (p->mm) {
if (unlikely(p->mm == mm)) {
lock_task_sighand(p, &flags);
nr += zap_process(p);
unlock_task_sighand(p, &flags);
}
} while_each_thread(g, p);
atomic_set(&core_state->nr_threads, nr);
static int coredump_wait(int exit_code, struct core_state *core_state)
struct task_struct *tsk = current;
struct mm_struct *mm = tsk->mm;
struct completion *vfork_done;
init_completion(&core_state->startup);
core_state->dumper.task = tsk;
core_state->dumper.next = NULL;
core_waiters = zap_threads(tsk, mm, core_state, exit_code);
if (unlikely(core_waiters < 0))
goto fail;
/*
* Make sure nobody is waiting for us to release the VM,
* otherwise we can deadlock when we wait on each other
*/
vfork_done = tsk->vfork_done;
if (vfork_done) {
tsk->vfork_done = NULL;
complete(vfork_done);
}
wait_for_completion(&core_state->startup);
fail:
return core_waiters;
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
static void coredump_finish(struct mm_struct *mm)
{
struct core_thread *curr, *next;
struct task_struct *task;
next = mm->core_state->dumper.next;
while ((curr = next) != NULL) {
next = curr->next;
task = curr->task;
/*
* see exit_mm(), curr->task must not see
* ->task == NULL before we read ->next.
*/
smp_mb();
curr->task = NULL;
wake_up_process(task);
}
mm->core_state = NULL;
}
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
/*
* set_dumpable converts traditional three-value dumpable to two flags and
* stores them into mm->flags. It modifies lower two bits of mm->flags, but
* these bits are not changed atomically. So get_dumpable can observe the
* intermediate state. To avoid doing unexpected behavior, get get_dumpable
* return either old dumpable or new one by paying attention to the order of
* modifying the bits.
*
* dumpable | mm->flags (binary)
* old new | initial interim final
* ---------+-----------------------
* 0 1 | 00 01 01
* 0 2 | 00 10(*) 11
* 1 0 | 01 00 00
* 1 2 | 01 11 11
* 2 0 | 11 10(*) 00
* 2 1 | 11 11 01
*
* (*) get_dumpable regards interim value of 10 as 11.
*/
void set_dumpable(struct mm_struct *mm, int value)
{
switch (value) {
case 0:
clear_bit(MMF_DUMPABLE, &mm->flags);
smp_wmb();
clear_bit(MMF_DUMP_SECURELY, &mm->flags);
break;
case 1:
set_bit(MMF_DUMPABLE, &mm->flags);
smp_wmb();
clear_bit(MMF_DUMP_SECURELY, &mm->flags);
break;
case 2:
set_bit(MMF_DUMP_SECURELY, &mm->flags);
smp_wmb();
set_bit(MMF_DUMPABLE, &mm->flags);
break;
}
}
int get_dumpable(struct mm_struct *mm)
{
int ret;
ret = mm->flags & 0x3;
return (ret >= 2) ? 2 : ret;
}
int do_coredump(long signr, int exit_code, struct pt_regs * regs)
{
struct core_state core_state;
char corename[CORENAME_MAX_SIZE + 1];
struct mm_struct *mm = current->mm;
struct linux_binfmt * binfmt;
struct inode * inode;
struct file * file;
int retval = 0;
int ispipe = 0;
unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;

Neil Horman
committed
char **helper_argv = NULL;
int helper_argc = 0;
char *delimit;
binfmt = current->binfmt;
if (!binfmt || !binfmt->core_dump)
goto fail;
down_write(&mm->mmap_sem);
/*
* If another thread got here first, or we are not dumpable, bail out.
*/
if (mm->core_state || !get_dumpable(mm)) {
/*
* We cannot trust fsuid as being the "true" uid of the
* process nor do we know its entire history. We only know it
* was tainted so we dump it as root in mode 2.
*/
if (get_dumpable(mm) == 2) { /* Setuid core dump mode */
flag = O_EXCL; /* Stop rewrite attacks */
current->fsuid = 0; /* Dump root private */
}
retval = coredump_wait(exit_code, &core_state);
/*
* Clear any false indication of pending signals that might
* be seen by the filesystem code called to write the core file.
*/
clear_thread_flag(TIF_SIGPENDING);
/*
* lock_kernel() because format_corename() is controlled by sysctl, which
* uses lock_kernel()
*/
lock_kernel();
ispipe = format_corename(corename, retval, signr);
/*
* Don't bother to check the RLIMIT_CORE value if core_pattern points
* to a pipe. Since we're not writing directly to the filesystem
* RLIMIT_CORE doesn't really apply, as no actual core file will be
* created unless the pipe reader choses to write out the core file
* at which point file size limits and permissions will be imposed
* as it does with any other process
*/

Neil Horman
committed
if ((!ispipe) && (core_limit < binfmt->min_coredump))
goto fail_unlock;
if (ispipe) {

Neil Horman
committed
helper_argv = argv_split(GFP_KERNEL, corename+1, &helper_argc);
/* Terminate the string before the first option */
delimit = strchr(corename, ' ');
if (delimit)
*delimit = '\0';
delimit = strrchr(helper_argv[0], '/');
if (delimit)
delimit++;
else
delimit = helper_argv[0];
if (!strcmp(delimit, current->comm)) {
printk(KERN_NOTICE "Recursive core dump detected, "
"aborting\n");
goto fail_unlock;
}
core_limit = RLIM_INFINITY;
/* SIGPIPE can happen, but it's just never processed */
if (call_usermodehelper_pipe(corename+1, helper_argv, NULL,
&file)) {
printk(KERN_INFO "Core dump to %s pipe failed\n",
corename);
goto fail_unlock;
}
} else
file = filp_open(corename,
O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag,
0600);
inode = file->f_path.dentry->d_inode;
if (inode->i_nlink > 1)
goto close_fail; /* multiple links - don't dump */
if (!ispipe && d_unhashed(file->f_path.dentry))
/* AK: actually i see no reason to not allow this for named pipes etc.,
but keep the previous behaviour for now. */
if (!ispipe && !S_ISREG(inode->i_mode))
/*
* Dont allow local users get cute and trick others to coredump
* into their pre-created files:
*/
if (inode->i_uid != current->fsuid)
goto close_fail;
if (!file->f_op)
goto close_fail;
if (!file->f_op->write)
goto close_fail;
if (!ispipe && do_truncate(file->f_path.dentry, 0, 0, file) != 0)
retval = binfmt->core_dump(signr, regs, file, core_limit);
if (retval)
current->signal->group_exit_code |= 0x80;
close_fail:
filp_close(file, NULL);
fail_unlock:

Neil Horman
committed
if (helper_argv)
argv_free(helper_argv);