cregit-Linux how code gets into the kernel

Release 4.10 arch/x86/kernel/ldt.c

Directory: arch/x86/kernel
/*
 * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
 * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
 * Copyright (C) 2002 Andi Kleen
 *
 * This handles calls from both 32bit and 64bit mode.
 */

#include <linux/errno.h>
#include <linux/gfp.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/uaccess.h>

#include <asm/ldt.h>
#include <asm/desc.h>
#include <asm/mmu_context.h>
#include <asm/syscalls.h>

/* context.lock is held for us, so we don't need any locking. */

static void flush_ldt(void *current_mm) { mm_context_t *pc; if (current->active_mm != current_mm) return; pc = &current->active_mm->context; set_ldt(pc->ldt->entries, pc->ldt->size); }

Contributors

PersonTokensPropCommitsCommitProp
andy lutomirskiandy lutomirski2246.81%125.00%
dave jonesdave jones2144.68%125.00%
jan beulichjan beulich24.26%125.00%
manfred spraulmanfred spraul24.26%125.00%
Total47100.00%4100.00%

/* The caller must call finalize_ldt_struct on the result. LDT starts zeroed. */
static struct ldt_struct *alloc_ldt_struct(unsigned int size) { struct ldt_struct *new_ldt; unsigned int alloc_size; if (size > LDT_ENTRIES) return NULL; new_ldt = kmalloc(sizeof(struct ldt_struct), GFP_KERNEL); if (!new_ldt) return NULL; BUILD_BUG_ON(LDT_ENTRY_SIZE != sizeof(struct desc_struct)); alloc_size = size * LDT_ENTRY_SIZE; /* * Xen is very picky: it requires a page-aligned LDT that has no * trailing nonzero bytes in any page that contains LDT descriptors. * Keep it simple: zero the whole allocation and never allocate less * than PAGE_SIZE. */ if (alloc_size > PAGE_SIZE) new_ldt->entries = vzalloc(alloc_size); else new_ldt->entries = (void *)get_zeroed_page(GFP_KERNEL); if (!new_ldt->entries) { kfree(new_ldt); return NULL; } new_ldt->size = size; return new_ldt; }

Contributors

PersonTokensPropCommitsCommitProp
andy lutomirskiandy lutomirski7358.87%114.29%
dave jonesdave jones4133.06%114.29%
jan beulichjan beulich64.84%228.57%
cyrill gorcunovcyrill gorcunov21.61%114.29%
dan carpenterdan carpenter10.81%114.29%
thomas gleixnerthomas gleixner10.81%114.29%
Total124100.00%7100.00%

/* After calling this, the LDT is immutable. */
static void finalize_ldt_struct(struct ldt_struct *ldt) { paravirt_alloc_ldt(ldt->entries, ldt->size); }

Contributors

PersonTokensPropCommitsCommitProp
andy lutomirskiandy lutomirski1568.18%125.00%
dave jonesdave jones418.18%125.00%
jeremy fitzhardingejeremy fitzhardinge29.09%125.00%
ingo molnaringo molnar14.55%125.00%
Total22100.00%4100.00%

/* context.lock is held */
static void install_ldt(struct mm_struct *current_mm, struct ldt_struct *ldt) { /* Synchronizes with lockless_dereference in load_mm_ldt. */ smp_store_release(&current_mm->context.ldt, ldt); /* Activate the LDT for all CPUs using current_mm. */ on_each_cpu_mask(mm_cpumask(current_mm), flush_ldt, current_mm, true); }

Contributors

PersonTokensPropCommitsCommitProp
andy lutomirskiandy lutomirski2965.91%120.00%
dave jonesdave jones715.91%120.00%
andrew mortonandrew morton511.36%240.00%
rusty russellrusty russell36.82%120.00%
Total44100.00%5100.00%


static void free_ldt_struct(struct ldt_struct *ldt) { if (likely(!ldt)) return; paravirt_free_ldt(ldt->entries, ldt->size); if (ldt->size * LDT_ENTRY_SIZE > PAGE_SIZE) vfree_atomic(ldt->entries); else free_page((unsigned long)ldt->entries); kfree(ldt); }

Contributors

PersonTokensPropCommitsCommitProp
andy lutomirskiandy lutomirski3249.23%120.00%
dave jonesdave jones2132.31%120.00%
jeremy fitzhardingejeremy fitzhardinge69.23%120.00%
jan beulichjan beulich57.69%120.00%
andrey ryabininandrey ryabinin11.54%120.00%
Total65100.00%5100.00%

/* * we do not have to muck with descriptors here, that is * done in switch_mm() as needed. */
int init_new_context_ldt(struct task_struct *tsk, struct mm_struct *mm) { struct ldt_struct *new_ldt; struct mm_struct *old_mm; int retval = 0; mutex_init(&mm->context.lock); old_mm = current->mm; if (!old_mm) { mm->context.ldt = NULL; return 0; } mutex_lock(&old_mm->context.lock); if (!old_mm->context.ldt) { mm->context.ldt = NULL; goto out_unlock; } new_ldt = alloc_ldt_struct(old_mm->context.ldt->size); if (!new_ldt) { retval = -ENOMEM; goto out_unlock; } memcpy(new_ldt->entries, old_mm->context.ldt->entries, new_ldt->size * LDT_ENTRY_SIZE); finalize_ldt_struct(new_ldt); mm->context.ldt = new_ldt; out_unlock: mutex_unlock(&old_mm->context.lock); return retval; }

Contributors

PersonTokensPropCommitsCommitProp
andy lutomirskiandy lutomirski8448.55%120.00%
dave jonesdave jones7442.77%120.00%
jeremy fitzhardingejeremy fitzhardinge105.78%120.00%
luiz fernando capitulinoluiz fernando capitulino42.31%120.00%
dave hansendave hansen10.58%120.00%
Total173100.00%5100.00%

/* * No need to lock the MM as we are the last user * * 64bit: Don't touch the LDT register - we're already in the next thread. */
void destroy_context_ldt(struct mm_struct *mm) { free_ldt_struct(mm->context.ldt); mm->context.ldt = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
dave jonesdave jones1659.26%133.33%
andy lutomirskiandy lutomirski1037.04%133.33%
dave hansendave hansen13.70%133.33%
Total27100.00%3100.00%


static int read_ldt(void __user *ptr, unsigned long bytecount) { int retval; unsigned long size; struct mm_struct *mm = current->mm; mutex_lock(&mm->context.lock); if (!mm->context.ldt) { retval = 0; goto out_unlock; } if (bytecount > LDT_ENTRY_SIZE * LDT_ENTRIES) bytecount = LDT_ENTRY_SIZE * LDT_ENTRIES; size = mm->context.ldt->size * LDT_ENTRY_SIZE; if (size > bytecount) size = bytecount; if (copy_to_user(ptr, mm->context.ldt->entries, size)) { retval = -EFAULT; goto out_unlock; } if (size != bytecount) { /* Zero-fill the rest and pretend we read bytecount bytes. */ if (clear_user(ptr + size, bytecount - size)) { retval = -EFAULT; goto out_unlock; } } retval = bytecount; out_unlock: mutex_unlock(&mm->context.lock); return retval; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git6939.88%763.64%
andy lutomirskiandy lutomirski4626.59%19.09%
dave jonesdave jones4224.28%19.09%
jesper juhljesper juhl158.67%19.09%
linus torvaldslinus torvalds10.58%19.09%
Total173100.00%11100.00%


static int read_default_ldt(void __user *ptr, unsigned long bytecount) { /* CHECKME: Can we use _one_ random number ? */ #ifdef CONFIG_X86_32 unsigned long size = 5 * sizeof(struct desc_struct); #else unsigned long size = 128; #endif if (bytecount > size) bytecount = size; if (clear_user(ptr, bytecount)) return -EFAULT; return bytecount; }

Contributors

PersonTokensPropCommitsCommitProp
linus torvaldslinus torvalds4262.69%240.00%
thomas gleixnerthomas gleixner2232.84%120.00%
dave jonesdave jones22.99%120.00%
jeremy fitzhardingejeremy fitzhardinge11.49%120.00%
Total67100.00%5100.00%


static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode) { struct mm_struct *mm = current->mm; struct ldt_struct *new_ldt, *old_ldt; unsigned int oldsize, newsize; struct user_desc ldt_info; struct desc_struct ldt; int error; error = -EINVAL; if (bytecount != sizeof(ldt_info)) goto out; error = -EFAULT; if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info))) goto out; error = -EINVAL; if (ldt_info.entry_number >= LDT_ENTRIES) goto out; if (ldt_info.contents == 3) { if (oldmode) goto out; if (ldt_info.seg_not_present == 0) goto out; } if ((oldmode && !ldt_info.base_addr && !ldt_info.limit) || LDT_empty(&ldt_info)) { /* The user wants to clear the entry. */ memset(&ldt, 0, sizeof(ldt)); } else { if (!IS_ENABLED(CONFIG_X86_16BIT) && !ldt_info.seg_32bit) { error = -EINVAL; goto out; } fill_ldt(&ldt, &ldt_info); if (oldmode) ldt.avl = 0; } mutex_lock(&mm->context.lock); old_ldt = mm->context.ldt; oldsize = old_ldt ? old_ldt->size : 0; newsize = max(ldt_info.entry_number + 1, oldsize); error = -ENOMEM; new_ldt = alloc_ldt_struct(newsize); if (!new_ldt) goto out_unlock; if (old_ldt) memcpy(new_ldt->entries, old_ldt->entries, oldsize * LDT_ENTRY_SIZE); new_ldt->entries[ldt_info.entry_number] = ldt; finalize_ldt_struct(new_ldt); install_ldt(mm, new_ldt); free_ldt_struct(old_ldt); error = 0; out_unlock: mutex_unlock(&mm->context.lock); out: return error; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git15945.69%637.50%
andy lutomirskiandy lutomirski10831.03%16.25%
h. peter anvinh. peter anvin226.32%16.25%
glauber de oliveira costaglauber de oliveira costa216.03%212.50%
thomas gleixnerthomas gleixner154.31%16.25%
zachary amsdenzachary amsden113.16%16.25%
ingo molnaringo molnar72.01%16.25%
luiz fernando capitulinoluiz fernando capitulino20.57%16.25%
dave jonesdave jones20.57%16.25%
linus torvaldslinus torvalds10.29%16.25%
Total348100.00%16100.00%


asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) { int ret = -ENOSYS; switch (func) { case 0: ret = read_ldt(ptr, bytecount); break; case 1: ret = write_ldt(ptr, bytecount, 1); break; case 2: ret = read_default_ldt(ptr, bytecount); break; case 0x11: ret = write_ldt(ptr, bytecount, 0); break; } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git7584.27%571.43%
linus torvaldslinus torvalds1415.73%228.57%
Total89100.00%7100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
andy lutomirskiandy lutomirski42734.86%12.17%
pre-gitpre-git32926.86%1532.61%
dave jonesdave jones23118.86%12.17%
linus torvaldslinus torvalds584.73%24.35%
thomas gleixnerthomas gleixner393.18%24.35%
h. peter anvinh. peter anvin221.80%12.17%
glauber de oliveira costaglauber de oliveira costa211.71%24.35%
jeremy fitzhardingejeremy fitzhardinge191.55%24.35%
jesper juhljesper juhl151.22%12.17%
jan beulichjan beulich131.06%36.52%
zachary amsdenzachary amsden110.90%12.17%
ingo molnaringo molnar80.65%24.35%
luiz fernando capitulinoluiz fernando capitulino60.49%12.17%
andrew mortonandrew morton50.41%24.35%
jaswinder singh rajputjaswinder singh rajput40.33%24.35%
adrian bunkadrian bunk30.24%12.17%
tejun heotejun heo30.24%12.17%
rusty russellrusty russell30.24%12.17%
cyrill gorcunovcyrill gorcunov20.16%12.17%
dave hansendave hansen20.16%12.17%
manfred spraulmanfred spraul20.16%12.17%
andrey ryabininandrey ryabinin10.08%12.17%
dan carpenterdan carpenter10.08%12.17%
Total1225100.00%46100.00%
Directory: arch/x86/kernel
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.