mailing list of musl libc
 help / color / mirror / code / Atom feed
From: finkler <finkler@officinamentis.org>
To: musl@lists.openwall.com
Subject: Re: utmpx support
Date: Fri, 16 Mar 2012 15:05:18 +0100	[thread overview]
Message-ID: <jjvhb4$tgv$1@dough.gmane.org> (raw)
In-Reply-To: <20120306013028.GY184@brightrain.aerifal.cx>

[-- Attachment #1: Type: text/plain, Size: 2094 bytes --]

On 06.03.2012 02:30, Rich Felker wrote:
> On Sun, Mar 04, 2012 at 08:10:36PM +0100, finkler wrote:
> Append mode is definitely not correct if you want to be able to
> overwrite existing entries.
Changed it to r+ and r

> I'm confused about the intent of this code.. Presumably it's supposed
> to modify the entry it just found (relying on getutxid leaving the
> file at the right position), but that's not going to work because the
> file is opened in append mode.
>
> Also, -(sizeof ut) is not a valid offset; it's almost SIZE_MAX. If you
> were using fseeko, this would result in a gigantic offset (rather than
> a negative one) after the conversion; with fseek (which takes a long),
> it should convert back to the desired negative value, but for safety
> you should cast to a signed type *before* negating the result of
> sizeof
Made the cast inside the function call.

> There's also the issue that there's absolutely no locking on updates,
> so if multiple apps try to add/update utmp entries at the same time,
> the file would be corrupted. This could be fixed by using an fcntl
> lock on fileno(f) for the duration of the function.
I added a lock, however, I am unsure whether I should use a lock that 
waits until it is free or not, and whether I should lock the whole file, 
or just the portion which is about to be written.
Right now I use a waiting lock, and lock the whole file.

 > Here strcmp is being called on data that was read from a file with no
 > validation. This is potentially a security issue (DoS); if the file
 > does not contain a null-terminated string, strcmp could run past the
 > end of the buffer and eventually segfault and crash the calling
 > program. It's probably hard to trigger the issue since the string for
 > comparison is also located in a utmp structure, but I think there
 > should be some validation, probably just fixing invalid data right
 > after the fread call so it never leaks out.
I changed it to use strncmp with the sizeof the respective struct field, 
is this enough?

Thank you very much for your time, I attached the reworked version.

[-- Attachment #2: utmpx.c --]
[-- Type: text/plain, Size: 2052 bytes --]

#include <utmpx.h>
#include <stddef.h>
#include "libc.h"

#define _PATH_UTMPX "/etc/utmp"

static FILE *f;
static struct utmpx ut;

void endutxent(void)
{
  if (f == NULL) return;
  fclose(f);
  f == NULL;
}

void setutxent(void)
{
  if (f == NULL) return;
  rewind(f);
}

struct utmpx *getutxent(void)
{
  if (f == NULL) {
    f = fopen(_PATH_UTMPX, "r+");
    if (f == NULL) {
      f = fopen(_PATH_UTMPX, "r");
      if (f == NULL) return NULL;
    }
  }
  if (fread(&ut, sizeof ut, 1, f)) return &ut;
  return NULL;
}

struct utmpx *getutxid(const struct utmpx *id)
{  
  while(getutxent()) {
    switch (id->ut_type) {
      case BOOT_TIME:
      case OLD_TIME:
      case NEW_TIME:
        if (id->ut_type == ut.ut_type) return &ut;
        break;
      case INIT_PROCESS:
      case LOGIN_PROCESS:
      case USER_PROCESS:
      case DEAD_PROCESS:
        if (id->type == ut.ut_type && !strncmp(id->ut_id, ut.ut_id, sizeof ut.ut_id)) return &ut;
        break;
    }
  }    
  return NULL;
}

struct utmpx *getutxline(const struct utmpx *line)
{
	while(getutxent()) {
    switch (ut.ut_type) {
      case LOGIN_PROCESS:
      case USER_PROCESS:
        if (!strncmp(line->ut_line, ut.ut_line, sizeof ut.ut_line)) return &ut;
        break;
    }
  }
  return NULL;
}

struct utmpx *pututxline(const struct utmpx *utmpx)
{
  struct flock fl;
  size_t n;
  
  fl.l_start = 0;
  fl.l_len = 0;
  fl.l_pid = getpid();
  fl.l_type = F_WRLCK;
  fl.l_whence = SEEK_SET;
  
  if (fcntl(fileno(f), F_SETLKW, &fl) < 0) return NULL;
  
  setutxent();
  
  if (getutxid(utmpx)) fseek(f, -((long)(sizeof ut)), SEEK_CUR);
  
  n = fwrite(&ut, sizeof ut, 1, f);
  
  fl.l_type = F_UNLCK;
  fcntl(fileno(f), F_SETLK, &fl);
  
  if (n == 1)
    return &ut;
  return NULL;
}

void updwtmpx(const char *f, const struct utmpx *u)
{
}

weak_alias(endutxent, endutent);
weak_alias(setutxent, setutent);
weak_alias(getutxent, getutent);
weak_alias(getutxid, getutid);
weak_alias(getutxline, getutline);
weak_alias(pututxline, pututline);
weak_alias(updwtmpx, updwtmp);

  reply	other threads:[~2012-03-16 14:05 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-04 17:41 finkler
2012-03-04 18:18 ` Rich Felker
2012-03-04 19:10   ` finkler
2012-03-06  1:30     ` Rich Felker
2012-03-16 14:05       ` finkler [this message]
2012-03-06  1:39     ` Rich Felker

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='jjvhb4$tgv$1@dough.gmane.org' \
    --to=finkler@officinamentis.org \
    --cc=musl@lists.openwall.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).