TIB Custom Storage
Asked Answered
T

2

2

After quite a bit of googling and some hints given here, I finally managed to find a layout of the FS segment (used by windows to store TIB data). Of particular interest to me is the ArbitraryUserPointer member provided in the PSDK:

typedef struct _NT_TIB {
    struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList;
    PVOID StackBase;
    PVOID StackLimit;
    PVOID SubSystemTib;
    union {
        PVOID FiberData;
        DWORD Version;
    };
    PVOID ArbitraryUserPointer;
    struct _NT_TIB *Self;
} NT_TIB;

How safe exactly is it to use this variable (under Vista and above)? and does it still exist on x64?

Secondary to that is the access of this variable. I'm using MSVC, and as such I have access to the __readfsdword & __readgsqword intrinsics, however, MSDN for some reason marks these as privileged instructions:

These intrinsics are only available in kernel mode, and the routines are only available as intrinsics.

They are of course not kernel only, but why are they marked as such, just incorrect documentation? (my offline VS 2008 docs don't have this clause).

Finally, is it safe to access ArbitraryUserPointer directly via a single __readfsdword(0x14) or is it preferred to use it via the linear TIB address? (which will still require a read from FS).

Tetchy answered 13/2, 2012 at 13:34 Comment(0)
S
4

ArbitraryUserPointer is an internal field not for general use. The operating system uses it internally, and if you overwrite it, you will corrupt stuff. I concede that it has a very poor name.

Spirograph answered 13/2, 2012 at 17:11 Comment(9)
hmm, thats disappointing, especially since the older MSVC article has it marked down as application managed. Is there any documentation anywhere as to which members are application managed vs OS managed? I'm basically looking for somewhere to hide a pointer thats not TLS basedTetchy
TLS is the only thing I can think of in the TEB that applications have free use of. (If there were something else like ArbitraryUserPointer, how would two DLLs negotiate control over it?)Spirograph
I can't hi-jiack the SEH/stack security token at all? (I can guarentee I won't have any SEH/security token in what I want to use this for). other than that I guess I'll just stick to __declspec(thread) for my singular per-thread data...Tetchy
TLS is the supported way of creating per-thread data. You haven't given any reason why you cannot use it.Spirograph
Its for a JIT'ed fibers, so I might not be able to have the TLS inited correctly. thats why I only need one pointer, for the generation contextTetchy
Not sure what you mean, but you can use FLS for fiber-local storage.Spirograph
Raymond, one potential use of the ArbitraryUserPointer is as a way of embedding user data (such as a thread name) in any thread in a way that's easily accessible via the debugger watch window. Is it possible to do this with TLS and access that data in the watch window?Costumier
To clarify my earlier question, the problem with using TLS for the purpose I described is that we have no way of knowing for a given thread which of the TlsSlots / TlsExpansionSlots in the TEB structure the data can be found in, short of manually examining each slot.Costumier
You can put the TLS slot number in a global variable with a well-known name. The debugger can read the value of that variable to learn the slot number.Spirograph
M
0

In case you're still for an answer, I've had the same problem too and posted my question, similar to yours:

Thread-local storage in kernel mode?

I need a TLS-equivalent in the kernel-mode driver. To be exact, I have a deep function call tree which originates at some point (driver's dispatch routine for instance), and I need to pass the context information.

In my specific case the catch is that I don't need a persistent storage, I just need a thread-specific placeholder for something for a single top-level function call. Hence I decided to use an arbitrary entry in the TLS array for the function call, and after it's done - restore its original value.

You get the TLS array by the following:

DWORD* get_Tls()
{
    return (DWORD*) (__readfsdword(0x18) + 0xe10);
}

BTW I have no idea why the TIB is usually accessed by reading the contents of fs:[0x18]. It's just pointed by the fs selector. But this is how all the MS's code accesses it, hence I decided to do this as well.

Next, you choose an arbitrary TLS index, say 0.

const DWORD g_dwMyTlsIndex = 0;

void MyTopLevelFunc()
{
    // prolog
    DWORD dwOrgVal = get_Tls()[g_dwMyTlsIndex];
    get_Tls()[g_dwMyTlsIndex] = dwMyContextValue;

    DoSomething();

    // epilog
    get_Tls()[g_dwMyTlsIndex] = dwOrgVal;
}

void DoSomething()
{
    DWORD dwMyContext = get_Tls()[g_dwMyTlsIndex];
}
Mistress answered 1/4, 2012 at 11:49 Comment(1)
I was using this before I asked this question, my issue is I need persistent storage without relying on TLS, so for now I'm using dummy __declspec(thread) varsTetchy

© 2022 - 2024 — McMap. All rights reserved.