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
1337728924.27837_0.ltw:2, <4FBC1F91.80003 at gareus dot org>