On Tue, Jun 27, 2017 at 11:40:49PM +0100, Nicholas Marriott wrote:
> Thanks. Comments inline.
>
> > [..]
>
> One member per line in structs please. Also you could reduce the amount
> of space here now to one tab.
>
> > [..]
>
> magic_load (which parses the magic file) is now before pledge and
> privdrop which is wrong. You need to drop privs and pledge before
> magic_load - if needed you can reduce the pledge further after
> magic_load, but I think it only needs stdio anyway.
>
> > [..]
>
> The privdrop was easier to see inline than in a separate function. I
> think it should all be up front in main() not hidden away.
>
> > [..]
>
> This fclose() is pointless here but it can be done much earlier (after
> magic_load).
>
> And you need to exit(0) rather than dropping out of the bottom of main.
>
> > [..]
>
> This comment needs to be edited now we are not passing the file
> descriptors anywhere.
>
> > [..]
>
> I'd assign this in the loop which calls test_file? Everything else in
> input_file is set up outside this function.
>
Here's another stab at it with your suggestions, seems to work. Thanks!
Index: Makefile
===================================================================
RCS file: /cvs/src/usr.bin/file/Makefile,v
retrieving revision 1.16
diff -u -p -u -r1.16 Makefile
--- Makefile 4 Oct 2015 07:25:59 -0000 1.16
+++ Makefile 27 Jun 2017 23:19:35 -0000
@@ -5,9 +5,6 @@ SRCS= file.c magic-dump.c magic-load.c
text.c xmalloc.c
MAN= file.1 magic.5
-LDADD= -lutil
-DPADD= ${LIBUTIL}
-
CDIAGFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2
CDIAGFLAGS+= -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
CDIAGFLAGS+= -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
Index: file.c
===================================================================
RCS file: /cvs/src/usr.bin/file/file.c,v
retrieving revision 1.59
diff -u -p -u -r1.59 file.c
--- file.c 18 Apr 2017 14:16:48 -0000 1.59
+++ file.c 27 Jun 2017 23:19:35 -0000
@@ -29,12 +29,10 @@
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
-#include <imsg.h>
#include <libgen.h>
#include <limits.h>
#include <pwd.h>
#include <stdlib.h>
-#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
@@ -43,45 +41,31 @@
#include "magic.h"
#include "xmalloc.h"
-struct input_msg {
- int idx;
-
- struct stat sb;
- int error;
-
- char link_path[PATH_MAX];
- int link_error;
- int link_target;
-};
-
-struct input_ack {
- int idx;
-};
-
struct input_file {
- struct magic *m;
- struct input_msg *msg;
+ struct magic *m;
- const char *path;
- int fd;
+ const char *path;
+ struct stat sb;
+ int fd;
+ int error;
- void *base;
- size_t size;
- int mapped;
- char *result;
+ char link_path[PATH_MAX];
+ int link_error;
+ int link_target;
+
+ void *base;
+ size_t size;
+ int mapped;
+ char *result;
};
extern char *__progname;
__dead void usage(void);
-static int prepare_message(struct input_msg *, int, const char *);
-static void send_message(struct imsgbuf *, void *, size_t, int);
-static int read_message(struct imsgbuf *, struct imsg *, pid_t);
-
-static void read_link(struct input_msg *, const char *);
+static void prepare_input(struct input_file *, const char *);
-static __dead void child(int, pid_t, int, char **);
+static void read_link(struct input_file *, const char *);
static void test_file(struct input_file *, size_t);
@@ -120,14 +104,12 @@ usage(void)
int
main(int argc, char **argv)
{
- int opt, pair[2], fd, idx;
+ int opt, idx;
char *home;
struct passwd *pw;
- struct imsgbuf ibuf;
- struct imsg imsg;
- struct input_msg msg;
- struct input_ack *ack;
- pid_t pid, parent;
+ struct magic *m;
+ struct input_file *inf;
+ size_t len, width = 0;
tzset();
@@ -193,79 +175,75 @@ main(int argc, char **argv)
if (magicfp == NULL)
err(1, "%s", magicpath);
- parent = getpid();
- if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
- err(1, "socketpair");
- switch (pid = fork()) {
- case -1:
- err(1, "fork");
- case 0:
- close(pair[0]);
- child(pair[1], parent, argc, argv);
+ if (!cflag) {
+ inf = xcalloc(argc, sizeof *inf);
+ for (idx = 0; idx < argc; idx++) {
+ len = strlen(argv[idx]) + 1;
+ if (len > width)
+ width = len;
+ prepare_input(&inf[idx], argv[idx]);
+ }
}
- close(pair[1]);
- fclose(magicfp);
- magicfp = NULL;
+ if (pledge("stdio getpw id", NULL) == -1)
+ err(1, "pledge");
- if (cflag)
- goto wait_for_child;
+ if (geteuid() == 0) {
+ pw = getpwnam(FILE_USER);
+ if (pw == NULL)
+ errx(1, "unknown user %s", FILE_USER);
+ if (setgroups(1, &pw->pw_gid) != 0)
+ err(1, "setgroups");
+ if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0)
+ err(1, "setresgid");
+ if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0)
+ err(1, "setresuid");
+ }
- imsg_init(&ibuf, pair[0]);
- for (idx = 0; idx < argc; idx++) {
- fd = prepare_message(&msg, idx, argv[idx]);
- send_message(&ibuf, &msg, sizeof msg, fd);
+ if (pledge("stdio", NULL) == -1)
+ err(1, "pledge");
- if (read_message(&ibuf, &imsg, pid) == 0)
- break;
- if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof *ack)
- errx(1, "message too small");
- ack = imsg.data;
- if (ack->idx != idx)
- errx(1, "index not expected");
- imsg_free(&imsg);
+ m = magic_load(magicfp, magicpath, cflag || Wflag);
+ if (cflag) {
+ magic_dump(m);
+ exit(0);
}
+ fclose(magicfp);
+ magicfp = NULL;
-wait_for_child:
- close(pair[0]);
- while (wait(NULL) == -1 && errno != ECHILD) {
- if (errno != EINTR)
- err(1, "wait");
+ for (idx = 0; idx < argc; idx++) {
+ inf[idx].m = m;
+ test_file(&inf[idx], width);
}
- _exit(0); /* let the child flush */
+ exit(0);
}
-static int
-prepare_message(struct input_msg *msg, int idx, const char *path)
+static void
+prepare_input(struct input_file *inf, const char *path)
{
int fd, mode, error;
- memset(msg, 0, sizeof *msg);
- msg->idx = idx;
-
if (strcmp(path, "-") == 0) {
- if (fstat(STDIN_FILENO, &msg->sb) == -1) {
- msg->error = errno;
- return (-1);
+ if (fstat(STDIN_FILENO, &inf->sb) == -1) {
+ inf->error = errno;
+ inf->fd = -1;
}
- return (STDIN_FILENO);
+ inf->fd = STDIN_FILENO;
}
if (Lflag)
- error = stat(path, &msg->sb);
+ error = stat(path, &inf->sb);
else
- error = lstat(path, &msg->sb);
+ error = lstat(path, &inf->sb);
if (error == -1) {
- msg->error = errno;
- return (-1);
+ inf->error = errno;
+ inf->fd = -1;
}
/*
- * pledge(2) doesn't let us pass directory file descriptors around -
- * but in fact we don't need them, so just don't open directories or
- * symlinks (which could be to directories).
+ * Don't open directories or symlinks (which could be to directories).
*/
- mode = msg->sb.st_mode;
+ mode = inf->sb.st_mode;
if (!S_ISDIR(mode) && !S_ISLNK(mode)) {
fd = open(path, O_RDONLY|O_NONBLOCK);
if (fd == -1 && (errno == ENFILE || errno == EMFILE))
@@ -273,46 +251,13 @@ prepare_message(struct input_msg *msg, i
} else
fd = -1;
if (S_ISLNK(mode))
- read_link(msg, path);
- return (fd);
-
-}
-
-static void
-send_message(struct imsgbuf *ibuf, void *msg, size_t msglen, int fd)
-{
- if (imsg_compose(ibuf, -1, -1, 0, fd, msg, msglen) != 1)
- err(1, "imsg_compose");
- if (imsg_flush(ibuf) != 0)
- err(1, "imsg_flush");
-}
-
-static int
-read_message(struct imsgbuf *ibuf, struct imsg *imsg, pid_t from)
-{
- int n;
-
- while ((n = imsg_read(ibuf)) == -1 && errno == EAGAIN)
- /* nothing */ ;
- if (n == -1)
- err(1, "imsg_read");
- if (n == 0)
- return (0);
-
- if ((n = imsg_get(ibuf, imsg)) == -1)
- err(1, "imsg_get");
- if (n == 0)
- return (0);
-
- if ((pid_t)imsg->hdr.pid != from)
- errx(1, "PIDs don't match");
-
- return (n);
-
+ read_link(inf, path);
+ inf->fd = fd;
+ inf->path = path;
}
static void
-read_link(struct input_msg *msg, const char *path)
+read_link(struct input_file *inf, const char *path)
{
struct stat sb;
char lpath[PATH_MAX];
@@ -322,25 +267,25 @@ read_link(struct input_msg *msg, const c
size = readlink(path, lpath, sizeof lpath - 1);
if (size == -1) {
- msg->link_error = errno;
+ inf->link_error = errno;
return;
}
lpath[size] = '\0';
if (*lpath == '/')
- strlcpy(msg->link_path, lpath, sizeof msg->link_path);
+ strlcpy(inf->link_path, lpath, sizeof inf->link_path);
else {
copy = xstrdup(path);
root = dirname(copy);
if (*root == '\0' || strcmp(root, ".") == 0 ||
strcmp (root, "/") == 0)
- strlcpy(msg->link_path, lpath, sizeof msg->link_path);
+ strlcpy(inf->link_path, lpath, sizeof inf->link_path);
else {
- used = snprintf(msg->link_path, sizeof msg->link_path,
+ used = snprintf(inf->link_path, sizeof inf->link_path,
"%s/%s", root, lpath);
- if (used < 0 || (size_t)used >= sizeof msg->link_path) {
- msg->link_error = ENAMETOOLONG;
+ if (used < 0 || (size_t)used >= sizeof inf->link_path) {
+ inf->link_error = ENAMETOOLONG;
free(copy);
return;
}
@@ -350,81 +295,7 @@ read_link(struct input_msg *msg, const c
}
if (!Lflag && stat(path, &sb) == -1)
- msg->link_target = errno;
-}
-
-static __dead void
-child(int fd, pid_t parent, int argc, char **argv)
-{
- struct passwd *pw;
- struct magic *m;
- struct imsgbuf ibuf;
- struct imsg imsg;
- struct input_msg *msg;
- struct input_ack ack;
- struct input_file inf;
- int i, idx;
- size_t len, width = 0;
-
- if (pledge("stdio getpw recvfd id", NULL) == -1)
- err(1, "pledge");
-
- if (geteuid() == 0) {
- pw = getpwnam(FILE_USER);
- if (pw == NULL)
- errx(1, "unknown user %s", FILE_USER);
- if (setgroups(1, &pw->pw_gid) != 0)
- err(1, "setgroups");
- if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0)
- err(1, "setresgid");
- if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0)
- err(1, "setresuid");
- }
-
- if (pledge("stdio recvfd", NULL) == -1)
- err(1, "pledge");
-
- m = magic_load(magicfp, magicpath, cflag || Wflag);
- if (cflag) {
- magic_dump(m);
- exit(0);
- }
-
- for (i = 0; i < argc; i++) {
- len = strlen(argv[i]) + 1;
- if (len > width)
- width = len;
- }
-
- imsg_init(&ibuf, fd);
- for (;;) {
- if (read_message(&ibuf, &imsg, parent) == 0)
- break;
- if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof *msg)
- errx(1, "message too small");
- msg = imsg.data;
-
- idx = msg->idx;
- if (idx < 0 || idx >= argc)
- errx(1, "index out of range");
-
- memset(&inf, 0, sizeof inf);
- inf.m = m;
- inf.msg = msg;
-
- inf.path = argv[idx];
- inf.fd = imsg.fd;
-
- test_file(&inf, width);
-
- if (imsg.fd != -1)
- close(imsg.fd);
- imsg_free(&imsg);
-
- ack.idx = idx;
- send_message(&ibuf, &ack, sizeof ack, -1);
- }
- exit(0);
+ inf->link_target = errno;
}
static void *
@@ -461,14 +332,14 @@ load_file(struct input_file *inf)
{
size_t used;
- if (inf->msg->sb.st_size == 0 && S_ISREG(inf->msg->sb.st_mode))
+ if (inf->sb.st_size == 0 && S_ISREG(inf->sb.st_mode))
return (0); /* empty file */
- if (inf->msg->sb.st_size == 0 || inf->msg->sb.st_size > FILE_READ_SIZE)
+ if (inf->sb.st_size == 0 || inf->sb.st_size > FILE_READ_SIZE)
inf->size = FILE_READ_SIZE;
else
- inf->size = inf->msg->sb.st_size;
+ inf->size = inf->sb.st_size;
- if (!S_ISREG(inf->msg->sb.st_mode))
+ if (!S_ISREG(inf->sb.st_mode))
goto try_read;
inf->base = mmap(NULL, inf->size, PROT_READ, MAP_PRIVATE, inf->fd, 0);
@@ -491,13 +362,13 @@ try_read:
static int
try_stat(struct input_file *inf)
{
- if (inf->msg->error != 0) {
+ if (inf->error != 0) {
xasprintf(&inf->result, "cannot stat '%s' (%s)", inf->path,
- strerror(inf->msg->error));
+ strerror(inf->error));
return (1);
}
if (sflag || strcmp(inf->path, "-") == 0) {
- switch (inf->msg->sb.st_mode & S_IFMT) {
+ switch (inf->sb.st_mode & S_IFMT) {
case S_IFIFO:
if (strcmp(inf->path, "-") != 0)
break;
@@ -508,29 +379,29 @@ try_stat(struct input_file *inf)
}
}
- if (iflag && (inf->msg->sb.st_mode & S_IFMT) != S_IFREG) {
+ if (iflag && (inf->sb.st_mode & S_IFMT) != S_IFREG) {
xasprintf(&inf->result, "application/x-not-regular-file");
return (1);
}
- switch (inf->msg->sb.st_mode & S_IFMT) {
+ switch (inf->sb.st_mode & S_IFMT) {
case S_IFDIR:
xasprintf(&inf->result, "directory");
return (1);
case S_IFLNK:
- if (inf->msg->link_error != 0) {
+ if (inf->link_error != 0) {
xasprintf(&inf->result, "unreadable symlink '%s' (%s)",
- inf->path, strerror(inf->msg->link_error));
+ inf->path, strerror(inf->link_error));
return (1);
}
- if (inf->msg->link_target == ELOOP)
+ if (inf->link_target == ELOOP)
xasprintf(&inf->result, "symbolic link in a loop");
- else if (inf->msg->link_target != 0) {
+ else if (inf->link_target != 0) {
xasprintf(&inf->result, "broken symbolic link to '%s'",
- inf->msg->link_path);
+ inf->link_path);
} else {
xasprintf(&inf->result, "symbolic link to '%s'",
- inf->msg->link_path);
+ inf->link_path);
}
return (1);
case S_IFSOCK:
@@ -538,13 +409,13 @@ try_stat(struct input_file *inf)
return (1);
case S_IFBLK:
xasprintf(&inf->result, "block special (%ld/%ld)",
- (long)major(inf->msg->sb.st_rdev),
- (long)minor(inf->msg->sb.st_rdev));
+ (long)major(inf->sb.st_rdev),
+ (long)minor(inf->sb.st_rdev));
return (1);
case S_IFCHR:
xasprintf(&inf->result, "character special (%ld/%ld)",
- (long)major(inf->msg->sb.st_rdev),
- (long)minor(inf->msg->sb.st_rdev));
+ (long)major(inf->sb.st_rdev),
+ (long)minor(inf->sb.st_rdev));
return (1);
case S_IFIFO:
xasprintf(&inf->result, "fifo (named pipe)");
@@ -571,16 +442,16 @@ try_access(struct input_file *inf)
{
char tmp[256] = "";
- if (inf->msg->sb.st_size == 0 && S_ISREG(inf->msg->sb.st_mode))
+ if (inf->sb.st_size == 0 && S_ISREG(inf->sb.st_mode))
return (0); /* empty file */
if (inf->fd != -1)
return (0);
- if (inf->msg->sb.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))
+ if (inf->sb.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))
strlcat(tmp, "writable, ", sizeof tmp);
- if (inf->msg->sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
+ if (inf->sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
strlcat(tmp, "executable, ", sizeof tmp);
- if (S_ISREG(inf->msg->sb.st_mode))
+ if (S_ISREG(inf->sb.st_mode))
strlcat(tmp, "regular file, ", sizeof tmp);
strlcat(tmp, "no read permission", sizeof tmp);