0

I'm doing kext development at XNU kernel, there is KPI function called copyin and its friends, similar to copy_from_user at Linux kernel

So I'm using copyin at most time, it's more secure processing data at kernelspace rather than relatively volatile userspace, but sometime i need process a quite large amount of memory(eg 2MB) from userspace, and i only need to read, could that be a excuse for directly access userspace memory ? (could that cause unexpected problem?)

The data from userspace has entries, so i only need read at least each time, besides I don't need to do any write on this memory neither from userspace process, I list three ways that just i could think about, hope someone could give me advice, i am really appreciate that!

  1. Alloc enough size pageable memory (IOMallocPageable) at kernel space, and calling copyin to copy the whole data from userspace
  2. Alloc also alloc pageable memory, and size is enough for one entry, use copyin to read and process then read again to same memory
  3. Use stac disable smap, directly read from userspace

First way, if i don't do writing, could that be mapping to same physical map, so doesn't need waster memory? Which way is more efficiency?

cocoa
  • 11
  • 6
  • What kind of data are you processing? What if data is changing while you are processing it? –  Dec 08 '17 at 14:03
  • *(could that cause unexpected problem?)* Depending on what you're doing it can cause all kinds of security issues. If you validate the data for security purposes, the process can then change the data. For example, say your driver will read a file and return data to the process. You read in the file name, and verify the user has permission to open and read it. Then you open it, read it, and pass the data to the process. In between the permission check and the actual reading of data, the process changes the name to `/etc/shadow` and gets all users' hashed passwords for offline cracking. – Andrew Henle Dec 08 '17 at 14:04
  • A list of entry structure, I have to read each of them doing calculation. I ensure proc is locked during the data been read – cocoa Dec 08 '17 at 14:06
  • @cocoa Are you sure if you can guarantee userspace threads are stopped? What is someone else resumes them? What if this memory is also available to another process (shared mapping)? –  Dec 08 '17 at 14:07
  • @cocoa Even though accessing userspace memory might be possible, it might be hard to do it correctly. Depending on how you process your data, you might consider using statefull API. You situation might or might not be similar to C10k problem which is solved by switching from `poll`/`select` to `epoll`/`kqueue`. –  Dec 08 '17 at 14:11
  • @AndrewHenle This data is for userspace using, so doesn't contain sensitive info. and will not read for change settings of kernel, so there shouldn't has security issues – cocoa Dec 08 '17 at 14:11
  • @ivan I am sure about that, cause the proc is interrupted since the data was appear in user space, so i am wondering will it has unexpected problems during reading – cocoa Dec 08 '17 at 14:13
  • @cocoa But what about shared mappings? What if process opens `/proc//mem`? Accessing it might be possible if you can ensure it is not unmapped while you are reading it, not swapped-out while you are running with IRQ disabled etc. –  Dec 08 '17 at 14:21
  • @Ivan yes, that is possible, hmm, but that should could also happen to copy_from_user(copyin in XNU), is it? – cocoa Dec 08 '17 at 14:26
  • @cocoa The problem is that you might process data, then return to it little later assuming it didn't change, but it did. Whatever you read from userspace, it becomes invalid immediately after reading. With `copy_from_user` you can assume data is not changing. So you are basically forced to copy data to kernel space anyway. Unless your data processing is very "dumb". –  Dec 08 '17 at 14:35
  • @Ivan thank you for comments, I'm going to do testing – cocoa Dec 08 '17 at 15:08
  • Hi, did you consider using iokit commands such as `IOConnectCallScalarMethod` where you can pass one entry at a time, and the `copyin` is already done for you... – Zohar81 Dec 09 '17 at 13:40
  • @Zohar81 thanks for reply, I'm not communicating with userland process, the data was written to that process vm by kernel, and I trying to read that data – cocoa Dec 09 '17 at 13:44
  • So if I understand you right, there are 2 entities in your game, kernel extension and user-mode process. your kext write some data to the process VM (how?) and you try to read that data from the kernel (can you assume that the data is not subject to change ? ) in that case, you may define `IOMemoryDescriptor` and play with the permissions.. but I'm not sure what are you really up to .. perhaps you can publish some source code ? – Zohar81 Dec 09 '17 at 14:06
  • @Zohar81 the data in userland proc is written by calling syscall, I read data right after syscall completed, the syscall only allow the parameters a pointer point to userspace vm, the internal implementation of the syscall is quite complicated, don't think copy the process to my kext is good idea – cocoa Dec 09 '17 at 14:14
  • @Zohar81 May i ask question? — to process a large amount data from userspace vm. Between allocate a large memory (enough for use) and read from userland just by one time. Another way is iterates in entries first, get largest length that will be need, then read one entry from userspace vm each time. Which way is saving more cpu resources? – cocoa Dec 09 '17 at 14:21

1 Answers1

0

If you have the userspace address you can remap it to kernel - use IOMemoryDescriptor::withAddressRange with the relevant task (process task) and map it to kernel with IOMemoryDescriptor::createMappingInTask.

Make sure the permissions are correct.

Just a friendly tip - the stac/clac instructions are overwritten by the context switch code handler and you will have to make sure it's not being called during your copying phase. Done it - not very fun.

mrdvlpr
  • 526
  • 4
  • 20
  • Really great advice, helpful for mapping user space memory to kernel space or kernel memory to user space both! – cocoa Dec 19 '17 at 18:03