Re: some vulns

2020-02-22 Thread Maxime Villard

CVSROOT:/cvs
Module name:src
Changes by: morti...@cvs.openbsd.org2020/02/15 15:59:55

Modified files:
sys/arch/amd64/amd64: vmm.c

Log message:
Add bounds check on addresses passed from guests in pvclock.

Fixes an issue where a guest can write to host memory by passing bogus 
addresses.


I'm a bit confused here. It is not because the GPAs are contiguous that the
HPAs are too. If the structure crosses a page, the guest still can write to
host memory.



some vulns

2020-02-15 Thread Maxime Villard

In vmm_update_pvclock():

6868pvclock_gpa = vcpu->vc_pvclock_system_gpa & 0xFFF0;  <-- 
controlled by the guest
6869if (!pmap_extract(vm->vm_map->pmap, pvclock_gpa, _hpa))
6870return (EINVAL);
6871pvclock_ti = (void*) PMAP_DIRECT_MAP(pvclock_hpa);
6872
6873/* START next cycle (must be odd) */
6874pvclock_ti->ti_version =
6875(++vcpu->vc_pvclock_version << 1) | 0x1;

Three things are wrong:

 1) The RO protections are not enforced, so the guest could have data be
written to a GPA it can only access as RO.

 2) If 'pvclock_ti' crosses a page, its second half could point to an HPA
that doesn't belong to the guest. The guest can therefore, to some
limited extent, overwrite host kernel memory.

 3) The pmap is not locked, so if the GPA gets unmapped and its
corresponding HPA recycled, there is a small window where the (new)
content of the HPA can get overwritten.

There is, in fact, a fourth case. Watch closely. On AMD CPUs the NPTs are
a regular pmap. The higher half of the GPA space is therefore mapped to
host kernel memory as KVA. Given that there is no check on PG_u here, the
guest can just put a host KVA in pvclock_gpa, and have its content be
overwritten. This gives write-where ability for the guest.

The OpenBSD kernel does not perform full ASLR, in that the PTE space and
direct map are at static addresses (contrary to eg NetBSD where everything
is randomized). These addresses are known. The guest can therefore use the
static address of the direct map for example to write at whatever HPA by
issuing the following instruction:

wrmsr(KVM_MSR_SYSTEM_TIME, PMAP_DIRECT_MAP(hpa) | 1);

This means the guest can overwrite whatever host kernel memory, and can
control *where* to write. I have tested this, and it works.

The guest can also choose *what* to write, because it just so happens that
'vc_pvclock_version' is the number of VMEXITs that occurred with pvclock
enabled, and the guest can reliably craft this value. So this is not just
a write-where, this is a full guest-to-host write-what-where.

Had there been proper ASLR, it still could have been somewhat bypassable,
because VMD does a pass-through of RDMSR on AMD CPUs (??), which can leak
HPAs such as HSAVE_PA.

(Speaking about direct map, notice how an alignment bug in locore0.S
causes the first 2MB of .text to be writable on Intel CPUs. So there is a
static address that maps the kernel .text as writable.)

There are additional assorted bugs and vulns that could be used to some
degree:

 - On AMD CPUs the CPL check on XSETBV VMEXITs must be performed by
   software. VMD forgot to do that, so from guest-userland, we can control
   the XCR0 that guest-kernel will use.

 - This XSETBV issue actually has an additional ramification. Right now
   OpenBSD doesn't check that the guest XCR0 is a subset of the host XCR0,
   which means that the guest can use more FPU states than the host allows.
   It looks like this check was lost when fixing another bug I reported one
   year ago which could cause guest-to-host DoS.

 - The TLB handling of guest pages is broken, in that the INVEPT
   instructions in the host could be issued on the wrong CPUs. This means
   that if UVM decides to swap out a guest page, the guest could still
   access it via stale TLB entries. On AMD CPUs, there is no TLB handling
   at all (??).

 - vmx_load_pdptes is broken.

In order to make this whole thing less of a security joke, I would suggest
the following:

 - Fix TLB handling, sanitize the GPAs, lock the pages correctly.
 - Don't pass-through RDMSR.
 - Fix the XSETBV issues.
 - Provide *real* ASLR: randomize the PTE space and the direct map.
 - Fix the alignment bug in the direct map to not map the text as writable.

Maxime



Brainy: a few bugs

2015-09-13 Thread Maxime Villard
Got some time tonight; nothing new, just emptying my list:

http://m00nbsd.net/e5ab5f6e59d6a0feb7d1a518acc8233d.html#Unsorted-2

Summary:

_17/ UNINITIALIZED VARIABLE: sys/netinet/if_ether.c rev1.165
_18/ UNINITIALIZED VARIABLE: sys/net80211/ieee80211_pae_output.c rev1.20
_19/ UNINITIALIZED VARIABLE: sys/arch/i386/i386/bios.c rev1.112
_20/ UNINITIALIZED VARIABLE: sys/arch/sgi/dev/if_iec.c rev1.14
_21/ UNINITIALIZED VARIABLE: sys/arch/armv7/omap/ti_iic.c rev1.2
_22/ OVERLAP: sys/arch/sparc64/dev/vdsp.c rev1.2
_23/ USE-AFTER-FREE: sys/dev/sun/z8530ms.c rev1.2
_24/ MEMORY LEAK: sys/dev/ic/oosiop.c rev1.22

Found by Brainy.

Maxime



Re: Brainy: User-Triggerable Kernel Memory Leak in execve()

2015-08-07 Thread Maxime Villard

Well, I guess I'll have to admit that I find your attitude extremely
disrespectful. But I don't tend to feel particularly offended by this
kind of things, so it probably does not matter.


Le 21/07/2015 12:31, sam a écrit :

On Tue, 21 Jul 2015 11:31:44 +0200
Maxime Villard m...@m00nbsd.net wrote:


Found by The Brainy Code Scanner.

It is not the last bug Brainy has found, but it is the last one I
report. I don't have time for that.



How about you release the Brainy Code Scanner then?

I have so many bugs; in fact, there are so many, I don't even have the
time to report them! My scanner is so good!

Or perhaps you should report 'just' the relatively important ones?



I think my work does (or used to) benefit to a lot of users, developers
and vendors here; a lot of people, including you.

Nobody supports my work, and I've never asked for anything here about
that. Even though I almost never receive a simple thank you for all
the bugs and vulnerabilities I've so far reported, I still expect a
spiritual thank you for my work.

But I certainly do not expect that kind of emails you just sent, somehow
trying to either make fun of me or disregard what I'm willing to spend
my spare time on for you.

Developing, improving and maintaining Brainy takes time and energy, as
well as investigating and packaging the bugs and vulnerabilities it
finds. I've so far sent some reports here just because I'm friendly
enough, and because modifying a few things for Brainy to properly
understand the OpenBSD code does not require a Herculean work.

Now, I believe that this effort is too much for my spare time. If you
want to say thanks to me for reporting this vulnerability, dear Sam,
it's never too late.

Maxime



Brainy: Use-After-Free in if_bnx

2015-07-21 Thread Maxime Villard
Hi,
I put here a bug among others:

-- sys/dev/pci/if_bnx.c 

if ((status  L2_FHDR_STATUS_L2_VLAN_TAG) 
!(sc-rx_mode  BNX_EMAC_RX_MODE_KEEP_VLAN_TAG)) {
#if NVLAN  0
DBPRINT(sc, BNX_VERBOSE_SEND,
%s(): VLAN tag = 0x%04X\n,
__FUNCTION__,
l2fhdr-l2_fhdr_vlan_tag);

m-m_pkthdr.ether_vtag =
l2fhdr-l2_fhdr_vlan_tag;
m-m_flags |= M_VLANTAG;
#else
m_freem(m);
goto bnx_rx_int_next_rx;
#endif  
}

bnx_rx_int_next_rx:
sw_prod = NEXT_RX_BD(sw_prod);
}

sw_cons = NEXT_RX_BD(sw_cons);

/* If we have a packet, pass it up the stack */
if (m) {
sc-rx_cons = sw_cons;

DBPRINT(sc, BNX_VERBOSE_RECV,
%s(): Passing received frame up.\n, __FUNCTION__);
ml_enqueue(ml, m);
DBRUNIF(1, sc-rx_mbuf_alloc--);

sw_cons = sc-rx_cons;
}



Use-after-free with 'm'.

Found by The Brainy Code Scanner.

Maxime



Brainy: User-Triggerable Kernel Memory Leak in execve()

2015-07-21 Thread Maxime Villard
Hi,
I put here a bug among others:

- sys/kern/kern_exec.c -

char *pathbuf = NULL;

[...]

pathbuf = pool_get(namei_pool, PR_WAITOK);

[...]

/* setup new registers and do misc. setup. */
if (pack.ep_emul-e_fixup != NULL) {
if ((*pack.ep_emul-e_fixup)(p, pack) != 0)
goto free_pack_abort;
}

[...]

free_pack_abort:
free(pack.ep_hdr, M_EXEC, 0);
exit1(p, W_EXITCODE(0, SIGABRT), EXIT_NORMAL);

/* NOTREACHED */
atomic_clearbits_int(pr-ps_flags, PS_INEXEC);
if (pathbuf != NULL)
pool_put(namei_pool, pathbuf);

return (0);
}



'pathbuf' is leaked.

This path being obviously reachable from userland, it is easy for a
local (un)privileged user to cause the kernel to run out of memory and
become unresponsive. OpenBSD 5.7 is affected, and quite certainly
previous releases.

Exploit here:

http://m00nbsd.net/garbage/OpenBSD_execve-DoS.txt

You can see with vmstat -m that the namei pool becomes enormous.

Found by The Brainy Code Scanner.

It is not the last bug Brainy has found, but it is the last one I
report. I don't have time for that.

Maxime



Brainy: Uninitialized Var in hppa64

2015-07-21 Thread Maxime Villard

Hi,
I put here a bug among others:

--- sys/arch/hppa64/dev/apic.c -

struct evcount *cnt;
struct apic_iv *aiv, *biv;
void *iv;
int irq = APIC_INT_IRQ(ih);
int line = APIC_INT_LINE(ih);
u_int32_t ent0;

/* no mapping or bogus */
if (irq = 0 || irq  63)
return (NULL);

aiv = malloc(sizeof(struct apic_iv), M_DEVBUF, M_NOWAIT);
if (aiv == NULL) {
free(cnt, M_DEVBUF, 0);
return NULL;
}



'cnt' is not initialized.

Found by The Brainy Code Scanner.

Maxime



Brainy: Use-After-Free in if_et

2015-07-04 Thread Maxime Villard
Hi,
I put here a bug among others:

-- sys/dev/pci/if_et.c -

1808if (m_defrag(m, M_DONTWAIT)) {
m_freem(m);
printf(%s: can't defrag TX mbuf\n,
sc-sc_dev.dv_xname);
error = ENOBUFS;
goto back;
}

[...]

back:
if (error) {
m_freem(m);
*m0 = NULL;
}




Use-after-free with 'm'.

Found by The Brainy Code Scanner.

Maxime



Brainy: Memory Leak in ti

2015-06-26 Thread Maxime Villard
Hi,
I put here a bug among others:

 sys/dev/ic/ti.c ---

648 MGETHDR(m_new, M_DONTWAIT, MT_DATA);
if (m_new == NULL)
return (ENOBUFS);

m_new-m_len = m_new-m_pkthdr.len = MHLEN;
m_adj(m_new, ETHER_ALIGN);

if (bus_dmamap_load_mbuf(sc-sc_dmatag, dmamap, m_new,
BUS_DMA_NOWAIT)) {
m_freem(m);
return (ENOBUFS);
}



'm_new' is leaked.

Found by The Brainy Code Scanner.

Maxime



Brainy: Memory Leak in vax

2015-06-26 Thread Maxime Villard
Hi,
I put here a bug among others:

 sys/arch/vax/if/if_qe.c ---

146 ring = malloc(PROBESIZE, M_TEMP, M_WAITOK | M_ZERO);
bzero(sc, sizeof(struct qe_softc));
sc-sc_iot = ua-ua_iot;
sc-sc_ioh = ua-ua_ioh;
sc-sc_dmat = ua-ua_dmat;

ubasc-uh_lastiv -= 4;
QE_WCSR(QE_CSR_CSR, QE_RESET);
QE_WCSR(QE_CSR_VECTOR, ubasc-uh_lastiv);

/*
 * Map the ring area. Actually this is done only to be able to
 * send and receive a internal packet; some junk is loopbacked
 * so that the DEQNA has a reason to interrupt.
 */
ui.ui_size = PROBESIZE;
ui.ui_vaddr = (caddr_t)ring[0];
if ((error = uballoc((void *)parent, ui, UBA_CANTWAIT)))
return 0;



'ring' is leaked.

Found by The Brainy Code Scanner.

Maxime



Brainy: Memory Leak in ipmi

2015-06-20 Thread Maxime Villard
Hi,
I put here a bug among others:

 sys/dev/ipmi.c 

1046buf = malloc(maxlen + 3, M_DEVBUF, M_NOWAIT);
if (buf == NULL) {
printf(%s: ipmi_recvcmd: malloc fails\n, DEVNAME(sc));
return (-1);
}
/* Receive message from interface, copy out result data */
if (sc-sc_if-recvmsg(sc, maxlen + 3, rawlen, buf) ||
rawlen  IPMI_MSG_DATARCV)
return (-1);



'buf' is leaked.

Found by The Brainy Code Scanner.

Maxime



