Ticket #5776: 0001-Hide-WPA-key-from-the-nas-process-command-line.patch

File 0001-Hide-WPA-key-from-the-nas-process-command-line.patch, 10.4 KB (added by jpap00, 3 months ago)

Patch to hide command-line arguments of the nas daemon that otherwise leaks WPA secret keys.

  • src/router/libutils/Makefile

    From 84204cbddeadfd004e43b3fe49233b646679d5db Mon Sep 17 00:00:00 2001
    From: <jpap00>
    Date: Sat, 18 Mar 2017 01:06:35 -0700
    Subject: [PATCH] Hide WPA key from the `nas` process command line
    
    ---
     src/router/libutils/Makefile          |  6 ++-
     src/router/libutils/interpose.c       | 81 +++++++++++++++++++++++++++++++++++
     src/router/libutils/shutils.c         | 65 +++++++++++++++++++++++++++-
     src/router/services/services/wpa.c    | 14 +++---
     src/router/services/sysinit/devinit.c |  2 +-
     src/router/shared/shutils.h           |  8 ++++
     6 files changed, 165 insertions(+), 11 deletions(-)
     create mode 100644 src/router/libutils/interpose.c
    
    diff --git a/src/router/libutils/Makefile b/src/router/libutils/Makefile
    index 594916f..da671f0 100644
    a b CFLAGS += -DHAVE_MATRIXSSL 
    14001400endif
    14011401HFLAGS := $(CFLAGS)
    14021402CFLAGS += $(COPTS)
    1403 all: libutils.so libutils.a libwireless.so libwireless.a
     1403all: libutils.so libutils.a libwireless.so libwireless.a interpose.so
    14041404
    14051405install: all
    14061406ifeq ($(CONFIG_XSCALE),y)
    else 
    14121412        install -m 755 libutils.so $(INSTALLDIR)/libutils/usr/lib
    14131413        install -m 755 libwireless.so $(INSTALLDIR)/libutils/usr/lib
    14141414endif
     1415        install -m 755 interpose.so $(INSTALLDIR)/libutils/usr/lib
    14151416
    14161417clean:
    14171418#       rm -f countrycode/countrycode_$(ARCH).o
    clean: 
    14231424
    14241425
    14251426
     1427interpose.so: interpose.c
     1428        $(CC) -fPIC -shared $(CFLAGS) $(LDFLAGS) -o $@ $^ -ldl
     1429
    14261430libutils.so: $(OBJS)
    14271431        $(CC) -shared $(CFLAGS) $(LDFLAGS) -o $@ $^  -lcrypt -L../nvram -lnvram $(QTNFLAGS)
    14281432
  • new file src/router/libutils/interpose.c

    diff --git a/src/router/libutils/interpose.c b/src/router/libutils/interpose.c
    new file mode 100644
    index 0000000..37fe6e8
    - +  
     1/*
     2 * interpose.c
     3 *
     4 * Copyright (C) 2017 <jpap00>
     5 *
     6 * This program is free software; you can redistribute it and/or
     7 * modify it under the terms of the GNU General Public License
     8 * as published by the Free Software Foundation; either version 2
     9 * of the License, or (at your option) any later version.
     10 *
     11 * This program is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 * GNU General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU General Public License
     17 * along with this program; if not, write to the Free Software
     18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     19 *
     20 * $Id:
     21 */
     22
     23#define _GNU_SOURCE
     24#include <dlfcn.h>
     25#include <unistd.h>
     26#include <stdio.h>
     27#include <stdlib.h>
     28#include <string.h>
     29
     30#define die(__str) do { perror(__str); exit(1); } while (0)
     31
     32static int (*__old_main) (int, char **, char **);
     33
     34static int __new_main(int argc, char ** argv, char ** env) {
     35  int iargc;
     36  char **iargv = NULL; // Lifetime is until end of process
     37
     38  // Get number of arguments from stdin
     39  if (read(STDIN_FILENO, &iargc, sizeof(int)) != sizeof(int)) die("read");
     40  iargv = calloc(sizeof(char *), iargc + 1);
     41  if (!iargv) die("calloc");
     42
     43  // Get each argument from stdin
     44  for (int index = 0; index < iargc; ++index) {
     45    int len;
     46
     47    if (read(STDIN_FILENO, &len, sizeof(int)) != sizeof(int)) die("read");
     48    iargv[index] = malloc(len + 1);
     49    iargv[index][len] = '\0';
     50    if (read(STDIN_FILENO, iargv[index], len) != len) die("read");
     51  }
     52
     53  // Call the real main() entrypoint with our interposed arguments
     54  return __old_main(iargc, iargv, env);
     55}
     56
     57int __libc_start_main(
     58  int (*main) (int, char **, char **),
     59  int argc, char ** ubp_av,
     60  void (*init) (void),
     61  void (*fini) (void),
     62  void (*rtld_fini) (void),
     63  void (* stack_end)
     64)
     65{
     66  int (*next)(
     67    int (*main) (int, char **, char **),
     68    int argc, char ** ubp_av,
     69    void (*init) (void),
     70    void (*fini) (void),
     71    void (*rtld_fini) (void),
     72    void (* stack_end)
     73  ) = dlsym(RTLD_NEXT, "__libc_start_main");
     74
     75  // Hang onto the real main
     76  __old_main = main;
     77
     78  // But start the process with our interposed main
     79  return next(__new_main, argc, ubp_av, init, fini, rtld_fini, stack_end);
     80}
     81
  • src/router/libutils/shutils.c

    diff --git a/src/router/libutils/shutils.c b/src/router/libutils/shutils.c
    index 0ab0145..1b8dc1c 100644
    a b int eval_va_silence(const char *cmd, ...) 
    186186}
    187187
    188188// FILE *debugfp=NULL;
    189 int _evalpid(char *const argv[], char *path, int timeout, int *ppid)
     189int _evalpid_internal(char *const argv[], char *path, int timeout, int *ppid, int redact)
    190190{
    191191        pid_t pid;
    192192        int status;
    193193        int fd;
    194194        int flags;
    195195        int sig;
     196        int pfd[2];
     197
     198        if (redact) {
     199                // We'll use a pipe to communicate the command line without exposing to other processes.
     200                // To do this, we will use an interpose library that intercepts the executed command and
     201                // reads the command line from the pipe before resuming regular execution.
     202                if (pipe(pfd) < 0) {
     203                        perror("fork");
     204                        return errno;
     205                }
     206        }
    196207
    197208        // if (debugfp==NULL)
    198209        // debugfp = fopen("/tmp/evallog.log","wb");
    int _evalpid(char *const argv[], char *path, int timeout, int *ppid) 
    223234        switch (pid = fork()) {
    224235        case -1:                /* error */
    225236                perror("fork");
     237                if (redact) {
     238                        close(pfd[0]);
     239                        close(pfd[1]);
     240                }
    226241                return errno;
    227242        case 0:         /* child */
    228243                /*
    int _evalpid(char *const argv[], char *path, int timeout, int *ppid) 
    290305                // cprintf("cmd=[%s]\n", buf);
    291306                setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin", 1);
    292307                alarm(timeout);
    293                 execvp(argv[0], argv);
     308
     309                if (redact) {
     310                        // Duplicate the input side of the pipe to stdin
     311                        dup2(pfd[0], 0);
     312
     313                        // We don't need the pipe anymore
     314                        close(pfd[0]);
     315                        close(pfd[1]);
     316
     317                        // Execute with our interpose library to redact arguments
     318                        char * const iargv[] = {argv[0], "<redacted>", NULL};
     319                        char * const ienvv[] = {"LD_PRELOAD=/usr/lib/interpose.so", NULL};
     320                        execvpe(iargv[0], iargv, ienvv);
     321                }
     322                else {
     323                        execvp(argv[0], argv);
     324                }
    294325                perror(argv[0]);
    295326                exit(errno);
    296327        default:                /* parent */
     328                if (redact) {
     329                        int argc = 0;
     330
     331                        // Count the number of arguments
     332                        while (argv[++argc]);
     333
     334                        // Parent does not receive from the child
     335                        close(pfd[0]);
     336
     337                        // Write argument list to the pipe connected to the child:
     338                        // Do this as an argument count, followed by Pascal strings.
     339                        write(pfd[1], (const void *)&argc, sizeof(int));
     340                        for (int index = 0; index < argc; ++index) {
     341                                const int len = strlen(argv[index]);
     342                                write(pfd[1], (const void *)&len, sizeof(int));
     343                                write(pfd[1], (const void *)argv[index], len);
     344                        }
     345                        close(pfd[1]);
     346                }
     347
    297348                if (ppid) {
    298349                        *ppid = pid;
    299350                        return 0;
    int _evalpid(char *const argv[], char *path, int timeout, int *ppid) 
    307358        }
    308359}
    309360
     361int _evalpid_redact(char *const argv[], char *path, int timeout, int *ppid)
     362{
     363        return _evalpid_internal(argv, path, timeout, ppid, 1);
     364}
     365
     366int _evalpid(char *const argv[], char *path, int timeout, int *ppid)
     367{
     368        return _evalpid_internal(argv, path, timeout, ppid, 0);
     369}
     370
    310371int _eval(char *const argv[])
    311372{
    312373        return _evalpid(argv, ">/dev/console", 0, NULL);
  • src/router/services/services/wpa.c

    diff --git a/src/router/services/services/wpa.c b/src/router/services/services/wpa.c
    index 20efceb..7d4eb3b 100644
    a b void start_nas_single(char *type, char *prefix) 
    529529                                "nas", "-P", pidfile, "-H", "34954", "-i", iface, mode, "-m", auth_mode, "-k", key, "-s", nvram_safe_get(ssid), "-w", sec_mode, "-g", nvram_default_get(rekey, "3600"), NULL};
    530530
    531531                        }
    532                         _evalpid(argv, NULL, 0, &pid);
     532                        _evalpid_redact(argv, NULL, 0, &pid);
    533533
    534534                } else {
    535535                        if (!strcmp(auth_mode, "2")
    void start_nas_single(char *type, char *prefix) 
    553553                                                // time
    554554                                                NULL
    555555                                        };
    556                                         _evalpid(argv, NULL, 0, &pid);
     556                                        _evalpid_redact(argv, NULL, 0, &pid);
    557557                                } else {
    558558                                        char *argv[] = { "nas", "-P", pidfile,
    559559                                                "-H", "34954", "-l",
    void start_nas_single(char *type, char *prefix) 
    571571                                                // time
    572572                                                NULL
    573573                                        };
    574                                         _evalpid(argv, NULL, 0, &pid);
     574                                        _evalpid_redact(argv, NULL, 0, &pid);
    575575                                }
    576576
    577577                        } else if (!strcmp(auth_mode, "32")) {
    void start_nas_single(char *type, char *prefix) 
    599599                                                // time
    600600                                                NULL
    601601                                        };
    602                                         _evalpid(argv, NULL, 0, &pid);
     602                                        _evalpid_redact(argv, NULL, 0, &pid);
    603603                                } else {
    604604                                        char *argv[] = { "nas", "-P", pidfile,
    605605                                                "-H", "34954", "-l",
    void start_nas_single(char *type, char *prefix) 
    620620                                                NULL
    621621                                        };
    622622
    623                                         _evalpid(argv, NULL, 0, &pid);
     623                                        _evalpid_redact(argv, NULL, 0, &pid);
    624624
    625625                                }
    626626
    void start_nas_single(char *type, char *prefix) 
    638638                                                nvram_default_get(rekey, "3600"),
    639639                                                NULL
    640640                                        };
    641                                         _evalpid(argv, NULL, 0, &pid);
     641                                        _evalpid_redact(argv, NULL, 0, &pid);
    642642                                } else {
    643643                                        char *argv[] = { "nas", "-P", pidfile,
    644644                                                "-H", "34954", "-l",
    void start_nas_single(char *type, char *prefix) 
    652652                                                nvram_default_get(rekey, "3600"),
    653653                                                NULL
    654654                                        };
    655                                         _evalpid(argv, NULL, 0, &pid);
     655                                        _evalpid_redact(argv, NULL, 0, &pid);
    656656                                }
    657657
    658658                        }
  • src/router/services/sysinit/devinit.c

    diff --git a/src/router/services/sysinit/devinit.c b/src/router/services/sysinit/devinit.c
    index 5d853fd..b0de579 100644
    a b void start_devinit(void) 
    127127        mknod("/dev/ppp", S_IFCHR | 0644, makedev(108, 0));
    128128#endif
    129129// fix me udevtrigger does not create that (yet) not registered?
    130         mknod("/dev/nvram", S_IFCHR | 0644, makedev(229, 0));
     130        mknod("/dev/nvram", S_IFCHR | 0600, makedev(229, 0));
    131131        mknod("/dev/watchdog", S_IFCHR | 0644, makedev(10, 130));
    132132
    133133        mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL, NULL);
  • src/router/shared/shutils.h

    diff --git a/src/router/shared/shutils.h b/src/router/shared/shutils.h
    index d3a35dd..12c3f02 100644
    a b extern int waitfor(int fd, int timeout); 
    5353
    5454int _evalpid(char *const argv[], char *path, int timeout, int *ppid);
    5555
     56/*
     57 * Similar to _evalpid(...), executes the given command except that the command
     58 * line is passed to it via a pipe, so any sensitive arguments (e.g. keys) are
     59 * redacted and kept hidden from other processes.
     60 */
     61
     62int _evalpid_redact(char *const argv[], char *path, int timeout, int *ppid);
     63
    5664//extern int _eval(char *const argv[]);
    5765extern int eval_va(const char *cmd, ...);
    5866extern int eval_va_silence(const char *cmd, ...);