Using thread-specific credentials on Linux in Samba with glibc.

Jeremy Allison jra@samba.org
Mon Jul 2 16:57:00 GMT 2012


On Mon, Jul 02, 2012 at 10:20:36PM +0530, Siddhesh Poyarekar wrote:
> On 2 July 2012 21:47, Jeremy Allison <jra@samba.org> wrote:
> > Happily, this doesn't require any changes in
> > glibc, as I have wrappers for all the credentials
> > changing code in Samba that I just redirect to
> > change from doing something like:
> >
> > ret = setresuid(ruid, euid, suid);
> >
> > to:
> >
> > ret = syscall(SYS_setresuid, ruid, euid, suid);
> >
> > and everything still works (modulo 32-bit/64-bit
> > call differences of course :-).
> >
> > So my question is - can we rely on glibc not to
> > break our usage of this in the future ? One of
> > the Samba developers is paranoid about glibc breaking
> > this ability by changing the syscall() call on
> > Linux to prevent this, and he would like some reassurance
> > that we can rely on this remaining possible in future
> > versions of glibc on Linux.
> 
> The syscall() function implementation is pretty straightforward -- it
> basically follows the ABI requirements of each architecture for the
> kernel syscall interface, putting the syscall number and arguments
> into the right registers/locations and then getting the return value
> into the right location. Could you elaborate on what you expect to
> change in this, that could be problematic? A lot of applications call
> the syscall function to make indirect system calls to avoid libc
> wrappers, so if there is an incompatible change here, I imagine it'll
> be pretty serious trouble.

Indeed. This was also the conclusion that I came to. However,
for reference I'll add his comments below (I don't think he'll
mind as this wasn't a private email, but one posted to the
samba-technical mailing list) so you can see what he is worried
about.

Personally I'd be happy with your statement above, that
an incompatible change to glibc syscall would break a lot of
applications that already use it to avoid glibc wrappers.

But if you can make a stronger guarentee, that would also
be good of course :-).

Thanks a lot,

	Jeremy.

----------------------------------------------------
Volker Lendecke Volker.Lendecke at SerNet.DE 

On Mon, Jul 02, 2012 at 08:13:38AM -0400, Jeff Layton wrote:
> It took me a minute to parse what Volker was saying but I think I get
> it now. Volker, correct me if I'm wrong...
> 
> It used to be that the direct syscall scheme would just return an int
> (or whatever you liked). Now, the syscall() wrapper generally returns
> '-1' on error and sets errno. Since errno isn't thread-local, multiple
> threads could clobber each others' error codes.
> 
> In light of that, I'm inclined to believe that Volker is correct here
> and you'll be best off with some sort of blessing from the glibc folks
> on this. A simple, thread-local syscall() function would probably be
> quite handy, but that's a rather long rope for hanging onesself. ;)

My reasoning was not that direct. Lets go back a bit:

I tried to tackle the general async posix syscall problem a
few years ago using raw clone(). First, clone() is
potentially cheaper than pthread_create() and second, it
does not suffer from the process wide credential problem.
The problem is that from a pure clone()'ed entity (not a
thread, not a process...) you want to do something sensible,
in particular you want to issue syscalls. You can't do this
using the glibc pwrite() wrapper around the INT80 (or
whatever mechanism is in place) that finally ends up in the
kernel. The reason is the global errno. The kernel interface
is a bit different: It returns >=0 in the success case and
-errno in the error case. If I remember correctly in some
distant past there was a general syscall()-like function
echoing exactly this calling convention. It would have been
an exact match for what I needed: A purely local function
call handling everything on the stack. Not so anymore with
glibc. The syscall() function returns -1 on error and fills
in errno(). So it is only usable when you have correctly set
up the errno symbol with the thread local storage reference
syscall() expects. I ended up using assembler, but it became
more and more difficult over time (try passing the 6
splice() arguments to the kernel on i386...). So by
coincidence around that time I listened to a talk by Ulrich.
I asked him about what I was supposed to do. His response
was that clone() was not supported, as it would screw up
internal assumptions of the pthread piece of glibc. Thus
they have made it harder to even try using syscall(). That's
at least what I remember from his response.

Long story short: Anything beyond standard, documented
behaviour is just not supported or actively blocked by
glibc. Without official blessing by glibc I see the
syscall() workaround just in the same place.

Try googling for anything around glibc linux per-thread
credentials, and you end up at lists.samba.org in this
thread. That should tell you something.

Volker
----------------------------------------------------



More information about the Libc-help mailing list