From: arvid.brodin@enea.com (Arvid Brodin)
To: kernelnewbies@lists.kernelnewbies.org
Subject: Build scatterlist covering a process' text segment?
Date: Fri, 17 Jun 2011 02:47:25 +0200 [thread overview]
Message-ID: <4DFAA41D.5010307@enea.com> (raw)
In-Reply-To: <BANLkTim3bwXaGXaeXo7D8ZprNUgCw7CK2g@mail.gmail.com>
Mulyadi Santosa wrote:
> Hi...
>
> On Sat, May 28, 2011 at 04:58, Arvid Brodin <arvid.brodin@enea.com> wrote:
>> Ok. And looking at e.g. sg_set_buf(), the scatterlist expects a kernel virtual
>> address (it uses virt_to_page() on its "buf" parameter internally, which
>> requires a kernel virtual adress, if I understand correctly).
>>
>> There seems to be no way to map process adresses to kernel addresses. (Well I
>> guess one could follow the page tables to get the physical page, and then map
>> back to kernel space, but this only works as long as the memory is paged in.)
>> Please correct me if I'm wrong.
>
> I am not good at it, but I think at the first place, you might use
> get_user_pages() (take a look here
> :http://lxr.linux.no/#linux+v2.6.39/mm/memory.c#L1703)
>
> then once you get the pointer to the pages (and making sure they're
> pinned by get_user_pages), I think you just need to use kmap().
>
> I suggest to really observe that scatter gather function and see if
> address in kernel address space is really needed.... if not, you can
> avoid using kmap() completely.
>
Many thanks for that tip! I've been reading LDD3 ("Linux Device Drivers 3rd
edition") and "Understanding the Linux Kernel" as well as searching google and
of course reading code for many hours, and nowhere has there been a mention of
get_user_pages()! Obviously I haven't been using the right search terms...
(Also, for some reason your mail didn't reach my inbox, so I only saw it a few
days ago when looking at a mail list archive.)
Anyway, the code looks like this now (below), and seems to work on 2.7.37.6. It
will probably have problems on systems with > 896 MiB and high memory enabled
though; I'm thinking the scatterlist functions won't handle virtual kernel
addresses?
Any ideas for improvements are welcome; especially if I'm doing something
stupid that risks a kernel panic.
static int proc_pid_text_checksum(struct seq_file *m, struct pid_namespace *ns,
struct pid *pid, struct task_struct *task)
{
int retval;
int text_size;
int nr_pages, nr_pages_mapped;
int i;
struct page **pages;
struct scatterlist *sgl, *sg;
u8 result[MD5_DIGEST_SIZE + 2];
struct crypto_hash *tfm;
struct hash_desc desc;
retval = 0;
if (!task->mm)
return -EINVAL;
text_size = task->mm->end_code - task->mm->start_code;
nr_pages = (text_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
/**** User page code ****/
pages = kmalloc(nr_pages * sizeof(*pages), GFP_KERNEL);
if (!pages) {
retval = -ENOMEM;
goto err_pages;
}
down_read(&task->mm->mmap_sem);
nr_pages_mapped = get_user_pages(current, task->mm,
task->mm->start_code, nr_pages, 0, 0, pages, NULL);
up_read(&task->mm->mmap_sem);
if (nr_pages_mapped < nr_pages) {
retval = -EBUSY; /* Weird error code for this,
couldn't find any better */
goto err_mapped;
}
/**** Scatterlist code ****/
sgl = kmalloc(nr_pages_mapped * sizeof(*sgl), GFP_KERNEL);
if (!sgl) {
retval = -ENOMEM;
goto err_sg;
}
sg_init_table(sgl, nr_pages_mapped);
for_each_sg(sgl, sg, nr_pages_mapped, i)
sg_set_page(sg, pages[i], (i < nr_pages_mapped) ? PAGE_SIZE :
text_size & ~PAGE_MASK, 0);
/**** Crypto code ****/
tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(tfm)) {
retval = -ENOMEM;
goto err_crypto;
}
desc.tfm = tfm;
desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
memset(result, 0, MD5_DIGEST_SIZE + 2);
retval = crypto_hash_digest(&desc, sgl, text_size, result);
if (retval)
goto err_digest;
for (i = 0; i < MD5_DIGEST_SIZE; i++)
seq_printf(m, "%02x", result[i]);
seq_printf(m, "\n");
err_digest:
crypto_free_hash(tfm);
err_crypto:
kfree(sgl);
for (i = 0; i < nr_pages_mapped; i++)
put_page(pages[i]);
err_sg:
err_mapped:
kfree(pages);
err_pages:
return retval;
}
--
Arvid Brodin
Enea Services Stockholm AB
next prev parent reply other threads:[~2011-06-17 0:47 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-05-23 23:06 Build scatterlist covering a process' text segment? Arvid Brodin
2011-05-25 20:27 ` Arvid Brodin
2011-05-26 4:02 ` Mulyadi Santosa
2011-05-27 21:58 ` Arvid Brodin
2011-05-28 9:42 ` Mulyadi Santosa
2011-06-17 0:47 ` Arvid Brodin [this message]
2011-06-17 15:10 ` Jonathan Neuschäfer
2011-06-17 15:18 ` Metin KAYA
2011-06-17 17:59 ` Dave Hylands
2011-06-17 18:46 ` Jonathan Neuschäfer
2011-06-17 18:53 ` Dave Hylands
2011-06-17 19:00 ` Jonathan Neuschäfer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4DFAA41D.5010307@enea.com \
--to=arvid.brodin@enea.com \
--cc=kernelnewbies@lists.kernelnewbies.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).