The mm_struct structure has two members called env_start and env_end, both of them are user space linear addresses, so you can easily get the starting address of the environment ( env_start ) and the length (env_end - env_start).
The problem is how do you access to this env. buffer while you are in kernel mode. You cannot simply use copy_from_user, because the current pgd (current->pgd) is not the same as the task pgd you want to get the environment.
Does the kernel provide any method to copy data from user space using a different pgd ? If it does, I could not find it yet.
I wrote a function that do this (copy_from_user_space() ) and another one to dump the environment of a task (using its pid) to the kernel ring buffer. (I have just tested over i386).
If someone knows a more efficient (or elegant) way of do this, please let me know.
Best Regards.
int copy_from_user_space(void *to, void *from, struct mm_struct *mm, unsigned long n)
{
unsigned long copied = 0;
pgd_t *pgd = pgd_offset(mm, (unsigned long) from);
pud_t *pud;
pmd_t *pmd;
pte_t *ptep, pte;
struct page *page;
unsigned long src_offset = (unsigned long)from & (PAGE_SIZE - 1);
while (copied < n)
{
unsigned long bytes_to_end = PAGE_SIZE - src_offset;
page = NULL;
bytes_to_end = ( bytes_to_end < (n-copied) ) ? bytes_to_end : (n-copied);
if (!pgd_none(*pgd)) {
pud = pud_offset(pgd, (unsigned long) from);
if (!pud_none(*pud)) {
pmd = pmd_offset(pud, (unsigned long) from);
if (!pmd_none(*pmd)) {
ptep = pte_offset_map(pmd, (unsigned long) from);
pte = *ptep;
if (pte_present(pte)) {
page = pte_page(pte);
}
pte_unmap(ptep);
}
}
}
if (page)
{
void *addr = kmap(page);
memcpy(to + copied, addr + src_offset, bytes_to_end);
kunmap(page);
copied += bytes_to_end;
}
else {
return -1;
}
src_offset = 0;
}
return 0;
}
int dump_env(int pid)
{
struct task_struct *task;
struct mm_struct *mm;
int i;
char *buff;
int buff_len;
unsigned long ret;
printk("pid %d\n", pid);
if (pid==-1)
return -1;
task = find_task_by_pid(pid);
if (!task)
{
printk("could not find task\n");
return -1;
}
if (task->comm)
printk("Task: %s\n", task->comm);
mm = task->mm;
buff_len = mm->env_end - mm->env_start;
buff = kmalloc( buff_len, GFP_KERNEL);
if (!buff)
return -1;
ret = copy_from_user_space( buff, (void *) mm->env_start, mm, buff_len);
printk("**************** Environment *****************\n");
for(i=0 ; i<buff_len ; i++)
{
printk("%c", buff[i] ? buff[i] : '\n');
}
printk("\n********************************************\n");
kfree(buff);
return 0;
}
On Jan 29, 2008 11:17 AM, Manish Katiyar <mkatiyar@xxxxxxxxx> wrote:
Hi,
Is it possible to print or access the environment variables of a
process from kernel module. I know it can be done from userspace, but
if there is a running process I don't know if there is any way to
access/print the environment of a process from userspace. So I thought
if it is possible to write a module which accepts a pid during load
and then prints its environment variables.
I tried looking at task_struct to see which member holds the
environment, but cudnt get much. Any help appreciated.
--
Thanks & Regards,
********************************************
Manish Katiyar ( http://mkatiyar.googlepages.com )
3rd Floor, Fair Winds Block
EGL Software Park
Off Intermediate Ring Road
Bangalore 560071, India
***********************************************
--
To unsubscribe from this list: send an email with
"unsubscribe kernelnewbies" to ecartis@xxxxxxxxxxxx
Please read the FAQ at http://kernelnewbies.org/FAQ