X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=libcfs%2Flibcfs%2Flinux%2Flinux-curproc.c;h=eb9f91509df6e167c102f741af2ebbfdcd030d7a;hb=9fa85c69c9e582874f52473e2612407a82319cb6;hp=be377238692de1326f6a15235bbe1ef803c543b9;hpb=1932a135cf8cedcea2d0f2d5be21edd7fe306251;p=fs%2Flustre-release.git diff --git a/libcfs/libcfs/linux/linux-curproc.c b/libcfs/libcfs/linux/linux-curproc.c index be37723..eb9f915 100644 --- a/libcfs/libcfs/linux/linux-curproc.c +++ b/libcfs/libcfs/linux/linux-curproc.c @@ -1,6 +1,4 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * +/* * GPL HEADER START * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -26,8 +24,10 @@ * GPL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. + * + * Copyright (c) 2011, 2012, Intel Corporation. */ /* * This file is part of Lustre, http://www.lustre.org/ @@ -41,6 +41,10 @@ */ #include +#include + +#include +#include #define DEBUG_SUBSYSTEM S_LNET @@ -53,22 +57,32 @@ uid_t cfs_curproc_uid(void) { - return current->uid; + return current_uid(); } gid_t cfs_curproc_gid(void) { - return current->gid; + return current_gid(); } uid_t cfs_curproc_fsuid(void) { - return current->fsuid; + return current_fsuid(); +} + +uid_t cfs_curproc_euid(void) +{ + return current_euid(); +} + +uid_t cfs_curproc_egid(void) +{ + return current_egid(); } gid_t cfs_curproc_fsgid(void) { - return current->fsgid; + return current_fsgid(); } pid_t cfs_curproc_pid(void) @@ -80,28 +94,18 @@ int cfs_curproc_groups_nr(void) { int nr; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,4) task_lock(current); - nr = current->group_info->ngroups; + nr = current_cred()->group_info->ngroups; task_unlock(current); -#else - nr = current->ngroups; -#endif return nr; } void cfs_curproc_groups_dump(gid_t *array, int size) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,4) task_lock(current); - size = min_t(int, size, current->group_info->ngroups); - memcpy(array, current->group_info->blocks[0], size * sizeof(__u32)); + size = min_t(int, size, current_cred()->group_info->ngroups); + memcpy(array, current_cred()->group_info->blocks[0], size * sizeof(__u32)); task_unlock(current); -#else - LASSERT(size <= NGROUPS); - size = min_t(int, size, current->ngroups); - memcpy(array, current->groups, size * sizeof(__u32)); -#endif } @@ -126,54 +130,251 @@ char *cfs_curproc_comm(void) void cfs_cap_raise(cfs_cap_t cap) { - cap_raise(cfs_current()->cap_effective, cfs_cap_unpack(cap)); + struct cred *cred; + if ((cred = prepare_creds())) { + cap_raise(cred->cap_effective, cfs_cap_unpack(cap)); + commit_creds(cred); + } } void cfs_cap_lower(cfs_cap_t cap) { - cap_lower(cfs_current()->cap_effective, cfs_cap_unpack(cap)); + struct cred *cred; + if ((cred = prepare_creds())) { + cap_lower(cred->cap_effective, cfs_cap_unpack(cap)); + commit_creds(cred); + } } int cfs_cap_raised(cfs_cap_t cap) { - return cap_raised(cfs_current()->cap_effective, cfs_cap_unpack(cap)); + return cap_raised(current_cap(), cfs_cap_unpack(cap)); } -cfs_cap_t cfs_curproc_cap_pack(void) +void cfs_kernel_cap_pack(cfs_kernel_cap_t kcap, cfs_cap_t *cap) { #if defined (_LINUX_CAPABILITY_VERSION) && _LINUX_CAPABILITY_VERSION == 0x19980330 - return cfs_cap_pack(current->cap_effective); + *cap = cfs_cap_pack(kcap); #elif defined (_LINUX_CAPABILITY_VERSION) && _LINUX_CAPABILITY_VERSION == 0x20071026 - return cfs_cap_pack(current->cap_effective[0]); + *cap = cfs_cap_pack(kcap[0]); #elif defined(_KERNEL_CAPABILITY_VERSION) && _KERNEL_CAPABILITY_VERSION == 0x20080522 /* XXX lost high byte */ - return cfs_cap_pack(current->cap_effective.cap[0]); + *cap = cfs_cap_pack(kcap.cap[0]); #else #error "need correct _KERNEL_CAPABILITY_VERSION " #endif } -void cfs_curproc_cap_unpack(cfs_cap_t cap) +void cfs_kernel_cap_unpack(cfs_kernel_cap_t *kcap, cfs_cap_t cap) { #if defined (_LINUX_CAPABILITY_VERSION) && _LINUX_CAPABILITY_VERSION == 0x19980330 - current->cap_effective = cfs_cap_unpack(cap); + *kcap = cfs_cap_unpack(cap); #elif defined (_LINUX_CAPABILITY_VERSION) && _LINUX_CAPABILITY_VERSION == 0x20071026 - current->cap_effective[0] = cfs_cap_unpack(cap); + (*kcap)[0] = cfs_cap_unpack(cap); #elif defined(_KERNEL_CAPABILITY_VERSION) && _KERNEL_CAPABILITY_VERSION == 0x20080522 - current->cap_effective.cap[0] = cfs_cap_unpack(cap); + kcap->cap[0] = cfs_cap_unpack(cap); #else #error "need correct _KERNEL_CAPABILITY_VERSION " #endif } +cfs_cap_t cfs_curproc_cap_pack(void) +{ + cfs_cap_t cap; + cfs_kernel_cap_pack(current_cap(), &cap); + return cap; +} + +void cfs_curproc_cap_unpack(cfs_cap_t cap) +{ + struct cred *cred; + if ((cred = prepare_creds())) { + cfs_kernel_cap_unpack(&cred->cap_effective, cap); + commit_creds(cred); + } +} + int cfs_capable(cfs_cap_t cap) { return capable(cfs_cap_unpack(cap)); } +/* Check if task is running in 32-bit API mode, for the purpose of + * userspace binary interfaces. On 32-bit Linux this is (unfortunately) + * always true, even if the application is using LARGEFILE64 and 64-bit + * APIs, because Linux provides no way for the filesystem to know if it + * is called via 32-bit or 64-bit APIs. Other clients may vary. On + * 64-bit systems, this will only be true if the binary is calling a + * 32-bit system call. */ +int cfs_curproc_is_32bit(void) +{ +#ifdef HAVE_IS_COMPAT_TASK + return is_compat_task(); +#else + return (BITS_PER_LONG == 32); +#endif +} + +static int cfs_access_process_vm(struct task_struct *tsk, unsigned long addr, + void *buf, int len, int write) +{ +#ifdef HAVE_ACCESS_PROCESS_VM + return access_process_vm(tsk, addr, buf, len, write); +#else + /* Just copied from kernel for the kernels which doesn't + * have access_process_vm() exported */ + struct mm_struct *mm; + struct vm_area_struct *vma; + struct page *page; + void *old_buf = buf; + + mm = get_task_mm(tsk); + if (!mm) + return 0; + + down_read(&mm->mmap_sem); + /* ignore errors, just check how much was sucessfully transfered */ + while (len) { + int bytes, rc, offset; + void *maddr; + + rc = get_user_pages(tsk, mm, addr, 1, + write, 1, &page, &vma); + if (rc <= 0) + break; + + bytes = len; + offset = addr & (PAGE_SIZE-1); + if (bytes > PAGE_SIZE-offset) + bytes = PAGE_SIZE-offset; + + maddr = kmap(page); + if (write) { + copy_to_user_page(vma, page, addr, + maddr + offset, buf, bytes); + set_page_dirty_lock(page); + } else { + copy_from_user_page(vma, page, addr, + buf, maddr + offset, bytes); + } + kunmap(page); + page_cache_release(page); + len -= bytes; + buf += bytes; + addr += bytes; + } + up_read(&mm->mmap_sem); + mmput(mm); + + return buf - old_buf; +#endif /* HAVE_ACCESS_PROCESS_VM */ +} + +/* Read the environment variable of current process specified by @key. */ +int cfs_get_environ(const char *key, char *value, int *val_len) +{ + struct mm_struct *mm; + char *buffer, *tmp_buf = NULL; + int buf_len = CFS_PAGE_SIZE; + int key_len = strlen(key); + unsigned long addr; + int rc; + ENTRY; + + buffer = cfs_alloc(buf_len, CFS_ALLOC_USER); + if (!buffer) + RETURN(-ENOMEM); + + mm = get_task_mm(current); + if (!mm) { + cfs_free(buffer); + RETURN(-EINVAL); + } + + /* Avoid deadlocks on mmap_sem if called from sys_mmap_pgoff(), + * which is already holding mmap_sem for writes. If some other + * thread gets the write lock in the meantime, this thread will + * block, but at least it won't deadlock on itself. LU-1735 */ + if (down_read_trylock(&mm->mmap_sem) == 0) + return -EDEADLK; + up_read(&mm->mmap_sem); + + addr = mm->env_start; + while (addr < mm->env_end) { + int this_len, retval, scan_len; + char *env_start, *env_end; + + memset(buffer, 0, buf_len); + + this_len = min_t(int, mm->env_end - addr, buf_len); + retval = cfs_access_process_vm(current, addr, buffer, + this_len, 0); + if (retval != this_len) + break; + + addr += retval; + + /* Parse the buffer to find out the specified key/value pair. + * The "key=value" entries are separated by '\0'. */ + env_start = buffer; + scan_len = this_len; + while (scan_len) { + char *entry; + int entry_len; + + env_end = memscan(env_start, '\0', scan_len); + LASSERT(env_end >= env_start && + env_end <= env_start + scan_len); + + /* The last entry of this buffer cross the buffer + * boundary, reread it in next cycle. */ + if (unlikely(env_end - env_start == scan_len)) { + /* This entry is too large to fit in buffer */ + if (unlikely(scan_len == this_len)) { + CERROR("Too long env variable.\n"); + GOTO(out, rc = -EINVAL); + } + addr -= scan_len; + break; + } + + entry = env_start; + entry_len = env_end - env_start; + + /* Key length + length of '=' */ + if (entry_len > key_len + 1 && + !memcmp(entry, key, key_len)) { + entry += key_len + 1; + entry_len -= key_len + 1; + /* The 'value' buffer passed in is too small.*/ + if (entry_len >= *val_len) + GOTO(out, rc = -EOVERFLOW); + + memcpy(value, entry, entry_len); + *val_len = entry_len; + GOTO(out, rc = 0); + } + + scan_len -= (env_end - env_start + 1); + env_start = env_end + 1; + } + } + GOTO(out, rc = -ENOENT); + +out: + mmput(mm); + cfs_free((void *)buffer); + if (tmp_buf) + cfs_free((void *)tmp_buf); + return rc; +} +EXPORT_SYMBOL(cfs_get_environ); + EXPORT_SYMBOL(cfs_curproc_uid); EXPORT_SYMBOL(cfs_curproc_pid); +EXPORT_SYMBOL(cfs_curproc_euid); EXPORT_SYMBOL(cfs_curproc_gid); +EXPORT_SYMBOL(cfs_curproc_egid); EXPORT_SYMBOL(cfs_curproc_fsuid); EXPORT_SYMBOL(cfs_curproc_fsgid); EXPORT_SYMBOL(cfs_curproc_umask); @@ -187,6 +388,7 @@ EXPORT_SYMBOL(cfs_cap_raised); EXPORT_SYMBOL(cfs_curproc_cap_pack); EXPORT_SYMBOL(cfs_curproc_cap_unpack); EXPORT_SYMBOL(cfs_capable); +EXPORT_SYMBOL(cfs_curproc_is_32bit); /* * Local variables: