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));

Reply via email to