Re: [Jack-Devel] su, limits, PAM and JACK

PrevNext  Index
DateWed, 23 May 2012 01:21:53 +0200
From Robin Gareus <[hidden] at gareus dot org>
ToJACK Mailing List <[hidden] at lists dot jackaudio dot org>
In-Reply-ToJamie Heilman Re: [Jack-Devel] su, limits, PAM and JACK
On 05/23/2012 01:09 AM, Jamie Heilman wrote:
> Robin Gareus wrote:
>> Hya,
>>
>> This is somewhat off-topic, but I think someone here may know the answer.
>>
>> For an installation, I'm trying to start jackd during boot on a headless
>> box, but it fails to acquire real-time privileges.
>>
>> 'user' is in the audio group, and limits.conf is set up. All works fine
>> if I log-in as 'user' and launch `jackd -d alsa ..` manually.
>>
>> If I log in as root (or call it from init):
>>
>>   su user -c 'jackd ..'     # fails -> no rt priv
>>   su user -l -c 'jackd ..'  # fails -> no rt priv
>>
>> the actual error message from jack is
>>   Cannot use real-time scheduling (RR/10)(1: Operation not permitted)
>>
>> If I change /etc/pam.d/su and add (or un-comment)
>> "session    required   pam_limits.so"
>>
>>   su user -l -c 'jackd ..'  # works now (also from init on boot.)
>>
>> Well. Next step is to not use 'su' but proper POSIX setgid(), setuid().
>> Alas, I seem to miss some crucial step that sets up the proper limits
>> after calling setuid().
> 
> Chances are your PAM stack isn't configured to use pam_limits.so for
> su sessions, which means using su won't pay any attention to the
> setttings in limits.conf until it is.  That said, don't do that.
> Using su programatically to switch users is a bad idea becuase su's
> behavior is notoriously unportable anyway.
> 
>> Any idea what that may be?
> 
> I run jackd on boot on headless virtuals, and I use Gerrit Pape's
> daemontools-a-like runit to do it.  That said, the recipe is the more
> or less the same regardless of technique.  My jackd-net/run script is:
> 
> #!/bin/bash
> exec 2>&1
> ulimit -l unlimited -r 95       # XXX ulimit -r is a bashism
> exec chpst -u jackd jackd -d net -a 0 -i 0 -o 2 -I 0 -O 0
> 
> That script is run as superuser, so that breaks down into:
> 
> 1) allow unlimited bytes to be locked into memory
> 2) allow a maximum real-time scheduling priority of 95
> 3) switch group to audio (implied because the jackd user's primary
>    group is audio on this system) then switch user to jackd. (chpst is
>    part of runit)
> 
>> Run the following as root from a console (don't use sudo or su to
>> acquire root priv) to reproduce the problem:
>>
>> #!/usr/bin/perl
>> use POSIX qw(setuid setgid);
>> my ($login,$pass,$uid,$gid) = getpwnam('user');
>> my $audiog  = getgrnam('audio');
>> setgid($audiog);
>> setuid($uid);
>> print `id`; # shows the UID and GID just fine
>> system('jackd -d alsa -d hw:1');
>> # Cannot use real-time scheduling (RR/10)(1: Operation not permitted)
>> # Aarrrrg!
>> # help please
> 
> Right, your perl script is missing two calls to setrlimit(2) for
> RLIMIT_RTPRIO and RLIMIT_MEMLOCK.  afaik there's no native wrapper for
> setrlimit in perl though, so you'll probably have to install
> BSD::Resource and use that or something similar.  Or call your perl
> script from a bash script that does the above ulimit first.
> 
> Normally I would never write bash-specific shell, because while bash
> is a fine login shell, it's a bloated horror and a lousy replacement
> for /bin/sh ... but unfortunately bash's builtin ulimit is one of only
> that I know supports setting RLIMIT_RTPRIO.
> 

yes, I just found that out and got it working.  Actually Adi brought me
onto this by pointing to `man setrlimit`. -- no need for BSD::Resource.

 require("syscall.ph");
 my $buf = pack("l l", 0x7fffffff, 0x7fffffff);
 syscall(&SYS_setrlimit, 8, $buf);  #  8:RLIMIT_MEMLOCK
 $buf = pack("l l", 95, 95);
 syscall(&SYS_setrlimit, 14, $buf); # 14:RLIMIT_RTPRIO

 setgid($audiog);
 setuid($uid);

I still need to clean this code up a bit, but it works.
Thanks for all the input, everyone.

Cheers!
robin
PrevNext  Index

1337728924.27837_0.ltw:2, <4FBC1F91.80003 at gareus dot org>