Maurizio Avogadro wrote:
> Il 16/02/2009 00:40, Corey Hickey ha scritto:
>> Ok, here's the problem.
>>
>> modem_main.c:976 function modem_main()
>> ----------------------------------------------------------------------
>> if (need_realtime) {
>> struct sched_param prm;
>> if(mlockall(MCL_CURRENT|MCL_FUTURE)) {
>> ERR("mlockall: %s\n",strerror(errno));
>> }
>> ----------------------------------------------------------------------
>>
>> That chunk of code runs when slmodemd starts up; the modem_start() code
>> I mentioned in my last email runs when the modem is dialed. So, the
>> mlockall(MCL_FUTURE) is allowing only a very limited allocation of
>> memory after the setuid().
>
> [...]
>
> Corey, thank you for digging this out.
You're welcome. I'm glad it helps.
> I think we're facing the same problems jackd users do.
>
> Maybe we can solve this issue with pam_limits: Corey, could you please
> try to add this line to /etc/security/limits.conf
>
> Slmodemd hard memlock 256000
>
> and see if this solves the issue even with the MCL_FUTURE flag set?
That's a good idea, and I tried it, but I think that's not quite how
limits.conf works. I haven't found anything that says this plainly, but
I'm pretty sure the following are true:
* Limits are applied at login by the pam_limits module, which reads
/etc/security/limits.conf. See pam_limits(8).
* Otherwise, limits are inherited from the parent process, and not
changed by a setuid() call.
Since slmodemd isn't actually "logging in" as the Slmodemd user, pam
isn't involved and the limits in limits.conf are not applied.
That actually works out nicely for this problem, though: slmodemd just
needs to raise its own locked memory limit before the setuid(). You can
test this by doing something like:
# ulimit -l 4208 ; ulimit -a ; slmodemd -a --debug
>From my testing, 4208 KB is the minimum needed for me, but I don't know
what a good comfortable value would be. I'm attaching a patch that sets
it to 8 MB, but maybe it would be good to go even higher.
The diff.diff file is the diff of the original 10_drop_privileges.diff
and the new one.
-Corey
slmodemd privilege dropping patch.
--- sl-modem-2.9.11~20080817.orig/modem/modem_main.c 2008-08-03
18:40:13.000000000 -0700
+++ sl-modem-2.9.11~20080817/modem/modem_main.c 2009-02-16 14:32:03.000000000
-0800
@@ -53,10 +53,13 @@
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
+#include <sys/time.h>
+#include <sys/resource.h>
#include <sched.h>
#include <signal.h>
#include <limits.h>
#include <grp.h>
+#include <pwd.h>
#ifdef SUPPORT_ALSA
#define ALSA_PCM_NEW_HW_PARAMS_API 1
@@ -76,6 +79,9 @@
#define DBG(fmt,args...) dprintf("main: " fmt, ##args)
+#define SLMODEMD_USER "Slmodemd"
+#define LOCKED_MEM_MAX (8 * 1024 * 1024)
+
#define CLOSE_COUNT_MAX 100
@@ -936,6 +942,7 @@
struct modem *m;
int pty;
int ret = 0;
+ struct passwd *pwd;
modem_debug_init(basename(dev_name));
@@ -984,6 +991,40 @@
signal(SIGINT, mark_termination);
signal(SIGTERM, mark_termination);
+#ifdef SLMODEMD_USER
+ if (need_realtime) {
+ struct rlimit limit;
+ limit.rlim_cur = limit.rlim_max = LOCKED_MEM_MAX;
+ if (setrlimit(RLIMIT_MEMLOCK, &limit)) {
+ ERR("setrlimit failed to set RLIMIT_MEMLOCK=%d: %s\n",
+ LOCKED_MEM_MAX);
+ exit(-1);
+ }
+ }
+
+ pwd = getpwnam(SLMODEMD_USER);
+ if (!pwd) {
+ ERR("getpwnam " SLMODEMD_USER ": %s\n",strerror(errno));
+ exit(-1);
+ }
+
+ ret = (setgroups(1,&pwd->pw_gid) ||
+ setgid(pwd->pw_gid) ||
+ setuid(pwd->pw_uid));
+ if (ret) {
+ ERR("setgroups or setgid %ld or setuid %ld failed: %s\n",
+ (long)pwd->pw_gid,(long)pwd->pw_uid,strerror(errno));
+ exit(-1);
+ }
+
+ if (setuid(0) != -1) {
+ ERR("setuid 0 succeeded after dropping privileges!\n");
+ exit(-1);
+ }
+ DBG("dropped privileges to %ld.%ld\n",
+ (long)pwd->pw_gid,(long)pwd->pw_uid);
+#endif
+
INFO("Use `%s' as modem device, Ctrl+C for termination.\n",
*link_name ? link_name : m->pty_name);
--- sl-modem-2.9.11~20080817.orig/debian/patches/10_drop_privileges.diff
2009-02-16 13:37:34.000000000 -0800
+++ sl-modem-2.9.11~20080817/debian/patches/10_drop_privileges.diff
2009-02-16 14:41:17.000000000 -0800
@@ -1,9 +1,13 @@
slmodemd privilege dropping patch.
-Index: slmodem-2.9.11-20080817/modem/modem_main.c
-===================================================================
---- slmodem-2.9.11-20080817.orig/modem/modem_main.c 2008-09-18
08:19:43.000000000 +0200
-+++ slmodem-2.9.11-20080817/modem/modem_main.c 2008-09-18 08:20:24.000000000
+0200
-@@ -57,6 +57,7 @@
+--- sl-modem-2.9.11~20080817.orig/modem/modem_main.c 2008-08-03
18:40:13.000000000 -0700
++++ sl-modem-2.9.11~20080817/modem/modem_main.c 2009-02-16
14:32:03.000000000 -0800
+@@ -53,10 +53,13 @@
+ #include <sys/stat.h>
+ #include <sys/ioctl.h>
+ #include <sys/mman.h>
++#include <sys/time.h>
++#include <sys/resource.h>
+ #include <sched.h>
#include <signal.h>
#include <limits.h>
#include <grp.h>
@@ -11,16 +15,17 @@
#ifdef SUPPORT_ALSA
#define ALSA_PCM_NEW_HW_PARAMS_API 1
-@@ -76,6 +77,8 @@
+@@ -76,6 +79,9 @@
#define DBG(fmt,args...) dprintf("main: " fmt, ##args)
+#define SLMODEMD_USER "Slmodemd"
++#define LOCKED_MEM_MAX (8 * 1024 * 1024)
+
#define CLOSE_COUNT_MAX 100
-@@ -936,6 +939,7 @@
+@@ -936,6 +942,7 @@
struct modem *m;
int pty;
int ret = 0;
@@ -28,11 +33,21 @@
modem_debug_init(basename(dev_name));
-@@ -984,6 +988,30 @@
+@@ -984,6 +991,40 @@
signal(SIGINT, mark_termination);
signal(SIGTERM, mark_termination);
+#ifdef SLMODEMD_USER
++ if (need_realtime) {
++ struct rlimit limit;
++ limit.rlim_cur = limit.rlim_max = LOCKED_MEM_MAX;
++ if (setrlimit(RLIMIT_MEMLOCK, &limit)) {
++ ERR("setrlimit failed to set RLIMIT_MEMLOCK=%d: %s\n",
++ LOCKED_MEM_MAX);
++ exit(-1);
++ }
++ }
++
+ pwd = getpwnam(SLMODEMD_USER);
+ if (!pwd) {
+ ERR("getpwnam " SLMODEMD_USER ": %s\n",strerror(errno));