Brainy: Memory Leak in rasops

2015-06-20 Thread Maxime Villard
Hi,
I put here a bug among others:

--- sys/dev/rasops/rasops.c 

1167f = malloc(sizeof(struct rotatedfont), M_DEVBUF, M_WAITOK);

if ((ncookie = wsfont_rotate(*cookie)) == -1)
return;



'f' is leaked.

Found by The Brainy Code Scanner.

Maxime



Brainy: No Error Set in an

2015-06-20 Thread Maxime Villard
Hi,
I put here a bug among others:

--- sys/dev/ic/an.c 

1030if (an_write_rid(sc, AN_RID_SSIDLIST, sc-sc_buf,
sizeof(sc-sc_buf.sc_ssidlist)) != 0) {
printf(%s: failed to write ssid list\n, ifp-if_xname);
an_stop(ifp, 1);
return error;
}



'error' does not hold an error code. Same problem l.1057.

Found by The Brainy Code Scanner.

Maxime



Brainy: Memory Leak in ICMP

2015-05-19 Thread Maxime Villard
Hi,
I put here a bug among others:

-- netinet/ip_icmp.c --

925 rt = rtalloc(sintosa(sin), RT_REPORT|RT_RESOLVE, rtableid);
if (rt == NULL)
return (NULL);

/* Check if the route is actually usable */
if (rt-rt_flags  (RTF_REJECT | RTF_BLACKHOLE) ||
(rt-rt_flags  RTF_UP) == 0)
return (NULL);

---

'rt' is not released.

Found by The Brainy Code Scanner.

Maxime



Brainy: Kernel Use-after-free Memory Leak in hifn

2015-05-11 Thread Maxime Villard
Hi,
I put here two bugs among others:

 sys/dev/pci/hifn7751.c 

2757
if (!(m0-m_flags  M_EXT))
m_freem(m0);
len = MCLBYTES;

totlen -= len;
m0-m_pkthdr.len = m0-m_len = len;
mlast = m0;



Use-after-free with 'm0'.

 sys/dev/pci/hifn7751.c 

2766
MGET(m, M_DONTWAIT, MT_DATA);
if (m == NULL) {
m_freem(m0);
return (NULL);
}
MCLGET(m, M_DONTWAIT);
if (!(m-m_flags  M_EXT)) {
m_freem(m0);
return (NULL);
}
len = MCLBYTES;



'm' is leaked.

Found by The Brainy Code Scanner.

Maxime



Re: kernel patch available

2015-05-01 Thread Maxime Villard

Le 30/04/2015 22:42, Philip Guenther a écrit :

Patches are now available for 5.6 and 5.7 which fix local security
issues in the kernel's handling of malformed ELF executables, which
could be used to panic the kernel or view some kernel memory.

Our thanks to Alejandro Hernandez for test cases and Maxime Villard
for providing the basis for one of the changes.


Hum. It curiously looks like the patch I sent here about two years
ago that nobody gave a shit about:

http://marc.info/?l=openbsd-techm=138703150604223w=2

- - - -

And don't you feel like there's an obvious bug in these patches?

if (ph[i].p_filesz  ph[i].p_memsz)
goto bad1;

[...]

bad1:
VOP_CLOSE(nd.ni_vp, FREAD, p-p_ucred, p);
bad:
free(ph, M_TEMP, 0);

*last = addr;
vput(nd.ni_vp);
return (error);


Where is 'error' initialized?




Le 30/04/2015 22:42, Philip Guenther a écrit :

Patches are now available for 5.6 and 5.7 which fix local security
issues in the kernel's handling of malformed ELF executables, which
could be used to panic the kernel or view some kernel memory.

Our thanks to Alejandro Hernandez for test cases and Maxime Villard
for providing the basis for one of the changes.


Links:

http://www.openbsd.org/errata56.html
http://ftp.openbsd.org/pub/OpenBSD/patches/5.6/common/023_elf.patch.sig

and

http://www.openbsd.org/errata57.html
http://ftp.openbsd.org/pub/OpenBSD/patches/5.7/common/006_elf.patch.sig


untrusted comment: signature from openbsd 5.7 base secret key
RWSvUZXnw9gUby4OBLM0n2MCFo9TM/FWZlryKfa4mLnPMEgi87dSLa8HTEXN15Z0YumeDyfsnFVHyQHjtL6106R1LxIOtJ/6pww=

OpenBSD 5.7 errata 6, Apr 30, 2015:

Missing validity checks in the kernel ELF loader meant malformed binaries
could trigger kernel panics or view kernel memory.

Apply by doing:
 cd /usr/src
 signify -Vep /etc/signify/openbsd-57-base.pub -x 006_elf.patch.sig -m - | \
 patch -p0

Then build and install a new kernel:

 cd /usr/src/sys/arch/`machine`/conf
 KK=`sysctl -n kern.osversion | cut -d# -f1`
 config $KK
 cd ../compile/$KK
 make
 make install

Index: sys/kern/exec_elf.c
===
RCS file: /cvs/src/sys/kern/exec_elf.c,v
retrieving revision 1.112
diff -u -p -r1.112 exec_elf.c
--- sys/kern/exec_elf.c 10 Feb 2015 23:39:57 -  1.112
+++ sys/kern/exec_elf.c 30 Apr 2015 18:41:25 -
@@ -362,6 +362,8 @@ ELFNAME(load_file)(struct proc *p, char

for (i = 0; i  eh.e_phnum; i++) {
if (ph[i].p_type == PT_LOAD) {
+   if (ph[i].p_filesz  ph[i].p_memsz)
+   goto bad1;
loadmap[idx].vaddr = trunc_page(ph[i].p_vaddr);
loadmap[idx].memsz = round_page (ph[i].p_vaddr +
ph[i].p_memsz - loadmap[idx].vaddr);
@@ -549,14 +551,20 @@ ELFNAME2(exec,makecmds)(struct proc *p,

for (i = 0, pp = ph; i  eh-e_phnum; i++, pp++) {
if (pp-p_type == PT_INTERP  !interp) {
-   if (pp-p_filesz = MAXPATHLEN)
+   if (pp-p_filesz  2 || pp-p_filesz  MAXPATHLEN)
goto bad;
interp = pool_get(namei_pool, PR_WAITOK);
if ((error = ELFNAME(read_from)(p, epp-ep_vp,
pp-p_offset, interp, pp-p_filesz)) != 0) {
goto bad;
}
+   if (interp[pp-p_filesz - 1] != '\0')
+   goto bad;
} else if (pp-p_type == PT_LOAD) {
+   if (pp-p_filesz  pp-p_memsz) {
+   error = EINVAL;
+   goto bad;
+   }
if (base_ph == NULL)
base_ph = pp;
} else if (pp-p_type == PT_PHDR) {





Brainy: Memory Leak in aic

2015-04-27 Thread Maxime Villard
Hi,
I put here a bug among others:

- sys/dev/ic/aic6915.c -

386 MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL) {
printf(%s: unable to allocate Tx mbuf\n,
sc-sc_dev.dv_xname);
break;
}
if (m0-m_pkthdr.len  MHLEN) {
MCLGET(m, M_DONTWAIT);
if ((m-m_flags  M_EXT) == 0) {
printf(%s: unable to allocate Tx 
cluster\n, sc-sc_dev.dv_xname);
m_freem(m);
break;
}
}
m_copydata(m0, 0, m0-m_pkthdr.len, mtod(m, caddr_t));
m-m_pkthdr.len = m-m_len = m0-m_pkthdr.len;
error = bus_dmamap_load_mbuf(sc-sc_dmat, dmamap,
m, BUS_DMA_WRITE|BUS_DMA_NOWAIT);
if (error) {
printf(%s: unable to load Tx buffer, 
error = %d\n, sc-sc_dev.dv_xname, error);
break;
}



'm' is leaked.

Found by The Brainy Code Scanner.

Maxime



Brainy: Kernel Memory Leak in PF

2015-02-19 Thread Maxime Villard
Hi,
I put here a bug among others:

-- sys/net/pf_ioctl.c --

1027qs = pool_get(pf_queue_pl, PR_WAITOK|PR_LIMITFAIL|PR_ZERO);
if (qs == NULL) {
error = ENOMEM;
break;
}
bcopy(q-queue, qs, sizeof(*qs));
qs-qid = pf_qname2qid(qs-qname, 1);
if (qs-parent[0]  (qs-parent_qid =
pf_qname2qid(qs-parent, 0)) == 0)
return (ESRCH);



'qs' is leaked.

Found by The Brainy Code Scanner.

Maxime



Brainy: Kernel Memory Leak in sdmmc

2015-02-15 Thread Maxime Villard
Hi,
I put here a bug among others:

-- dev/sdmmc/sdmmc.c --

783 data = malloc(ucmd-c_datalen, M_TEMP,
M_WAITOK | M_CANFAIL);
if (data == NULL)
return ENOMEM;
if (copyin(ucmd-c_data, data, ucmd-c_datalen))
return EFAULT;

---

'data' is leaked.

Found by The Brainy Code Scanner.

Maxime



Re: Brainy: User-Triggerable Kernel Memory Leak

2015-02-06 Thread Maxime Villard
FWIW, it would be wise to propagate the fix to the stable branch(es).

I guess people use compat-linux.


Le 31/01/2015 00:33, Alexander Bluhm a écrit :
 On Fri, Jan 30, 2015 at 03:57:12PM -0700, Todd C. Miller wrote:
 On Fri, 30 Jan 2015 22:55:06 +0100, Alexander Bluhm wrote:

 sosetopt() calls m_free() and then it is called again.  So it is a
 double free.

 Whoops, I didn't notice that the non-error case also falls thought
 to the bad label.  We could just do what sys_setsockopt() does
 and zero out m after calling sosetopt().
 
 Let's take this fix.  OK bluhm@
 

  - todd

 Index: sys/compat/linux/linux_socket.c
 ===
 RCS file: /cvs/src/sys/compat/linux/linux_socket.c,v
 retrieving revision 1.59
 diff -u -r1.59 linux_socket.c
 --- sys/compat/linux/linux_socket.c  21 Jan 2015 13:47:45 -  1.59
 +++ sys/compat/linux/linux_socket.c  30 Jan 2015 22:56:40 -
 @@ -969,10 +969,8 @@
  if (lsa.optval != NULL) {
  m = m_get(M_WAIT, MT_SOOPTS);
  error = copyin(lsa.optval, mtod(m, caddr_t), lsa.optlen);
 -if (error) {
 -(void) m_free(m);
 +if (error)
  goto bad;
 -}
  m-m_len = lsa.optlen;
  }
  so = (struct socket *)fp-f_data;
 @@ -984,7 +982,10 @@
  goto bad;
  }
  error = sosetopt(so, level, name, m);
 +m = NULL;
  bad:
 +if (m)
 +m_free(m);
  FRELE(fp, p);
  return (error);
  }
 
 



Brainy: User-Triggerable Kernel Memory Leak

2015-01-30 Thread Maxime Villard
Hi,
I put here a bug among others:

-- sys/compat/linux/linux_socket.c --

969 if (lsa.optval != NULL) {
m = m_get(M_WAIT, MT_SOOPTS);
error = copyin(lsa.optval, mtod(m, caddr_t), lsa.optlen);
if (error) {
(void) m_free(m);
goto bad;
}
m-m_len = lsa.optlen;
}
so = (struct socket *)fp-f_data;
if (so-so_proto  level == IPPROTO_TCP  name == TCP_NODELAY  
so-so_proto-pr_domain-dom_family == AF_LOCAL 
so-so_proto-pr_protocol == PF_LOCAL) {
/* ignore it */
error = 0;
goto bad;
}
error = sosetopt(so, level, name, m);
bad:
FRELE(fp, p);
return (error);

-

'm' is allocated and filled in, but later the function may jump to 'bad' and
return without freeing it.

'lsa' being user-controllable, it is easy for a local (un)privileged user to
cause the kernel to run out of memory and become unresponsive. OpenBSD 5.6/i386
is affected, and perhaps previous releases.

Exploit here:

http://m00nbsd.net/garbage/OpenBSD_Linux_DoS.c

Binary sample:

http://m00nbsd.net/garbage/OpenBSD_Linux_DoS.tar.gz

Found by my code scanner.

Maxime



Brainy: OpenSSH Memory Leak

2014-09-21 Thread Maxime Villard
Hi,
I put here a bug among others:

Index: ssh-ed25519.c
===
RCS file: /cvs/src/usr.bin/ssh/ssh-ed25519.c,v
retrieving revision 1.4
diff -u -r1.4 ssh-ed25519.c
--- ssh-ed25519.c   24 Jun 2014 01:13:21 -  1.4
+++ ssh-ed25519.c   29 Aug 2014 10:28:35 -
@@ -125,8 +125,10 @@
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
-   if (datalen = SIZE_MAX - len)
-   return SSH_ERR_INVALID_ARGUMENT;
+   if (datalen = SIZE_MAX - len) {
+   r = SSH_ERR_INVALID_ARGUMENT;
+   goto out;
+   }
smlen = len + datalen;
mlen = smlen;
if ((sm = malloc(smlen)) == NULL || (m = xmalloc(mlen)) == NULL) {

Found by my code scanner.

Maxime



Re: exec_elf.c: mistake ?

2014-06-30 Thread Maxime Villard
Well, at the time I didn't really know these stuff - this bug was found by my
home-made code scanner, in an area I was not particularly familiar with. 
However,
I did try to help as far as I could, but despite my pings, it has remained
unfixed so far, and 5.5 was released with no care taken about that.

I vaguely remember that I later ended up with a working patch, but apparently
I've lost it since. This bug crashed binaries, and I had told myself it was
annoying enough to be worth an Erratum.

Anyway, it ain't that bad, and I'm glad to see people waking up one year later.
(it won't be necessary to cc' me again for this issue)

Regards,
Maxime


Le 17/06/2014 00:29, Matthew Dempsky a écrit :
 
 Reading through exec_elf.c, I just noticed the uninitialized bdiff
 variable myself, and remembered this thread.
 
 Tangentially, the code for worrying about zero-filling the last page
 is overzealous.  We only need to zero-fill the page if memsz  filesz
 (accounting for alignment and page boundaries).  In the common case
 (at least on amd64), we always have either memsz==filesz (most
 segments) or filesz==0 (segment for .bss), so we shouldn't need
 zero-filling.
 
 And actually, I think the logic for only doing zero-fill for writable
 segments is wrong.  It looks to me like the ELF gABI specifies
 zero-fill semantics for memsz  filesz even for read-only segments.
 
 On Sat, Oct 5, 2013 at 4:27 PM, Philip Guenther guent...@gmail.com wrote:
 On Thu, 15 Aug 2013, Maxime Villard wrote:
 Hum hum, after investigating a bit, and from what I understood - if I'm
 not mistaken, I think it would make sense if bdiff was set to

   bdiff = ph-p_vaddr - trunc_page(ph-p_vaddr);

 Yep.

 Since we are supposed to align only on 2^n boundaries, if we get 0 or 1
 we do not align on p_align. But p_vaddr still has to be aligned on
 PAGE_MASK (with trunc_page()); I read somewhere that ELF loaders are
 smart enough to adjust the address when it does not exactly fit a page
 boundary. So bdiff should be the difference with the original p_vaddr.
 Actually, bdiff is already set to this value in the other conditions.

 There's another problem, 'base' should also be initialized here. I would
 say that is should be set to the truncated p_vaddr plus the address at
 which we want to load:

   base = *addr + trunc_page(ph-p_vaddr);

 but I'm not sure at all.

 By the logic of the ph-p_align  1 case, it should be
 base = *addr + trunc_page(ph-p_vaddr) - ph-p_vaddr;

 (I think the only reason the 'if' is necessary is that p_align==0 must be
 treated the same as p_align==1.  The ELF_TRUNC() macro handles an
 alignment of 1 correctly, but it'll barf on 0.)


 Philip Guenther

 
 



Re: [patch] courier-imap-4.13 imapd patch replacing malloc, strcat and strcpy with asprintf

2014-04-20 Thread Maxime Villard
Le 20/04/2014 02:38, Peter Malone a écrit :
 Hi,
 
 I'm using OpenBSD 5.5. courier-imap-4.13 is in the ports tree and it's
 quite a mess. I started looking at it today with the hope of just
 replacing some of the malloc,strcat  strcpy calls with asprintf, but it
 became clear before long that there's lots more issues with this code.
 
 Regardless, here's a patch which fixes some of the malloc,strcat 
 strcpy spaghetti in imapd.c 
 
 I figure you guys are fairly busy with OpenSSL right now so if it's OK
 with you I'll get working on the rest of this code.
 
 I spoke with the courier-imap team and their response was less than
 satisfactory - claiming asprintf code won't compile on non-linux
 platforms.

courier-imap is *totally buggy*. Not only because there are big
programming mistakes - at a time I started to fix many issues like
double-free, use-after-free, leaks, etc., before letting down -,
but also because this team doesn't give a fuck at all.

Give a quick glance at the code: it is just a great mess, with bugs
everywhere, no indentation, and probably no review. Clearly, there
are poor - not to say *no* - considerations for security. That's the
idea I made myself of this project, and you seem to have come to the
same conclusion.

 
 --- imapd_orig.c Sat Apr 19 19:38:18 2014
 +++ imapd.c Sat Apr 19 20:09:48 2014
 @@ -343,9 +343,8 @@
 
 if (q)
 {
 - r=malloc(strlen(q)+sizeof(/.));
 - if (!r) write_error_exit(0);
 - strcat(strcpy(r, q), /.);
 + if(asprintf(r, %s%s, q, /.) == -1)
 + write_error_exit(0);
 if (access(r, 0) == 0)
 {
 free(r);
 @@ -1373,11 +1372,9 @@
 
 static char *alloc_filename(const char *mbox, const char *name)
 {
 -char *p=malloc(strlen(mbox)+strlen(name)+sizeof(/cur/));
 -
 - if (!p) write_error_exit(0);
 -
 - strcat(strcat(strcpy(p, mbox), /cur/), name);
 + char *p;
 + if(asprintf(p, %s%s%s, mbox, /cur/, name) == -1)
 + write_error_exit(0);
 return (p);
 }
 
 @@ -1812,14 +1809,12 @@
 {
 #if EXPLICITDIRSYNC
 
 - char *p=malloc(strlen(folder)+sizeof(/new));
 + char *p;
 int fd;
 -
 - if (!p)
 + 
 + if(asprintf(p, %s%s, folder, /new) == -1)
 write_error_exit(0);
 
 - p=strcat(strcpy(p, folder), /new);
 -
 fd=open(p, O_RDONLY);
 
 if (fd = 0)
 @@ -1828,7 +1823,8 @@
 close(fd);
 }
 
 - p=strcat(strcpy(p, folder), /cur);
 + if(asprintf(p, %s%s, folder, /cur) == -1)
 + write_error_exit(0);
 
 fd=open(p, O_RDONLY);
 
 @@ -2212,12 +2208,10 @@
 {
 struct imapscaninfo minfo;
 
 - char *p=malloc(strlen(new_path)+sizeof(/ IMAPDB));
 + char *p;
 + if(asprintf(p, %s%s, new_path, / IMAPDB) == -1)
 +write_error_exit(0);
 
 - if (!p)
 - write_error_exit(0);
 -
 - strcat(strcpy(p, new_path), / IMAPDB);
 unlink(p);
 free(p);
 imapscan_init(minfo);
 @@ -2448,14 +2442,12 @@
 }
 return 0;
 }
 - q=malloc(strlen(p)+sizeof(/new));
 - if (!q)
 + if(asprintf(q, %s%s, p, /new) == -1)
 {
 free(p);
 maildir_aclt_list_destroy(aclt_list);
 return -1;
 }
 - strcat(strcpy(q, p), /new);
 free(p);
 
 if (maildir_aclt_list_add(aclt_list,
 @@ -4216,11 +4208,10 @@
 if (p  (p=maildir_shareddir(., p+1)) != NULL)
 {
 int rc;
 - char *q=malloc(strlen(p)+sizeof(/shared));
 -
 - if (!q) write_error_exit(0);
 -
 - strcat(strcpy(q, p), /shared);
 + char *q;
 + 
 + if(asprintf(q, %s%s, p, /shared) == -1)
 + write_error_exit(0);
 free(p);
 rc=append(tag, tok-tokenbuf, q);
 free(q);
 @@ -6041,10 +6032,9 @@
 isshared=0;
 if (is_sharedsubdir(cqinfo.destmailbox))
 {
 - char *p=malloc(strlen(cqinfo.destmailbox)+sizeof(/shared));
 -
 - if (!p) write_error_exit(0);
 - strcat(strcpy(p, cqinfo.destmailbox), /shared);
 + char *p;
 + if(asprintf(p, %s%s, cqinfo.destmailbox, /shared) == -1)
 + write_error_exit(0);
 
 free(mailbox);
 mailbox=cqinfo.destmailbox=p;
 



Re: [PATCH] ELF: ensure PT_INTERP strings are NULL-terminated

2013-12-14 Thread Maxime Villard
I would like to end this thread. Here's a final patch:

Index: exec_elf.c
===
RCS file: /cvs/src/sys/kern/exec_elf.c,v
retrieving revision 1.93
diff -u -r1.93 exec_elf.c
--- exec_elf.c  4 Jul 2013 17:37:05 -   1.93
+++ exec_elf.c  26 Nov 2013 18:36:35 -
@@ -552,11 +552,16 @@

for (i = 0, pp = ph; i  eh-e_phnum; i++, pp++) {
if (pp-p_type == PT_INTERP  !interp) {
-   if (pp-p_filesz = MAXPATHLEN)
+   if (pp-p_filesz  2 || pp-p_filesz  MAXPATHLEN)
goto bad;
interp = pool_get(namei_pool, PR_WAITOK);
if ((error = ELFNAME(read_from)(p, epp-ep_vp,
pp-p_offset, interp, pp-p_filesz)) != 0) {
+   goto bad;
+   }
+   /* Ensure interp is NUL-terminated and of the expected 
length */
+   if (strnlen(interp, pp-p_filesz) != pp-p_filesz - 1) {
+   error = ENOEXEC;
goto bad;
}
} else if (pp-p_type == PT_LOAD) {

To sum up what it does, and why it does what it does:

PT_INTERP segments are parts of PIE binaries, and specify a path to
an interpreter. This path's len is registered in the p_filesz field
of this segment, which includes the last NUL byte. The goal of this patch
is to check the length of this path to ensure it is consistent with
what is specified in p_filesz.

We do this, because otherwise the kernel may use a non-NUL-terminated
interp. It currently doesn't harm, since the copystr()'s that are later
called will stop the execution as well. But it is error-prone.

Ok/Opinions?



Re: Weird loop in ftp client

2013-12-14 Thread Maxime Villard
Is there something wrong with this patch?


Le 29/11/2013 20:44, Maxime Villard a écrit :
 What about that?
 
 Index: ftp.c
 ===
 RCS file: /cvs/src/usr.bin/ftp/ftp.c,v
 retrieving revision 1.83
 diff -u -r1.83 ftp.c
 --- ftp.c 13 Nov 2013 20:41:14 -  1.83
 +++ ftp.c 29 Nov 2013 21:17:49 -
 @@ -1089,9 +1089,10 @@
   may_send_noop_char();
   d = 0;
   do {
 - wr = write(fileno(fout), buf + d, rd);
 - if (wr == -1  errno == EPIPE)
 + if ((wr = write(fileno(fout), buf + d, rd)) == 
 -1) {
 + d = -1;
   break;
 + }
   d += wr;
   rd -= wr;
   } while (d  c);
 
 
 p is set to -1 to display the proper error message

of course here I meant 'd'

 
 



linux_socket: uninitialized variable ~ NULL pointer dereference

2013-12-14 Thread Maxime Villard
Hi,
I was reading linux_socket.c when I came across a bug in
linux_sendmsg().

Index: linux_socket.c
===
RCS file: /cvs/src/sys/compat/linux/linux_socket.c,v
retrieving revision 1.46
diff -u -r1.46 linux_socket.c
--- linux_socket.c  26 Jun 2012 10:18:08 -  1.46
+++ linux_socket.c  14 Dec 2013 17:45:37 -
@@ -1214,7 +1214,7 @@
struct msghdr msg, *nmsg = NULL;
int error;
caddr_t control;
-   int level;
+   int level = -1;

if ((error = copyin((caddr_t) uap, (caddr_t) lla, sizeof lla)))
return error;


At l.1252, if control == NULL, the function jumps to 'done' and 'level'
is checked while it hasn't been initialized. As 'control' is NULL,
copyout() tries to write to NULL-cmsg_level.

What the kernel wants to do is to translate the level from 1 to
SOL_SOCKET, call OpenBSD's sendmsg(), and then reset it to 1. By
setting level to -1, we prevent it from entering the if in 'done'.

Ok/Comments?



Re: linux_socket: uninitialized variable ~ NULL pointer dereference

2013-12-14 Thread Maxime Villard
Le 14/12/2013 19:18, Ted Unangst a écrit :
 On Sat, Dec 14, 2013 at 19:06, Maxime Villard wrote:
 Hi,
 I was reading linux_socket.c when I came across a bug in
 linux_sendmsg().
 
 At l.1252, if control == NULL, the function jumps to 'done' and 'level'
 is checked while it hasn't been initialized. As 'control' is NULL,
 copyout() tries to write to NULL-cmsg_level.
 
 Agree with the patch. Can you do one other change? Change
 control-level to control + offsetof(level). (Maybe with a second
 variable.) I think that would make it more clear that we're not
 dereferencing the pointer in the kernel and would reduce the number of
 casts.
 

ah, something like that? (not tested)

Index: linux_socket.c
===
RCS file: /cvs/src/sys/compat/linux/linux_socket.c,v
retrieving revision 1.46
diff -u -r1.46 linux_socket.c
--- linux_socket.c  26 Jun 2012 10:18:08 -  1.46
+++ linux_socket.c  14 Dec 2013 19:30:03 -
@@ -1214,7 +1214,8 @@
struct msghdr msg, *nmsg = NULL;
int error;
caddr_t control;
-   int level;
+   int level = -1;
+   void *ulevel;

if ((error = copyin((caddr_t) uap, (caddr_t) lla, sizeof lla)))
return error;
@@ -1251,8 +1252,8 @@
return error;
if (control == NULL)
goto done;
-   error = copyin(((struct cmsghdr *)control)-cmsg_level,
-   level, sizeof(int));
+   ulevel = control + offsetof(struct cmsghdr, cmsg_level);
+   error = copyin(ulevel, level, sizeof(int));
if (error)
return error;
if (level == 1) {
@@ -1266,8 +1267,7 @@
 * We don't because the control header is variable length
 * up to 2048 bytes, and there's only 512 bytes of gap.
 */
-   error = copyout(level, ((struct cmsghdr *)control)-
-   cmsg_level, sizeof(int));
+   error = copyout(level, ulevel, sizeof(int));
if (error)
return error;
}
@@ -1277,8 +1277,7 @@
if (level == SOL_SOCKET) {
level = 1;
/* don't worry about the error */
-   copyout(level, ((struct cmsghdr *)control)-cmsg_level,
-   sizeof(int));
+   copyout(level, ulevel, sizeof(int));
}
return (error);
 }



Kernel leak with compat-linux

2013-12-02 Thread Maxime Villard
Hi,
when loading a linux binary, the kernel could leak MAXPATHLEN bytes.

Index: linux_exec.c
===
RCS file: /cvs/src/sys/compat/linux/linux_exec.c,v
retrieving revision 1.38
diff -u -r1.38 linux_exec.c
--- linux_exec.c3 Nov 2013 13:52:44 -   1.38
+++ linux_exec.c1 Dec 2013 17:33:55 -
@@ -227,9 +227,10 @@
if (itp) {
if ((error = emul_find(p, NULL, linux_emul_path, itp, bp, 0)))
return (error);
-   if ((error = copystr(bp, itp, MAXPATHLEN, len)))
-   return (error);
+   error = copystr(bp, itp, MAXPATHLEN, len);
free(bp, M_TEMP);
+   if (error)
+   return (error);
}
epp-ep_emul = emul_linux_elf;
*pos = ELF32_NO_ADDR;

emul_find() allocates bp, and if the copystr() fails, bp is lost.

However, there's apparently no reason to fail here, since bp isn't
larger than MAXPATHLEN and is NUL-terminated.

While here, also fix a typo in a comment:

Index: linux_exec.c
===
RCS file: /cvs/src/sys/compat/linux/linux_exec.c,v
retrieving revision 1.38
diff -u -r1.38 linux_exec.c
--- linux_exec.c3 Nov 2013 13:52:44 -   1.38
+++ linux_exec.c2 Dec 2013 17:40:11 -
@@ -218,7 +218,7 @@
 * If this is a static binary, do not allow it to run, as it
 * has not been identified. We'll give non-static binaries a
 * chance to run, as the Linux ld.so name is usually unique
-* enough to clear any amibiguity.
+* enough to clear any ambiguity.
 */
if (itp == NULL)
return (EINVAL);


Ok/Comments?



Re: Weird loop in ftp client

2013-11-29 Thread Maxime Villard
What about that?

Index: ftp.c
===
RCS file: /cvs/src/usr.bin/ftp/ftp.c,v
retrieving revision 1.83
diff -u -r1.83 ftp.c
--- ftp.c   13 Nov 2013 20:41:14 -  1.83
+++ ftp.c   29 Nov 2013 21:17:49 -
@@ -1089,9 +1089,10 @@
may_send_noop_char();
d = 0;
do {
-   wr = write(fileno(fout), buf + d, rd);
-   if (wr == -1  errno == EPIPE)
+   if ((wr = write(fileno(fout), buf + d, rd)) == 
-1) {
+   d = -1;
break;
+   }
d += wr;
rd -= wr;
} while (d  c);


p is set to -1 to display the proper error message



Weird loop in ftp client

2013-11-22 Thread Maxime Villard
Hi,
a thing I spotted some weeks ago

- - - usr.bin/ftp/ftp.c l.1090 - - -

d = 0;
do {
wr = write(fileno(fout), buf + d, rd);
if (wr == -1  errno == EPIPE)
break;
d += wr;
rd -= wr;
} while (d  c);

If write() fails without EPIPE, d is decremented, and the function
keeps looping. If write() succeeds after several loops, d will be
negative, and the function will write from buf-XX.

Since d is later used to display a proper error message, I'd suggest
this patch:


Index: ftp.c
===
RCS file: /cvs/src/usr.bin/ftp/ftp.c,v
retrieving revision 1.83
diff -u -r1.83 ftp.c
--- ftp.c   13 Nov 2013 20:41:14 -  1.83
+++ ftp.c   22 Nov 2013 06:23:32 -
@@ -1094,7 +1094,7 @@
break;
d += wr;
rd -= wr;
-   } while (d  c);
+   } while (d  c  d  0);
if (rd != 0)
break;
bytes += c;


Any opinion?



Re: Weird loop in ftp client

2013-11-22 Thread Maxime Villard
Le 22/11/2013 17:48, Ted Unangst a écrit :
 On Fri, Nov 22, 2013 at 10:09, Stuart Henderson wrote:
 On 2013/11/22 07:25, Maxime Villard wrote:
 
 If write() fails without EPIPE, d is decremented, and the function
 keeps looping. If write() succeeds after several loops, d will be
 negative, and the function will write from buf-XX.
 
 When does write() fail and do we want to keep writing? (If I fill up
 the filesystem, do I really want to spin here?)


I must say that I actually fail to see why EPIPE is the only case
handled; it should stop looping regardless of the errno code,
shouldn't it?


 
 Shouldn't it be something more like this? Otherwise if the write() fails,
 we attempt writing one byte fewer for every retry.
 
 That looks better to me.
 



Re: [PATCH] ELF: ensure PT_INTERP strings are NULL-terminated

2013-11-21 Thread Maxime Villard
Le 06/10/2013 01:09, Kenneth R Westerback a écrit :
 On Sat, Oct 05, 2013 at 03:22:36PM -0600, Todd C. Miller wrote:
 On Wed, 28 Aug 2013 22:34:26 -0400, Kenneth R Westerback wrote:

 @@ -552,11 +552,16 @@ ELFNAME2(exec,makecmds)(struct proc *p, 
  
for (i = 0, pp = ph; i  eh-e_phnum; i++, pp++) {
if (pp-p_type == PT_INTERP  !interp) {
 -  if (pp-p_filesz = MAXPATHLEN)
 +  if (pp-p_filesz  2 || pp-p_filesz = MAXPATHLEN)

 Still think you're depriving yourself of one character out by using
 = instead of .

 I'm not sure about this.  We want to limit the path length to
 MAXPATHLEN-1 since we include the NUL terminator in MAXPATHLEN.
 The buffer we get from namei_pool is MAXPATHLEN long and the
 read_from() function just calls vn_rdwr().  If we allow interp to
 be MAXPATHLEN, is there any guarantee that it will end in a NUL
 byte?

  - todd

since get_pool() is not given PR_ZERO, interp won't be zeroed. So even
with the '=', there's no guarantee that it will end in a NUL byte.

p_filesz includes the last '\0'; there's no problem with changing '='
to ''.

 
 My reading at the time convinced me that p_filesz also includes the NUL. So
 using = left room for two NULs.
 
 But I am not trying to hold up either version, since I don't really
 understand the relevant code. :-)
 
  Ken
 



Re: Fix error code for ELF

2013-11-21 Thread Maxime Villard
Le 05/10/2013 23:10, Todd C. Miller a écrit :
 That looks reasonable to me.  I can't think of a reason to not
 return the proper errno values, especially as things like ENOMEM
 are already documented for execve(2).
 
  - todd
 

up...



Re: Wrong rights for ELF interpreters

2013-10-21 Thread Maxime Villard
On 10/20/13 21:54, Theo de Raadt wrote:
 Indeed, the interpreter is not passed to execve. That's why I used
 'get executed'
 instead of
 'are executed'
 though the difference might not be clear.
 
 The kernel loads the interpreter, and the code of that interpreter
 gets executed. So, actually, it plays as an executable. And as long
 as code gets executed from it, it should have +x rights.
 
 Shouldn't it?
 Absolutely not, because then someone can try to run execve on it.
 

Maybe I'm missing something.

I don't get what's wrong with running execve on it. In all cases,
someone can load it through another executable.

If I have an interpreter that I chmod as exec-only, I want this
interpreter to be world-loadable without thereby letting other
users copy it. The same for a library.

 You are not thinking clearly.

I've just given a glance to FreeBSD and NetBSD. They both check
exec rights, not read rights. So it looks like I'm not the only
one who does not think clearly...



Re: Wrong rights for ELF interpreters

2013-10-21 Thread Maxime Villard

Le 21/10/2013 09:38, Theo de Raadt a écrit :

I don't get what's wrong with running execve on it. In all cases,
someone can load it through another executable.


Using ld.so does not imply execve'ing it.


If I have an interpreter that I chmod as exec-only, I want this
interpreter to be world-loadable without thereby letting other
users copy it. The same for a library.


It is loadable.  Because it is readable.



I said exec-only, so no it is not readable and not loadable.
My point was that, actually, it should be loadable.

But after sleeping a bit, I figured out that there may indeed be
some issues with some libraries.

To me it looks weird. I'm gonna investigate a bit, and if I have
an objection I'll send it here.

Until then, sorry for the noise.



Wrong rights for ELF interpreters

2013-10-20 Thread Maxime Villard
Hi,
when the kernel loads an ELF binary, it will also load its interpreter.
The kernel checks the rights of the interpreter, that way:

if ((error = VOP_ACCESS(vp, VREAD, p-p_ucred, p)) != 0)
goto bad1;

It should check with VEXEC instead of VREAD. Interpreters get executed,
so they have to be executable; a read-only interpreter shouldn't be
loaded by the kernel.

Index: exec_elf.c
===
RCS file: /cvs/src/sys/kern/exec_elf.c,v
retrieving revision 1.93
diff -u -r1.93 exec_elf.c
--- exec_elf.c  4 Jul 2013 17:37:05 -   1.93
+++ exec_elf.c  7 Oct 2013 19:03:33 -
@@ -345,7 +345,7 @@
error = EACCES;
goto bad;
}
-   if ((error = VOP_ACCESS(vp, VREAD, p-p_ucred, p)) != 0)
+   if ((error = VOP_ACCESS(vp, VEXEC, p-p_ucred, p)) != 0)
goto bad1;
if ((error = ELFNAME(read_from)(p, nd.ni_vp, 0,
(caddr_t)eh, sizeof(eh))) != 0)


Ok/Comments?



Re: Wrong rights for ELF interpreters

2013-10-20 Thread Maxime Villard

Le 20/10/2013 16:53, Theo de Raadt a écrit :

when the kernel loads an ELF binary, it will also load its interpreter.
The kernel checks the rights of the interpreter, that way:

if ((error = VOP_ACCESS(vp, VREAD, p-p_ucred, p)) != 0)
goto bad1;

It should check with VEXEC instead of VREAD. Interpreters get executed,
so they have to be executable; a read-only interpreter shouldn't be
loaded by the kernel.


I am not sure I agree on this.



Why?



Re: Wrong rights for ELF interpreters

2013-10-20 Thread Maxime Villard

Le 20/10/2013 18:05, Theo de Raadt a écrit :

Le 20/10/2013 16:53, Theo de Raadt a écrit :

when the kernel loads an ELF binary, it will also load its interpreter.
The kernel checks the rights of the interpreter, that way:

if ((error = VOP_ACCESS(vp, VREAD, p-p_ucred, p)) != 0)
goto bad1;

It should check with VEXEC instead of VREAD. Interpreters get executed,
so they have to be executable; a read-only interpreter shouldn't be
loaded by the kernel.


I am not sure I agree on this.



Why?


VEXEC is used in other cases to insist on a filesystem permission, for
instance, when supplying a path for execve().

The interpreter is not a path supplied to execve.



Indeed, the interpreter is not passed to execve. That's why I used
'get executed'
instead of
'are executed'
though the difference might not be clear.

The kernel loads the interpreter, and the code of that interpreter
gets executed. So, actually, it plays as an executable. And as long
as code gets executed from it, it should have +x rights.

Shouldn't it?



Re: [PATCH] ELF: ensure PT_INTERP strings are NULL-terminated

2013-10-05 Thread Maxime Villard
up, please


Le 28/08/2013 21:43, Maxime Villard a écrit :
 On 08/28/13 20:57, Matthew Dempsky wrote:
 On Wed, Aug 28, 2013 at 5:54 AM, Maxime Villard m...@m00nbsd.net wrote:
 +   /* Ensure interp is a valid, NUL-terminated string 
 */
 +   for (n = 0; n  pp-p_filesz; n++) {
 +   if (interp[n] == '\0')
 +   break;
 +   }
 +   if (n != pp-p_filesz - 1) {
 +   error = ENOEXEC;
   goto bad;
   }

 A more concise test would be:

   if (strnlen(interp, pp-p_filesz) != pp-p_filesz - 1) {
   error = ENOEXEC;
   goto bad;
   }

 
 Hum you're right, it's better that way
 
 
 Index: exec_elf.c
 ===
 RCS file: /cvs/src/sys/kern/exec_elf.c,v
 retrieving revision 1.93
 diff -u -p -r1.93 exec_elf.c
 --- exec_elf.c4 Jul 2013 17:37:05 -   1.93
 +++ exec_elf.c28 Aug 2013 21:14:22 -
 @@ -552,11 +552,16 @@ ELFNAME2(exec,makecmds)(struct proc *p,
   
   for (i = 0, pp = ph; i  eh-e_phnum; i++, pp++) {
   if (pp-p_type == PT_INTERP  !interp) {
 - if (pp-p_filesz = MAXPATHLEN)
 + if (pp-p_filesz  2 || pp-p_filesz = MAXPATHLEN)
   goto bad;
   interp = pool_get(namei_pool, PR_WAITOK);
   if ((error = ELFNAME(read_from)(p, epp-ep_vp,
   pp-p_offset, interp, pp-p_filesz)) != 0) {
 + goto bad;
 + }
 + /* Ensure interp is NUL-terminated and of the expected 
 length */
 + if (strnlen(interp, pp-p_filesz) != pp-p_filesz - 1) {
 + error = ENOEXEC;
   goto bad;
   }
   } else if (pp-p_type == PT_LOAD) {
 
 
 It no longer looks like my patch...
 
 



Re: Set of 14 potential bugs

2013-09-19 Thread Maxime Villard
Le 12/07/2013 20:24, Maxime Villard a écrit :
 Hi,
 as I did for NetBSD, here is a list of 14 potential bugs/errors
 found by my code scanner in OpenBSD:
 
   http://M00nBSD.net/e5ab5f6e59d6a0feb7d1a518acc8233d.html
 
 I do not provide patches.
 
 

May I ask what's the status of the remaining bugs?



[PATCH] ELF: ensure PT_INTERP strings are NULL-terminated

2013-08-28 Thread Maxime Villard
Hi,
in the ELF format, the PT_INTERP segment contains the path of the
interpreter which must be loaded. For this segment, the kernel looks
at these values in the program header:

 p_offset: offset of the path string
 p_filesz: size of the path string, including the \0

The path string must be a valid string, or the binary won't be loaded.

The kernel actually doesn't check the string, it just reads p_filesz
bytes from p_offset, and later it checks if it can be loaded. Malformed
binaries which have paths like:

a
or
aaa\0aaa\0aaa\0aaa\0

are parsed, loaded, and then the kernel figures out that the path is
not valid, and aborts.

When the kernel reads the path from the file, it should check directly
the string to ensure it is at least a valid string.

Here is a patch for this. For pp-p_filesz, I could have put
if (pp-p_filesz == 0)
but values of 1 also don't make sense; \0 can't be a valid path.



Index: exec_elf.c
===
RCS file: /cvs/src/sys/kern/exec_elf.c,v
retrieving revision 1.93
diff -u -p -r1.93 exec_elf.c
--- exec_elf.c  4 Jul 2013 17:37:05 -   1.93
+++ exec_elf.c  27 Aug 2013 22:59:21 -
@@ -513,7 +513,7 @@ ELFNAME2(exec,makecmds)(struct proc *p, 
Elf_Ehdr *eh = epp-ep_hdr;
Elf_Phdr *ph, *pp, *base_ph = NULL;
Elf_Addr phdr = 0, exe_base = 0;
-   int error, i;
+   int error, i, n;
char *interp = NULL;
u_long pos = 0, phsize;
size_t randomizequota = ELF_RANDOMIZE_LIMIT;
@@ -552,11 +552,21 @@ ELFNAME2(exec,makecmds)(struct proc *p, 
 
for (i = 0, pp = ph; i  eh-e_phnum; i++, pp++) {
if (pp-p_type == PT_INTERP  !interp) {
-   if (pp-p_filesz = MAXPATHLEN)
+   if (pp-p_filesz = MAXPATHLEN ||
+   pp-p_filesz  2)
goto bad;
interp = pool_get(namei_pool, PR_WAITOK);
if ((error = ELFNAME(read_from)(p, epp-ep_vp,
pp-p_offset, interp, pp-p_filesz)) != 0) {
+   goto bad;
+   }
+   /* Ensure interp is a valid, NULL-terminated string */
+   for (n = 0; n  pp-p_filesz; n++) {
+   if (interp[n] == '\0')
+   break;
+   }
+   if (n != pp-p_filesz - 1) {
+   error = ENOEXEC;
goto bad;
}
} else if (pp-p_type == PT_LOAD) {



If you want to test
 * Before patching
   take whatever binary you have, open it with a text/hex editor, at the
   beginning of the file there should be a string like /usr/libexec/ld.so,
   just add a character to it, then run the binary with execv(): you will
   get abort traps.
 * After patching
   execv() now returns -1, and errno is set to ENOEXEC.

There should not be any regression; if there is, it means that the binary
is not spec compliant.


Ok/Comments?



Re: [PATCH] ELF: ensure PT_INTERP strings are NULL-terminated

2013-08-28 Thread Maxime Villard
Updated diff, with small tweaks from Andres Perera,
 * int - size_t, signedness issue, even if it can't be INT_MAX
 * NULL - NUL


Index: exec_elf.c
===
RCS file: /cvs/src/sys/kern/exec_elf.c,v
retrieving revision 1.93
diff -u -p -r1.93 exec_elf.c
--- exec_elf.c  4 Jul 2013 17:37:05 -   1.93
+++ exec_elf.c  28 Aug 2013 14:36:58 -
@@ -516,7 +516,7 @@ ELFNAME2(exec,makecmds)(struct proc *p, 
int error, i;
char *interp = NULL;
u_long pos = 0, phsize;
-   size_t randomizequota = ELF_RANDOMIZE_LIMIT;
+   size_t n, randomizequota = ELF_RANDOMIZE_LIMIT;
 
if (epp-ep_hdrvalid  sizeof(Elf_Ehdr))
return (ENOEXEC);
@@ -552,11 +552,21 @@ ELFNAME2(exec,makecmds)(struct proc *p, 
 
for (i = 0, pp = ph; i  eh-e_phnum; i++, pp++) {
if (pp-p_type == PT_INTERP  !interp) {
-   if (pp-p_filesz = MAXPATHLEN)
+   if (pp-p_filesz = MAXPATHLEN ||
+   pp-p_filesz  2)
goto bad;
interp = pool_get(namei_pool, PR_WAITOK);
if ((error = ELFNAME(read_from)(p, epp-ep_vp,
pp-p_offset, interp, pp-p_filesz)) != 0) {
+   goto bad;
+   }
+   /* Ensure interp is a valid, NUL-terminated string */
+   for (n = 0; n  pp-p_filesz; n++) {
+   if (interp[n] == '\0')
+   break;
+   }
+   if (n != pp-p_filesz - 1) {
+   error = ENOEXEC;
goto bad;
}
} else if (pp-p_type == PT_LOAD) {



On 08/28/13 08:44, Maxime Villard wrote:
 Hi,
 in the ELF format, the PT_INTERP segment contains the path of the
 interpreter which must be loaded. For this segment, the kernel looks
 at these values in the program header:
 
   p_offset: offset of the path string
   p_filesz: size of the path string, including the \0
 
 The path string must be a valid string, or the binary won't be loaded.
 
 The kernel actually doesn't check the string, it just reads p_filesz
 bytes from p_offset, and later it checks if it can be loaded. Malformed
 binaries which have paths like:
 
   a
 or
   aaa\0aaa\0aaa\0aaa\0
 
 are parsed, loaded, and then the kernel figures out that the path is
 not valid, and aborts.
 
 When the kernel reads the path from the file, it should check directly
 the string to ensure it is at least a valid string.
 
 Here is a patch for this. For pp-p_filesz, I could have put
   if (pp-p_filesz == 0)
 but values of 1 also don't make sense; \0 can't be a valid path.
 
 
 
 Index: exec_elf.c
 ===
 RCS file: /cvs/src/sys/kern/exec_elf.c,v
 retrieving revision 1.93
 diff -u -p -r1.93 exec_elf.c
 --- exec_elf.c4 Jul 2013 17:37:05 -   1.93
 +++ exec_elf.c27 Aug 2013 22:59:21 -
 @@ -513,7 +513,7 @@ ELFNAME2(exec,makecmds)(struct proc *p,
   Elf_Ehdr *eh = epp-ep_hdr;
   Elf_Phdr *ph, *pp, *base_ph = NULL;
   Elf_Addr phdr = 0, exe_base = 0;
 - int error, i;
 + int error, i, n;
   char *interp = NULL;
   u_long pos = 0, phsize;
   size_t randomizequota = ELF_RANDOMIZE_LIMIT;
 @@ -552,11 +552,21 @@ ELFNAME2(exec,makecmds)(struct proc *p,
   
   for (i = 0, pp = ph; i  eh-e_phnum; i++, pp++) {
   if (pp-p_type == PT_INTERP  !interp) {
 - if (pp-p_filesz = MAXPATHLEN)
 + if (pp-p_filesz = MAXPATHLEN ||
 + pp-p_filesz  2)
   goto bad;
   interp = pool_get(namei_pool, PR_WAITOK);
   if ((error = ELFNAME(read_from)(p, epp-ep_vp,
   pp-p_offset, interp, pp-p_filesz)) != 0) {
 + goto bad;
 + }
 + /* Ensure interp is a valid, NULL-terminated string */
 + for (n = 0; n  pp-p_filesz; n++) {
 + if (interp[n] == '\0')
 + break;
 + }
 + if (n != pp-p_filesz - 1) {
 + error = ENOEXEC;
   goto bad;
   }
   } else if (pp-p_type == PT_LOAD) {
 
 
 
 If you want to test
   * Before patching
 take whatever binary you have, open it with a text/hex editor, at the
 beginning of the file there should be a string like /usr/libexec/ld.so,
 just add a character to it, then run the binary with execv(): you will
 get abort traps.
   * After patching
 execv() now returns -1

Re: [PATCH] ELF: ensure PT_INTERP strings are NULL-terminated

2013-08-28 Thread Maxime Villard
On 08/28/13 16:30, Kenneth R Westerback wrote:
 On Wed, Aug 28, 2013 at 02:54:11PM +0200, Maxime Villard wrote:
 Updated diff, with small tweaks from Andres Perera,
   * int - size_t, signedness issue, even if it can't be INT_MAX
   * NULL - NUL


 Index: exec_elf.c
 ===
 RCS file: /cvs/src/sys/kern/exec_elf.c,v
 retrieving revision 1.93
 diff -u -p -r1.93 exec_elf.c
 --- exec_elf.c   4 Jul 2013 17:37:05 -   1.93
 +++ exec_elf.c   28 Aug 2013 14:36:58 -
 @@ -516,7 +516,7 @@ ELFNAME2(exec,makecmds)(struct proc *p,
  int error, i;
  char *interp = NULL;
  u_long pos = 0, phsize;
 -size_t randomizequota = ELF_RANDOMIZE_LIMIT;
 +size_t n, randomizequota = ELF_RANDOMIZE_LIMIT;
   
  if (epp-ep_hdrvalid  sizeof(Elf_Ehdr))
  return (ENOEXEC);
 @@ -552,11 +552,21 @@ ELFNAME2(exec,makecmds)(struct proc *p,
   
  for (i = 0, pp = ph; i  eh-e_phnum; i++, pp++) {
  if (pp-p_type == PT_INTERP  !interp) {
 -if (pp-p_filesz = MAXPATHLEN)
 +if (pp-p_filesz = MAXPATHLEN ||
 +pp-p_filesz  2)
 
 Since p_filesz includes the NUL and MAXPATHLEN includes the NUL as
 far as I know, could the comparison not be simply ' MAXPATHLEN'?
 
 In passing I note that 37 out of 749 declarations using MAXPATHLEN in the
 tree use 'char blah[MAXPATHLEN + 1]'. No idea if it is worth looking at
 making them do without the '+ 1'. :-)
 
 I also note in passing several #define PATH_MAX (MAXPATHLEN + 1)'
 declarations, which strike me as odd since MAXPATHLEN is defined
 in sys/param.h by '#define MAXPATHEN PATH_MAX'.
 
 Let the POSIX lawyers apply any necessary cluebats please.
 
  goto bad;
  interp = pool_get(namei_pool, PR_WAITOK);
  if ((error = ELFNAME(read_from)(p, epp-ep_vp,
  pp-p_offset, interp, pp-p_filesz)) != 0) {
 +goto bad;
 +}
 +/* Ensure interp is a valid, NUL-terminated string */
 
 The condition is not that the string is NUL terminated (aaa\0aaa\0 is after
 all NUL terminated and valid as far as any function reading strings would be
 concerned. It just has trailing garbage.) Perhaps the comment should refer
 to making sure the string is spec compliant by being of the expected length.


By 'valid string' I actually meant 'without trailing garbage'... but ok
if it's not clear
/* Ensure interp is NUL-terminated and of the expected length */


 
  Ken
 
 +for (n = 0; n  pp-p_filesz; n++) {
 +if (interp[n] == '\0')
 +break;
 +}
 +if (n != pp-p_filesz - 1) {
 +error = ENOEXEC;
  goto bad;
  }
  } else if (pp-p_type == PT_LOAD) {



 On 08/28/13 08:44, Maxime Villard wrote:
 Hi,
 in the ELF format, the PT_INTERP segment contains the path of the
 interpreter which must be loaded. For this segment, the kernel looks
 at these values in the program header:

p_offset: offset of the path string
p_filesz: size of the path string, including the \0

 The path string must be a valid string, or the binary won't be loaded.

 The kernel actually doesn't check the string, it just reads p_filesz
 bytes from p_offset, and later it checks if it can be loaded. Malformed
 binaries which have paths like:

 a
 or
 aaa\0aaa\0aaa\0aaa\0

 are parsed, loaded, and then the kernel figures out that the path is
 not valid, and aborts.

 When the kernel reads the path from the file, it should check directly
 the string to ensure it is at least a valid string.

 Here is a patch for this. For pp-p_filesz, I could have put
 if (pp-p_filesz == 0)
 but values of 1 also don't make sense; \0 can't be a valid path.



 Index: exec_elf.c
 ===
 RCS file: /cvs/src/sys/kern/exec_elf.c,v
 retrieving revision 1.93
 diff -u -p -r1.93 exec_elf.c
 --- exec_elf.c  4 Jul 2013 17:37:05 -   1.93
 +++ exec_elf.c  27 Aug 2013 22:59:21 -
 @@ -513,7 +513,7 @@ ELFNAME2(exec,makecmds)(struct proc *p,
 Elf_Ehdr *eh = epp-ep_hdr;
 Elf_Phdr *ph, *pp, *base_ph = NULL;
 Elf_Addr phdr = 0, exe_base = 0;
 -   int error, i;
 +   int error, i, n;
 char *interp = NULL;
 u_long pos = 0, phsize;
 size_t randomizequota = ELF_RANDOMIZE_LIMIT;
 @@ -552,11 +552,21 @@ ELFNAME2(exec,makecmds)(struct proc *p,

 for (i = 0, pp = ph; i  eh-e_phnum; i++, pp++) {
 if (pp-p_type == PT_INTERP  !interp) {
 -   if (pp-p_filesz = MAXPATHLEN)
 +   if (pp-p_filesz = MAXPATHLEN ||
 +   pp-p_filesz  2)
 goto

Re: [PATCH] ELF: ensure PT_INTERP strings are NULL-terminated

2013-08-28 Thread Maxime Villard
On 08/28/13 20:57, Matthew Dempsky wrote:
 On Wed, Aug 28, 2013 at 5:54 AM, Maxime Villard m...@m00nbsd.net wrote:
 +   /* Ensure interp is a valid, NUL-terminated string */
 +   for (n = 0; n  pp-p_filesz; n++) {
 +   if (interp[n] == '\0')
 +   break;
 +   }
 +   if (n != pp-p_filesz - 1) {
 +   error = ENOEXEC;
  goto bad;
  }
 
 A more concise test would be:
 
  if (strnlen(interp, pp-p_filesz) != pp-p_filesz - 1) {
  error = ENOEXEC;
  goto bad;
  }
 

Hum you're right, it's better that way


Index: exec_elf.c
===
RCS file: /cvs/src/sys/kern/exec_elf.c,v
retrieving revision 1.93
diff -u -p -r1.93 exec_elf.c
--- exec_elf.c  4 Jul 2013 17:37:05 -   1.93
+++ exec_elf.c  28 Aug 2013 21:14:22 -
@@ -552,11 +552,16 @@ ELFNAME2(exec,makecmds)(struct proc *p, 
 
for (i = 0, pp = ph; i  eh-e_phnum; i++, pp++) {
if (pp-p_type == PT_INTERP  !interp) {
-   if (pp-p_filesz = MAXPATHLEN)
+   if (pp-p_filesz  2 || pp-p_filesz = MAXPATHLEN)
goto bad;
interp = pool_get(namei_pool, PR_WAITOK);
if ((error = ELFNAME(read_from)(p, epp-ep_vp,
pp-p_offset, interp, pp-p_filesz)) != 0) {
+   goto bad;
+   }
+   /* Ensure interp is NUL-terminated and of the expected 
length */
+   if (strnlen(interp, pp-p_filesz) != pp-p_filesz - 1) {
+   error = ENOEXEC;
goto bad;
}
} else if (pp-p_type == PT_LOAD) {


It no longer looks like my patch...



Fix error code for ELF

2013-08-26 Thread Maxime Villard
Hi,
after playing with some ELF binaries, I figured out that error
codes received in errno do not always match with what is expected
in the kernel.

Actually, this function should return (error) instead of (ENOEXEC):


Index: exec_elf.c
===
RCS file: /cvs/src/sys/kern/exec_elf.c,v
retrieving revision 1.93
diff -u -p -r1.93 exec_elf.c
--- exec_elf.c  4 Jul 2013 17:37:05 -   1.93
+++ exec_elf.c  26 Aug 2013 15:26:06 -
@@ -552,8 +552,10 @@ ELFNAME2(exec,makecmds)(struct proc *p, 
 
for (i = 0, pp = ph; i  eh-e_phnum; i++, pp++) {
if (pp-p_type == PT_INTERP  !interp) {
-   if (pp-p_filesz = MAXPATHLEN)
+   if (pp-p_filesz = MAXPATHLEN) {
+   error = ENOEXEC;
goto bad;
+   }
interp = pool_get(namei_pool, PR_WAITOK);
if ((error = ELFNAME(read_from)(p, epp-ep_vp,
pp-p_offset, interp, pp-p_filesz)) != 0) {
@@ -567,8 +569,10 @@ ELFNAME2(exec,makecmds)(struct proc *p, 
 
if (eh-e_type == ET_DYN) {
/* need an interpreter and load sections for PIE */
-   if (interp == NULL || base_ph == NULL)
+   if (interp == NULL || base_ph == NULL) {
+   error = ENOEXEC;
goto bad;
+   }
/* randomize exe_base for PIE */
exe_base = uvm_map_pie(base_ph-p_align);
}
@@ -589,9 +593,9 @@ ELFNAME2(exec,makecmds)(struct proc *p, 
 * *interp with a changed path (/emul/xxx/path), and also
 * set the ep_emul field in the exec package structure.
 */
-   error = ENOEXEC;
if (eh-e_ident[EI_OSABI] != ELFOSABI_OPENBSD 
ELFNAME(os_pt_note)(p, epp, epp-ep_hdr, OpenBSD, 8, 4) != 0) {
+   error = ENOEXEC;
for (i = 0; ELFNAME(probes)[i].func != NULL  error; i++)
error = (*ELFNAME(probes)[i].func)(p, epp, interp, 
pos);
if (error)
@@ -760,7 +764,7 @@ bad:
pool_put(namei_pool, interp);
free(ph, M_TEMP);
kill_vmcmds(epp-ep_vmcmds);
-   return (ENOEXEC);
+   return (error);
 }
 
 /*


Ok/Comments?



Re: exec_elf.c: mistake ?

2013-08-15 Thread Maxime Villard
Le 06/07/2013 17:42, Kenneth R Westerback a écrit :
 On Sat, Jul 06, 2013 at 05:21:31PM +0200, Maxime Villard wrote:
 Hi,
 - - - - sys/kern/exec_elf.c l.236 ~ 251252
 Are my code scanner and me wrong, or 'bdiff' may not be
 initialized ?

 
 Codewise it does look possible that bdiff will be used uninitialized.
 Whether it can happen in reality depends on whether ph-p_align can ever
 be  1. Next question -- what would the correct value for bdiff be in that

= 1

 case?  0? i.e. should the line be 'diff = bdiff = 0;'.
 
  Ken
 

Hum hum, after investigating a bit, and from what I understood - if I'm
not mistaken, I think it would make sense if bdiff was set to

bdiff = ph-p_vaddr - trunc_page(ph-p_vaddr);

Since we are supposed to align only on 2^n boundaries, if we get 0 or 1
we do not align on p_align. But p_vaddr still has to be aligned on
PAGE_MASK (with trunc_page()); I read somewhere that ELF loaders are
smart enough to adjust the address when it does not exactly fit a page
boundary. So bdiff should be the difference with the original p_vaddr.
Actually, bdiff is already set to this value in the other conditions.

There's another problem, 'base' should also be initialized here. I would
say that is should be set to the truncated p_vaddr plus the address at
which we want to load:

base = *addr + trunc_page(ph-p_vaddr);

but I'm not sure at all.

Anyway, here is a patch. With these changes, 'uaddr' becomes useless,
so I removed it.

...Ok?




Index: exec_elf.c
===
RCS file: /cvs/src/sys/kern/exec_elf.c,v
retrieving revision 1.93
diff -u -r1.93 exec_elf.c
--- exec_elf.c  4 Jul 2013 17:37:05 -   1.93
+++ exec_elf.c  14 Aug 2013 18:31:37 -
@@ -215,7 +215,7 @@
 ELFNAME(load_psection)(struct exec_vmcmd_set *vcset, struct vnode *vp,
Elf_Phdr *ph, Elf_Addr *addr, Elf_Addr *size, int *prot, int flags)
 {
-   u_long uaddr, msize, lsize, psize, rm, rf;
+   u_long msize, lsize, psize, rm, rf;
long diff, offset, bdiff;
Elf_Addr base;
 
@@ -229,19 +229,16 @@
/* page align vaddr */
base = *addr + trunc_page(ph-p_vaddr) 
- ELF_TRUNC(ph-p_vaddr, ph-p_align);
-
-   bdiff = ph-p_vaddr - trunc_page(ph-p_vaddr);
-
} else
diff = 0;
} else {
-   *addr = uaddr = ph-p_vaddr;
+   *addr = ph-p_vaddr;
if (ph-p_align  1)
-   *addr = ELF_TRUNC(uaddr, ph-p_align);
-   base = trunc_page(uaddr);
-   bdiff = uaddr - base;
-   diff = uaddr - *addr;
+   *addr = ELF_TRUNC(*addr, ph-p_align);
+   base = trunc_page(ph-p_vaddr);
+   diff = ph-p_vaddr - *addr;
}
+   bdiff = ph-p_vaddr - trunc_page(ph-p_vaddr);
 
*prot |= (ph-p_flags  PF_R) ? VM_PROT_READ : 0;
*prot |= (ph-p_flags  PF_W) ? VM_PROT_WRITE : 0;



pcmcia/if_ray.c: dead code

2013-08-11 Thread Maxime Villard
Hi,
in src/sys/dev/pcmcia/if_ray.c, at l.1018:

- - - -

case SIOCG80211NWID:
RAY_DPRINTF((%s: ioctl: cmd SIOCG80211NWID\n, ifp-if_xname));
error = copyout(sc-sc_cnwid, ifr-ifr_data,
sizeof(sc-sc_cnwid));
break; --
#ifdef RAY_DO_SIGLEV
error = copyout(sc-sc_siglevs, ifr-ifr_data,
sizeof sc-sc_siglevs);
break;
#endif
default:
[...]

- - - -

The code in the 'ifdef' is never reached, because of the 'break'. Found
by my scanner.



softraid_aoe.c

2013-07-22 Thread Maxime Villard
Hi,
- - - dev/softraid_aoe.c - - -
I don't know if it's a mistake, but at l.393 the function always
returns 1.

If you put that just to temporarily shut down the function, then you
should add a comment to explicitly tell to the stupid guys who might
think it's a mistake - like me - something like

/* Ok here. */



Set of 14 potential bugs

2013-07-12 Thread Maxime Villard
Hi,
as I did for NetBSD, here is a list of 14 potential bugs/errors
found by my code scanner in OpenBSD:

http://M00nBSD.net/e5ab5f6e59d6a0feb7d1a518acc8233d.html

I do not provide patches.



Static variables

2013-07-08 Thread Maxime Villard
Hi,
is it normal that in some functions like

tc_ticktock(void)
{
static int count;

if (++count  tc_tick)
return;
count = 0;
tc_windup();
}

the static variables are not initialized?

- kern_tc.c l.547
- kern_resource.c l.499
- kern_sched.c l.106
- subr_extent.c l.130
- ...



Re: Static variables

2013-07-08 Thread Maxime Villard
Le 08/07/2013 11:00, Franco Fichtner a écrit :
 Hi Maxime,
 
 On Jul 8, 2013, at 10:40 AM, Maxime Villard rusty...@gmx.fr wrote:
 
 the static variables are not initialized?
 
 Static variables are always zeroed when not specified otherwise.
 
 
 Regards,
 Franco
 
 

Ah, yes. I didn't know.



exec_elf.c: mistake ?

2013-07-06 Thread Maxime Villard
Hi,
- - - - sys/kern/exec_elf.c l.236 ~ 251252
Are my code scanner and me wrong, or 'bdiff' may not be
initialized ?



smtpd: if?

2013-07-04 Thread Maxime Villard
Hi,

- - - src/usr.sbin/smtpd/smtpd.c l.1326

if (! bsnprintf(key, sizeof key,
profiling.imsg.%s.%s.%s,
proc_name(smtpd_process),
proc_name(p-proc),
imsg_to_str(imsg-hdr.type)));-- ';'
stat_set(key, stat_timespec(dt));


What's the goal of the 'if' right there?



[PATCH?] Variable assignments...

2013-06-24 Thread Maxime Villard
Hi,
there are lots of useless assignment of variables in the code. I know this
kind of things does not really matter, but when I run my code scanner on
some parts of the source tree it gives me lots of them.

For example, for the net* directories:

== src/sys/net/if_bridge.c - l2017

u_int32_t cnt = 0;--- Here, we don't need to set cnt to 0
struct bridge_rtnode *n;
struct ifbareq bareq;

if (baconf-ifbac_len == 0)
onlycnt = 1;

for (i = 0, cnt = 0; i  BRIDGE_RTABLE_SIZE; i++) --- set here

== src/sys/net/if_sppprubr.c - l403

int i = 0, x;

i = 0;  Hum, hum, hum

== src/sys/net/if_pppx.c - l238

int rv = 0; --- ?

rv = rw_enter(pppx_devs_lk, RW_WRITE | RW_INTR);

== src/sys/netinet/if_output.c - l623

int transportmode = 0; - ?

transportmode = (tdb-tdb_dst.sa.sa_family == AF_INET) 
(tdb-tdb_dst.sin.sin_addr.s_addr ==
ip-ip_dst.s_addr);

== src/sys/netinet6/raw_ip6.c - l380

int priv = 0;   --
va_list ap;
int flags;

va_start(ap, m);
so = va_arg(ap, struct socket *);
dstsock = va_arg(ap, struct sockaddr_in6 *);
control = va_arg(ap, struct mbuf *);
va_end(ap);

in6p = sotoin6pcb(so);

priv = 0;  --- ?


Same thing in several other places... Here is a patch for these dirs.

Ok/Comments?


Index: net/if_bridge.c
===
RCS file: /cvs/src/sys/net/if_bridge.c,v
retrieving revision 1.210
diff -u -r1.210 if_bridge.c
--- net/if_bridge.c 28 Mar 2013 23:10:05 -  1.210
+++ net/if_bridge.c 24 Jun 2013 15:55:08 -
@@ -2014,7 +2014,7 @@
 bridge_rtfind(struct bridge_softc *sc, struct ifbaconf *baconf)
 {
int i, error = 0, onlycnt = 0;
-   u_int32_t cnt = 0;
+   u_int32_t cnt;
struct bridge_rtnode *n;
struct ifbareq bareq;
 
Index: net/if_pppx.c
===
RCS file: /cvs/src/sys/net/if_pppx.c,v
retrieving revision 1.23
diff -u -r1.23 if_pppx.c
--- net/if_pppx.c   24 Jun 2013 09:34:59 -  1.23
+++ net/if_pppx.c   24 Jun 2013 15:55:08 -
@@ -235,7 +235,7 @@
 pppxopen(dev_t dev, int flags, int mode, struct proc *p)
 {
struct pppx_dev *pxd;
-   int rv = 0;
+   int rv;
 
rv = rw_enter(pppx_devs_lk, RW_WRITE | RW_INTR);
if (rv != 0)
Index: net/if_spppsubr.c
===
RCS file: /cvs/src/sys/net/if_spppsubr.c,v
retrieving revision 1.104
diff -u -r1.104 if_spppsubr.c
--- net/if_spppsubr.c   20 Jun 2013 12:03:40 -  1.104
+++ net/if_spppsubr.c   24 Jun 2013 15:55:09 -
@@ -4028,7 +4028,6 @@
STDDCL;
int i = 0, x;
 
-   i = 0;
sp-rst_counter[IDX_CHAP] = sp-lcp.max_configure;
 
/*
Index: netinet/ip_output.c
===
RCS file: /cvs/src/sys/netinet/ip_output.c,v
retrieving revision 1.241
diff -u -r1.241 ip_output.c
--- netinet/ip_output.c 11 Jun 2013 18:15:53 -  1.241
+++ netinet/ip_output.c 24 Jun 2013 15:55:10 -
@@ -620,7 +620,7 @@
tdb-tdb_mtutimeout  time_second) {
struct rtentry *rt = NULL;
int rt_mtucloned = 0;
-   int transportmode = 0;
+   int transportmode;
 
transportmode = (tdb-tdb_dst.sa.sa_family == AF_INET) 

(tdb-tdb_dst.sin.sin_addr.s_addr ==
Index: netinet6/raw_ip6.c
===
RCS file: /cvs/src/sys/netinet6/raw_ip6.c,v
retrieving revision 1.58
diff -u -r1.58 raw_ip6.c
--- netinet6/raw_ip6.c  4 Jun 2013 19:11:52 -   1.58
+++ netinet6/raw_ip6.c  24 Jun 2013 15:55:10 -
@@ -377,7 +377,6 @@
 
in6p = sotoin6pcb(so);
 
-   priv = 0;
if ((so-so_state  SS_PRIV) != 0)
priv = 1;
dst = dstsock-sin6_addr;



[PATCH] Mistake in Intel/DRM...

2013-05-05 Thread Maxime Villard
I have been making a code scanner for a while, and I wanted to test
a new rule, so I scanned sys/pci/drm. It found an uninitialized
variable in intel_ddi.c.

Quite simple, if !(val  DDI_BUF_CTL_ENABLE) at l.1420, the variable
'wait' is not initialized at l.1432.

I guess I should send it upstream, but, you know, I don't want to
subscribe to the ML only to send one small mail. Is there someone here
who's upstream or who's willing to send that patch?

Thanks


Index: intel_ddi.c
===
RCS file: /cvs/src/sys/dev/pci/drm/i915/intel_ddi.c,v
retrieving revision 1.1
diff -u -r1.1 intel_ddi.c
--- intel_ddi.c 18 Mar 2013 12:36:52 -  1.1
+++ intel_ddi.c 5 May 2013 10:56:40 -
@@ -1412,7 +1412,7 @@
struct intel_dp *intel_dp = intel_dig_port-dp;
struct inteldrm_softc *dev_priv = encoder-dev-dev_private;
enum port port = intel_dig_port-port;
-   bool wait;
+   bool wait = false;
uint32_t val;
 
if (I915_READ(DP_TP_CTL(port))  DP_TP_CTL_ENABLE) {



[ntpd] Useless variables...

2013-04-27 Thread Maxime Villard
Hi,
here is a patch to remove two useless variables in ntpd. Spotted
when recompiling with -Wextra.

Ok/Comments?

Index: client.c
===
RCS file: /cvs/src/usr.sbin/ntpd/client.c,v
retrieving revision 1.89
diff -u -p -r1.89 client.c
--- client.c21 Sep 2011 15:41:30 -  1.89
+++ client.c27 Apr 2013 21:59:52 -
@@ -186,8 +186,7 @@ client_query(struct ntp_peer *p)
p-query-msg.xmttime.fractionl = arc4random();
p-query-xmttime = gettime_corrected();
 
-   if (ntp_sendmsg(p-query-fd, NULL, p-query-msg,
-   NTP_MSGSIZE_NOAUTH, 0) == -1) {
+   if (ntp_sendmsg(p-query-fd, NULL, p-query-msg) == -1) {
p-senderrors++;
set_next(p, INTERVAL_QUERY_PATHETIC);
p-trustlevel = TRUSTLEVEL_PATHETIC;
Index: ntp_msg.c
===
RCS file: /cvs/src/usr.sbin/ntpd/ntp_msg.c,v
retrieving revision 1.18
diff -u -p -r1.18 ntp_msg.c
--- ntp_msg.c   19 Oct 2007 15:53:57 -  1.18
+++ ntp_msg.c   27 Apr 2013 21:59:52 -
@@ -40,8 +40,7 @@ ntp_getmsg(struct sockaddr *sa, char *p,
 }
 
 int
-ntp_sendmsg(int fd, struct sockaddr *sa, struct ntp_msg *msg, ssize_t len,
-int auth)
+ntp_sendmsg(int fd, struct sockaddr *sa, struct ntp_msg *msg)
 {
socklen_t   sa_len;
ssize_t n;
Index: ntpd.h
===
RCS file: /cvs/src/usr.sbin/ntpd/ntpd.h,v
retrieving revision 1.106
diff -u -p -r1.106 ntpd.h
--- ntpd.h  20 Sep 2012 12:43:16 -  1.106
+++ ntpd.h  27 Apr 2013 21:59:52 -
@@ -226,7 +226,7 @@ struct ntp_conf_sensor  *new_sensor(char 
 
 /* ntp_msg.c */
 intntp_getmsg(struct sockaddr *, char *, ssize_t, struct ntp_msg *);
-intntp_sendmsg(int, struct sockaddr *, struct ntp_msg *, ssize_t, int);
+intntp_sendmsg(int, struct sockaddr *, struct ntp_msg *);
 
 /* server.c */
 intsetup_listeners(struct servent *, struct ntpd_conf *, u_int *);
Index: server.c
===
RCS file: /cvs/src/usr.sbin/ntpd/server.c,v
retrieving revision 1.36
diff -u -p -r1.36 server.c
--- server.c21 Sep 2011 15:41:30 -  1.36
+++ server.c27 Apr 2013 21:59:52 -
@@ -210,6 +210,6 @@ server_dispatch(int fd, struct ntpd_conf
reply.rootdelay = d_to_sfp(lconf-status.rootdelay);
reply.refid = lconf-status.refid;
 
-   ntp_sendmsg(fd, (struct sockaddr *)fsa, reply, size, 0);
+   ntp_sendmsg(fd, (struct sockaddr *)fsa, reply);
return (0);
 }



Re: [PATCH] tftpd: DoS vuln

2013-03-16 Thread Maxime Villard
Le 15/03/2013 12:17, David Gwynne a écrit :
 
 On 15/03/2013, at 9:02 AM, Maxime Villard rusty...@gmx.fr wrote:
 
 Hi,
 there is a huge bug in the tftp daemon.
 
 sure, but then there's also a huge bug in your fix by your own definition of 
 huge.
 when oack fails it frees the client struct and everything hanging off it. now 
 you avoid the unconditional free of of the client options straight after oack 
 is called by going to the error label if oack fails, which calls nak, which 
 then uses client and tries to free it again.
 


No. I removed the call to client_free() in oack():

 -  client_free(client);
 +  return -1;

There is no double-free in my patch. But I saw you committed
fixes, so ok now.


 nice find though. i'll put a fix in shortly which will look very much like 
 yours.
 
 dlg
 
 

 -- /usr/src/usr.sbin/tftpd/tftpd.c --
 In tftp_open() on line 870, the daemon checks for options
 (OACK) and handle them through the oack() function. Then,
 it frees and NULLs the variable client-options.

 oack() - l.1390 - does some stuff, and if an error happens,
 client_free() is called with the client structure, which
 frees this structure, including client-options, but does
 not null it.

 So, when returning after an error, client-options is freed
 twice, causing a double-free and a crash.

 I succeeded in making the server crash, by changing the
 tsize and blksize options before transferring a small file
 in localhost. In fact, if you look on line 1432, you'll see
 that you just have to close the socket to make the server
 crash, just after sending the OACK packet.

 Typically, I just have to do:
   $ tftp localhost
   tftp tsize 2
   Tsize option on.
   tftp blksize 10
   tftp get test
   [...wait ~ 10 sec...]
   tftpd in free(): error: chunk is already free 0x1a658ca65f40

 Here is a patch. I switched oack() to int, so that we can
 handle errors and call nak() to alert the client before
 closing the connection. nak() frees the client structure,
 so all goes well.

 Ok/Comments?


 Index: tftpd.c
 ===
 RCS file: /cvs/src/usr.sbin/tftpd/tftpd.c,v
 retrieving revision 1.8
 diff -u -r1.8 tftpd.c
 --- tftpd.c  13 Jul 2012 02:31:46 -  1.8
 +++ tftpd.c  15 Mar 2013 00:36:40 -
 @@ -168,7 +168,7 @@
 void tftp(struct tftp_client *, struct tftphdr *, size_t);
 void tftp_open(struct tftp_client *, const char *);
 void nak(struct tftp_client *, int);
 -voidoack(struct tftp_client *);
 +int oack(struct tftp_client *);
 void oack_done(int, short, void *);

 void sendfile(struct tftp_client *);
 @@ -876,8 +876,8 @@
  goto error;

  if (client-options) {
 -oack(client);
 -
 +if (oack(client) == -1)
 +goto error;
  free(client-options);
  client-options = NULL;
  } else if (client-opcode == WRQ) {
 @@ -1386,7 +1386,7 @@
 /*
   * Send an oack packet (option acknowledgement).
   */
 -void
 +int
 oack(struct tftp_client *client)
 {
  struct opt_client *options = client-options;
 @@ -1436,10 +1436,10 @@
  oack_done, client);

  event_add(client-sev, client-tv);
 -return;
 +return 0;

 error:
 -client_free(client);
 +return -1;
 }

 int

 
 
 



Re: [PATCH] tftpd: DoS vuln

2013-03-15 Thread Maxime Villard
What would that be used for? Look: client_free() frees
client-options, client-file AND client. So even if
you null client-options, client does no longer exist
as it has been freed. We should never use client after
calling client_free().


On 03/15/13 01:09, Ted Unangst wrote:
 After reading your description, I was expecting the patch to include a line 
 setting options to null after freeing it. Whatever else we do, shouldn't we 
 do that too?
 
 
 On Fri, Mar 15, 2013 at 00:02, Maxime Villard wrote:
 Hi,
 there is a huge bug in the tftp daemon.

 -- /usr/src/usr.sbin/tftpd/tftpd.c --
 In tftp_open() on line 870, the daemon checks for options
 (OACK) and handle them through the oack() function. Then,
 it frees and NULLs the variable client-options.

 oack() - l.1390 - does some stuff, and if an error happens,
 client_free() is called with the client structure, which
 frees this structure, including client-options, but does
 not null it.

 So, when returning after an error, client-options is freed
 twice, causing a double-free and a crash.

 I succeeded in making the server crash, by changing the
 tsize and blksize options before transferring a small file
 in localhost. In fact, if you look on line 1432, you'll see
 that you just have to close the socket to make the server
 crash, just after sending the OACK packet.

 Typically, I just have to do:
 $ tftp localhost
 tftp tsize 2
 Tsize option on.
 tftp blksize 10
 tftp get test
 [...wait ~ 10 sec...]
 tftpd in free(): error: chunk is already free 0x1a658ca65f40

 Here is a patch. I switched oack() to int, so that we can
 handle errors and call nak() to alert the client before
 closing the connection. nak() frees the client structure,
 so all goes well.

 Ok/Comments?


 Index: tftpd.c
 ===
 RCS file: /cvs/src/usr.sbin/tftpd/tftpd.c,v
 retrieving revision 1.8
 diff -u -r1.8 tftpd.c
 --- tftpd.c  13 Jul 2012 02:31:46 -  1.8
 +++ tftpd.c  15 Mar 2013 00:36:40 -
 @@ -168,7 +168,7 @@
 void tftp(struct tftp_client *, struct tftphdr *, size_t);
 void tftp_open(struct tftp_client *, const char *);
 void nak(struct tftp_client *, int);
 -voidoack(struct tftp_client *);
 +int oack(struct tftp_client *);
 void oack_done(int, short, void *);

 void sendfile(struct tftp_client *);
 @@ -876,8 +876,8 @@
 goto error;

 if (client-options) {
 -oack(client);
 -
 +if (oack(client) == -1)
 +goto error;
 free(client-options);
 client-options = NULL;
 } else if (client-opcode == WRQ) {
 @@ -1386,7 +1386,7 @@
 /*
 * Send an oack packet (option acknowledgement).
 */
 -void
 +int
 oack(struct tftp_client *client)
 {
 struct opt_client *options = client-options;
 @@ -1436,10 +1436,10 @@
 oack_done, client);

 event_add(client-sev, client-tv);
 -return;
 +return 0;

 error:
 -client_free(client);
 +return -1;
 }

 int
 
 



[PATCH] tftpd: DoS vuln

2013-03-14 Thread Maxime Villard
Hi,
there is a huge bug in the tftp daemon.

-- /usr/src/usr.sbin/tftpd/tftpd.c --
In tftp_open() on line 870, the daemon checks for options
(OACK) and handle them through the oack() function. Then,
it frees and NULLs the variable client-options.

oack() - l.1390 - does some stuff, and if an error happens,
client_free() is called with the client structure, which
frees this structure, including client-options, but does
not null it.

So, when returning after an error, client-options is freed
twice, causing a double-free and a crash.

I succeeded in making the server crash, by changing the
tsize and blksize options before transferring a small file
in localhost. In fact, if you look on line 1432, you'll see
that you just have to close the socket to make the server
crash, just after sending the OACK packet.

Typically, I just have to do:
  $ tftp localhost
  tftp tsize 2
  Tsize option on.
  tftp blksize 10
  tftp get test
  [...wait ~ 10 sec...]
  tftpd in free(): error: chunk is already free 0x1a658ca65f40

Here is a patch. I switched oack() to int, so that we can
handle errors and call nak() to alert the client before
closing the connection. nak() frees the client structure,
so all goes well.

Ok/Comments?


Index: tftpd.c
===
RCS file: /cvs/src/usr.sbin/tftpd/tftpd.c,v
retrieving revision 1.8
diff -u -r1.8 tftpd.c
--- tftpd.c 13 Jul 2012 02:31:46 -  1.8
+++ tftpd.c 15 Mar 2013 00:36:40 -
@@ -168,7 +168,7 @@
 void   tftp(struct tftp_client *, struct tftphdr *, size_t);
 void   tftp_open(struct tftp_client *, const char *);
 void   nak(struct tftp_client *, int);
-void   oack(struct tftp_client *);
+intoack(struct tftp_client *);
 void   oack_done(int, short, void *);
 
 void   sendfile(struct tftp_client *);
@@ -876,8 +876,8 @@
goto error;
 
if (client-options) {
-   oack(client);
-
+   if (oack(client) == -1)
+   goto error;
free(client-options);
client-options = NULL;
} else if (client-opcode == WRQ) {
@@ -1386,7 +1386,7 @@
 /*
  * Send an oack packet (option acknowledgement).
  */
-void
+int
 oack(struct tftp_client *client)
 {
struct opt_client *options = client-options;
@@ -1436,10 +1436,10 @@
oack_done, client);
 
event_add(client-sev, client-tv);
-   return;
+   return 0;
 
 error:
-   client_free(client);
+   return -1;
 }
 
 int



Re: vfs_syscall: doreadlinkat()

2013-01-25 Thread Maxime Villard
Le 24/01/2013 19:10, Matthew Dempsky a écrit :
 On Thu, Jan 24, 2013 at 9:57 AM, Maxime Villard rusty...@gmx.fr wrote:
 
  Hum here, if vp-v_type != VLNK, auio is untouched, but before returning
  we use auio.uio_resid, which is not initialized. Is it?
 
 Nice catch.  We should probably move the *retval assignment up just after
 the VOP_READLINK() call, since this can technically result in undefined
 behavior if you try to readlink on a non-symlink file.
 

Yes.

Index: vfs_syscalls.c
===
RCS file: /cvs/src/sys/kern/vfs_syscalls.c,v
retrieving revision 1.189
diff -u -r1.189 vfs_syscalls.c
--- vfs_syscalls.c  10 Sep 2012 11:10:59 -  1.189
+++ vfs_syscalls.c  25 Jan 2013 15:30:30 -
@@ -1843,9 +1843,9 @@
auio.uio_procp = p;
auio.uio_resid = count;
error = VOP_READLINK(vp, auio, p-p_ucred);
+   *retval = count - auio.uio_resid;
}
vput(vp);
-   *retval = count - auio.uio_resid;
return (error);
 }
 

 I don't think it should leak any information moment though, since the
 EINVAL errno will take precedence instead of *retval when we return to
 userspace.
 
 



vfs_syscall: doreadlinkat()

2013-01-24 Thread Maxime Villard
Hi,
I was looking at readlink syscall. There is the following function in
kern/vfs_syscalls.c:

int
doreadlinkat(struct proc *p, int fd, const char *path, char *buf,
size_t count, register_t *retval)
{
struct vnode *vp;
struct iovec aiov;
struct uio auio;
int error;
struct nameidata nd;

NDINITAT(nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, fd, path, p);
if ((error = namei(nd)) != 0)
return (error);
vp = nd.ni_vp;
if (vp-v_type != VLNK)
error = EINVAL;
else {
aiov.iov_base = buf;
aiov.iov_len = count;
auio.uio_iov = aiov;
auio.uio_iovcnt = 1;
auio.uio_offset = 0;
auio.uio_rw = UIO_READ;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_procp = p;
auio.uio_resid = count;
error = VOP_READLINK(vp, auio, p-p_ucred);
}
vput(vp);
*retval = count - auio.uio_resid;
return (error);
}

Hum here, if vp-v_type != VLNK, auio is untouched, but before returning
we use auio.uio_resid, which is not initialized. Is it?



[PATCH] pfctl: leak stuff

2012-12-21 Thread Maxime Villard
Hi,
here are my small changes for pfctl.

1) There are cases where we could leak a file descriptor by
   returning.

2) We don't need to check memory before freeing it, as
   free() already does that.

3) Just replaced a snprintf() by strlcpy(), it's faster.

Ok/Comments ?



Index: pfctl.c
===
RCS file: /cvs/src/sbin/pfctl/pfctl.c,v
retrieving revision 1.314
diff -u -r1.314 pfctl.c
--- pfctl.c 19 Sep 2012 15:52:17 -  1.314
+++ pfctl.c 22 Dec 2012 07:08:28 -
@@ -1377,8 +1377,7 @@
err(1, DIOCXROLLBACK);
exit(1);
} else {/* sub ruleset */
-   if (path)
-   free(path);
+   free(path);
return (-1);
}
 
@@ -1867,10 +1866,6 @@
unsigned int len = 0;
size_t n;
 
-   f = fopen(file, w);
-   if (f == NULL)
-   err(1, open: %s, file);
-
memset(ps, 0, sizeof(ps));
for (;;) {
ps.ps_len = len;
@@ -1893,6 +1888,10 @@
return; /* no states */
len *= 2;
}
+
+   f = fopen(file, w);
+   if (f == NULL)
+   err(1, open: %s, file);
 
n = ps.ps_len / sizeof(struct pfsync_state);
if (fwrite(inbuf, sizeof(struct pfsync_state), n, f)  n)
Index: pfctl_osfp.c
===
RCS file: /cvs/src/sbin/pfctl/pfctl_osfp.c,v
retrieving revision 1.18
diff -u -r1.18 pfctl_osfp.c
--- pfctl_osfp.c18 Oct 2010 15:55:28 -  1.18
+++ pfctl_osfp.c22 Dec 2012 07:08:28 -
@@ -112,16 +112,11 @@
 
while ((line = fgetln(in, len)) != NULL) {
lineno++;
-   if (class)
-   free(class);
-   if (version)
-   free(version);
-   if (subtype)
-   free(subtype);
-   if (desc)
-   free(desc);
-   if (tcpopts)
-   free(tcpopts);
+   free(class);
+   free(version);
+   free(subtype);
+   free(desc);
+   free(tcpopts);
class = version = subtype = desc = tcpopts = NULL;
memset(fp, 0, sizeof(fp));
 
@@ -250,16 +245,11 @@
add_fingerprint(dev, opts, fp);
}
 
-   if (class)
-   free(class);
-   if (version)
-   free(version);
-   if (subtype)
-   free(subtype);
-   if (desc)
-   free(desc);
-   if (tcpopts)
-   free(tcpopts);
+   free(class);
+   free(version);
+   free(subtype);
+   free(desc);
+   free(tcpopts);
 
fclose(in);
 
@@ -513,7 +503,7 @@
return (buf);
 
 found:
-   snprintf(buf, len, %s, class_name);
+   strlcpy(buf, class_name, len);
if (version_name) {
strlcat(buf,  , len);
strlcat(buf, version_name, len);
Index: pfctl_radix.c
===
RCS file: /cvs/src/sbin/pfctl/pfctl_radix.c,v
retrieving revision 1.29
diff -u -r1.29 pfctl_radix.c
--- pfctl_radix.c   27 Jul 2011 00:26:10 -  1.29
+++ pfctl_radix.c   22 Dec 2012 07:08:28 -
@@ -499,8 +499,7 @@
 {
if (b == NULL)
return;
-   if (b-pfrb_caddr != NULL)
-   free(b-pfrb_caddr);
+   free(b-pfrb_caddr);
b-pfrb_caddr = NULL;
b-pfrb_size = b-pfrb_msize = 0;
 }



Re: [PATCH] OpenSSH: auth.c

2012-12-14 Thread Maxime Villard
Le 14/12/2012 06:27, Darren Tucker a écrit :
 On Thu, Dec 13, 2012 at 07:31:46PM +0100, Maxime Villard wrote:
  Hi,
  I was looking at some openssh code when I spotted a mistake
 applied, thanks.

Another trivial patch. Make a more detailed error message.
Or, we should use strlcpy().

Ok ?


--- auth.c  2012-12-14 15:54:15.0 +0100
+++ auth.c  2012-12-14 16:22:01.897130976 +0100
@@ -367,7 +367,8 @@
/* for each component of the canonical path, walking upwards */
for (;;) {
if ((cp = dirname(buf)) == NULL) {
-   snprintf(err, errlen, dirname() failed);
+   snprintf(err, errlen, dirname %s failed: %s, buf,
+   strerror(errno));
return -1;
}
strlcpy(buf, cp, sizeof(buf));



[PATCH] OpenSSH: auth.c

2012-12-13 Thread Maxime Villard
Hi,
I was looking at some openssh code when I spotted a mistake
in a function from auth.c:


static int
secure_filename(FILE *f, const char *file, struct passwd *pw,
char *err, size_t errlen)
{
char buf[MAXPATHLEN];
struct stat st;

/* check the open file to avoid races */
if (fstat(fileno(f), st)  0) {
snprintf(err, errlen, cannot stat file %s: %s,
buf, strerror(errno));
return -1;
}
return auth_secure_path(file, st, pw-pw_dir, pw-pw_uid, err, errlen);
}


'buf' is not initialized and used whereas it should be 'file'.
Patch:


--- auth.c  2012-12-08 12:51:32.0 +0100
+++ auth.c  2012-12-13 19:11:30.968193729 +0100
@@ -404,13 +404,12 @@
 secure_filename(FILE *f, const char *file, struct passwd *pw,
 char *err, size_t errlen)
 {
-   char buf[MAXPATHLEN];
struct stat st;
 
/* check the open file to avoid races */
if (fstat(fileno(f), st)  0) {
snprintf(err, errlen, cannot stat file %s: %s,
-   buf, strerror(errno));
+   file, strerror(errno));
return -1;
}
return auth_secure_path(file, st, pw-pw_dir, pw-pw_uid, err, errlen);



Sendbug getenv

2012-12-07 Thread Maxime Villard
Hi,
== src/usr.bin/sendbug/sendbug.c ==
Tell me if I'm wrong, but in the main() function, we call
getenv() two times (l. 113  134) without holding the result
of the first call.

According to man getenv:
 The string pointed to may be overwritten by a subsequent
  call to getenv()

After the second call, main() could launch hwdump() which
uses the return value of the first call, which could have been
overwritten by the second one.

We should hold the return value in a char instead of a pointer,
with something like:


--- sendbug.c   2012-07-21 21:55:17.0 +0200
+++ sendbug.c   2012-12-07 19:04:04.770853812 +0100
@@ -83,7 +83,7 @@
 {
int ch, c, fd, ret = 1;
struct stat sb;
-   char *pr_form;
+   char *pr_form, *tmp;
time_t mtime;
FILE *fp;
 
@@ -110,7 +110,8 @@
if (argc  0)
usage();
 
-   if ((tmpdir = getenv(TMPDIR)) == NULL || tmpdir[0] == '\0')
+   if ((tmp = getenv(TMPDIR)) == NULL || tmp[0] == '\0' ||
+   (tmpdir = strdup(tmp)) == NULL)
tmpdir = _PATH_TMP;
 
if (Pflag) {



Shouldn't we ?