[Dnsmasq-discuss] dnsmasq-2.43rc3 available.

Simon Kelley simon at thekelleys.org.uk
Thu Jul 10 13:23:44 BST 2008


Jean Wolter wrote:
> Simon Kelley <simon at thekelleys.org.uk> writes:
> 
>> Patrick McLean wrote:
>>> On Linux 2.6.24 (Gentoo kernel, though I don't see why it wouldn't
>>> happen on other distros), starting this release with the user set to
>>> anything other than root fails with this message:
>>> dnsmasq: setting capabilities failed: Operation not permitted
>>>
>> I think I may have been guilty of answering the question I expected in
>> my last reply. Its valid if what you are talking about is running (as
>> root)
>>
>> dnsmasq --user <someuser>
>>
>> if you are actually starting dnsmasq as <someuser> (presumably
>> listening on a high port) then I can see that changing the capability
>> error from soft to hard is a problem. The solution is not to attempt
>> any of that stuff if the original process uid is non-zero.
> 
> I tried dnsmaq *rc4 
>   - on 2.6.16.60
>   - with SECURITY* disabled in its config
>     zcat /proc/config.gz | grep SECURITY
>     # CONFIG_SECURITY is not set
>   - started with uid 0
> and it fails to drop priviledges. From an strace:
> 
> 2302  capset(0x19980330, -1208317308,
> {CAP_SETUID|CAP_NET_ADMIN|CAP_NET_RAW, CAP_SETUID|CAP_NET_ADMIN|CAP_NET_RAW,
> CAP_SETUID|CAP_NET_ADMIN|CAP_NET_RAW}) = -1 EPERM (Operation not permitted)
> 2302  write(9, "\f\0\0\0\1\0\0\0", 8 <unfinished ...>
> 2298  <... read resumed> "\f\0\0\0\1\0\0\0", 8) = 8
> 2302  <... write resumed> )             = 8
> 2298  write(2, "\n", 1 <unfinished ...>
> 2302  _exit(0)                          = ?
> 2298  <... write resumed> )             = 1
> 2298  getpid()                          = 2298
> 2298  write(2, "dnsmasq: ", 9)          = 9
> 2298  write(2, "setting capabilities failed: ", 29) = 29
> 2298  write(2, "Operation not permitted", 23) = 23
> 2298  write(2, "\n", 1)                 = 1
> # getuid/geteuid added for debugging purposes
> 2298  geteuid()                         = 0
> 2298  getuid()                          = 0
> 
> It looks like this happens due to some uninitialized values (pid
> -1208317308); dnsmasq tries to set capabilities for arbitrary process
> ids. If I add the following, capset succeeds:
> 
> --- dnsmasq-2.43rc4/src/dnsmasq.c.orig	2008-07-10 13:08:59.000000000 +0200
> +++ dnsmasq-2.43rc4/src/dnsmasq.c	2008-07-10 12:58:16.000000000 +0200
> @@ -383,6 +383,7 @@
>  	    (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
>  	  
>  	  /* Tell kernel to not clear capabilities when dropping root */
> +	  hdr->pid = getpid();
>  	  if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1) == -1)
>  	    bad_capabilities = errno;
>  			  
> 
> 2334  capset(0x19980330, 2334, {CAP_SETUID|CAP_NET_ADMIN|CAP_NET_RAW,
> CAP_SETUID|CAP_NET_ADMIN|CAP_NET_RAW,
> CAP_SETUID|CAP_NET_ADMIN|CAP_NET_RAW}) = 0
> 2334  capset(0x19980330, 2334, {CAP_NET_ADMIN|CAP_NET_RAW,
> CAP_NET_ADMIN|CAP_NET_RAW, 0}) = 0
> 
> dnsmasq starts and resolves names.
> 

Kudos! Thanks for spotting that. The bug that causes this is more subtle
but more dangerous: hdr->pid is supposed to be zero, which means "the
current process", but the memset that clears hdr to zero got lost when
the code for determining the capability ABI version was moved to earlier
in the file. I also found that the memset zeroing the capability data
had args 2 and 3 swapped.

New rc soon......


Cheers,

Simon.







More information about the Dnsmasq-discuss mailing list