untrusted comment: verify with openbsd-66-base.pub
RWSvK/c+cFe24Nnboj1PMZE5lNWPO6yDiz1nnvFzjiJVyt1UhQXi1GeQx0vtgyCOKv090914EufmxN/iI8Jlbj1NNhT4mylAWw0=
OpenBSD 6.6 errata 010, December 3, 2019:
libc's authentication layer performed insufficient username validation.
Apply by doing:
signify -Vep /etc/signify/openbsd-66-base.pub -x 010_libcauth.patch.sig \
-m - | (cd /usr/src && patch -p0)
And then rebuild and install libc, su and login:
cd /usr/src/lib/libc
make obj
make
make install
cd /usr/src/usr.bin/su
make obj
make
make install
cd /usr/src/usr.bin/login
make obj
make
make install
Index: lib/libc/gen/auth_subr.c
===================================================================
RCS file: /cvs/src/lib/libc/gen/auth_subr.c,v
diff -u -p -u -r1.53 auth_subr.c
--- lib/libc/gen/auth_subr.c 28 Jun 2019 13:32:41 -0000 1.53
+++ lib/libc/gen/auth_subr.c 3 Dec 2019 06:59:16 -0000
@@ -304,7 +304,7 @@ auth_challenge(auth_session_t *as)
char path[PATH_MAX];
int len;
- if (as == NULL || as->style == NULL || as->name == NULL)
+ if (as == NULL || as->style == NULL || !_auth_validuser(as->name))
return (NULL);
len = snprintf(path, sizeof(path), _PATH_AUTHPROG "%s", as->style);
@@ -316,7 +316,7 @@ auth_challenge(auth_session_t *as)
free(as->challenge);
as->challenge = NULL;
- auth_call(as, path, as->style, "-s", "challenge", as->name,
+ auth_call(as, path, as->style, "-s", "challenge", "--", as->name,
as->class, (char *)NULL);
if (as->state & AUTH_CHALLENGE)
as->challenge = auth_getvalue(as, "challenge");
@@ -476,6 +476,10 @@ auth_setitem(auth_session_t *as, auth_it
case AUTHV_NAME:
if (value == as->name)
return (0);
+ if (value != NULL && !_auth_validuser(value)) {
+ errno = EINVAL;
+ return (-1);
+ }
if (value != NULL && (value = strdup(value)) == NULL)
return (-1);
free(as->name);
@@ -821,6 +825,7 @@ auth_call(auth_session_t *as, char *path
argv[argc++] = "-v";
argv[argc++] = "fd=4"; /* AUTH_FD, see below */
}
+ /* XXX - fail if out of space in argv */
for (opt = as->optlist; opt != NULL; opt = opt->next) {
if (argc < Nargc - 2) {
argv[argc++] = "-v";
Index: lib/libc/gen/authenticate.c
===================================================================
RCS file: /cvs/src/lib/libc/gen/authenticate.c,v
diff -u -p -u -r1.27 authenticate.c
--- lib/libc/gen/authenticate.c 28 Jun 2019 13:32:41 -0000 1.27
+++ lib/libc/gen/authenticate.c 3 Dec 2019 01:33:42 -0000
@@ -174,6 +174,17 @@ auth_cat(char *file)
DEF_WEAK(auth_cat);
int
+_auth_validuser(const char *name)
+{
+ /* User name must be specified and may not start with a '-'. */
+ if (name == NULL || *name == '\0' || *name == '-') {
+ syslog(LOG_ERR, "invalid user name %s", name ? name : "(NULL)");
+ return 0;
+ }
+ return 1;
+}
+
+int
auth_approval(auth_session_t *as, login_cap_t *lc, char *name, char *type)
{
int close_on_exit, close_lc_on_exit, len;
@@ -192,6 +203,10 @@ auth_approval(auth_session_t *as, login_
if (pwd == NULL) {
if (name != NULL) {
+ if (!_auth_validuser(name)) {
+ warnx("cannot approve who we don't recognize");
+ return (0);
+ }
getpwnam_r(name, &pwstore, pwbuf, sizeof(pwbuf), &pwd);
} else {
getpwuid_r(getuid(), &pwstore, pwbuf, sizeof(pwbuf),
@@ -217,7 +232,7 @@ auth_approval(auth_session_t *as, login_
}
if (pwd == NULL && (approve = strchr(name, '.')) != NULL) {
strlcpy(path, name, sizeof path);
- path[approve-name] = '\0';
+ path[approve - name] = '\0';
getpwnam_r(name, &pwstore, pwbuf, sizeof(pwbuf), &pwd);
}
lc = login_getclass(pwd ? pwd->pw_class : NULL);
@@ -290,7 +305,7 @@ auth_approval(auth_session_t *as, login_
}
}
if (approve)
- auth_call(as, approve, strrchr(approve, '/') + 1, name,
+ auth_call(as, approve, strrchr(approve, '/') + 1, "--", name,
lc->lc_class, type, (char *)NULL);
out:
@@ -314,6 +329,8 @@ auth_usercheck(char *name, char *style,
struct passwd pwstore, *pwd = NULL;
char *slash;
+ if (!_auth_validuser(name))
+ return (NULL);
if (strlcpy(namebuf, name, sizeof(namebuf)) >= sizeof(namebuf))
return (NULL);
name = namebuf;
@@ -382,6 +399,8 @@ auth_userchallenge(char *name, char *sty
struct passwd pwstore, *pwd = NULL;
char *slash, pwbuf[_PW_BUF_LEN];
+ if (!_auth_validuser(name))
+ return (NULL);
if (strlen(name) >= sizeof(namebuf))
return (NULL);
strlcpy(namebuf, name, sizeof namebuf);
@@ -440,7 +459,8 @@ auth_userresponse(auth_session_t *as, ch
auth_setstate(as, 0);
if ((style = auth_getitem(as, AUTHV_STYLE)) == NULL ||
- (name = auth_getitem(as, AUTHV_NAME)) == NULL) {
+ (name = auth_getitem(as, AUTHV_NAME)) == NULL ||
+ !_auth_validuser(name)) {
if (more == 0)
return (auth_close(as));
return(0);
@@ -466,7 +486,8 @@ auth_userresponse(auth_session_t *as, ch
} else
auth_setdata(as, "", 1);
- auth_call(as, path, style, "-s", "response", name, class, (char *)NULL);
+ auth_call(as, path, style, "-s", "response", "--", name,
+ class, (char *)NULL);
/*
* If they authenticated then make sure they did not expire
@@ -495,7 +516,7 @@ auth_verify(auth_session_t *as, char *st
char path[PATH_MAX];
if ((name == NULL || style == NULL) && as == NULL)
- return (as);
+ return (NULL);
if (as == NULL && (as = auth_open()) == NULL)
return (NULL);
@@ -509,12 +530,14 @@ auth_verify(auth_session_t *as, char *st
style = auth_getitem(as, AUTHV_STYLE);
name = auth_getitem(as, AUTHV_NAME);
+ if (!_auth_validuser(name))
+ return (as);
snprintf(path, sizeof(path), _PATH_AUTHPROG "%s", style);
va_start(ap, name);
auth_set_va_list(as, ap);
auth_call(as, path, auth_getitem(as, AUTHV_STYLE), "-s",
- auth_getitem(as, AUTHV_SERVICE), name, (char *)NULL);
+ auth_getitem(as, AUTHV_SERVICE), "--", name, (char *)NULL);
va_end(ap);
return (as);
}
Index: lib/libc/hidden/bsd_auth.h
===================================================================
RCS file: /cvs/src/lib/libc/hidden/bsd_auth.h,v
diff -u -p -u -r1.1 bsd_auth.h
--- lib/libc/hidden/bsd_auth.h 12 Sep 2015 15:20:14 -0000 1.1
+++ lib/libc/hidden/bsd_auth.h 3 Dec 2019 01:33:42 -0000
@@ -20,6 +20,10 @@
#include_next <bsd_auth.h>
+__BEGIN_HIDDEN_DECLS
+int _auth_validuser(const char *name);
+__END_HIDDEN_DECLS
+
PROTO_NORMAL(auth_approval);
PROTO_NORMAL(auth_call);
PROTO_NORMAL(auth_cat);
Index: usr.bin/su/su.c
===================================================================
RCS file: /cvs/src/usr.bin/su/su.c,v
diff -u -p -u -r1.77 su.c
--- usr.bin/su/su.c 14 Sep 2019 17:47:01 -0000 1.77
+++ usr.bin/su/su.c 3 Dec 2019 01:33:42 -0000
@@ -149,11 +149,11 @@ main(int argc, char **argv)
if (pwd == NULL)
auth_errx(as, 1, "who are you?");
if ((username = strdup(pwd->pw_name)) == NULL)
- auth_errx(as, 1, "can't allocate memory");
+ auth_err(as, 1, NULL);
if (asme && !altshell) {
if (pwd->pw_shell && *pwd->pw_shell) {
if ((shell = strdup(pwd->pw_shell)) == NULL)
- auth_errx(as, 1, "can't allocate memory");
+ auth_err(as, 1, NULL);
} else {
shell = _PATH_BSHELL;
iscsh = NO;
@@ -196,7 +196,7 @@ main(int argc, char **argv)
auth_clean(as);
if (auth_setitem(as, AUTHV_INTERACTIVE, "True") != 0 ||
auth_setitem(as, AUTHV_NAME, user) != 0)
- auth_errx(as, 1, "can't allocate memory");
+ auth_err(as, 1, NULL);
if ((user = auth_getitem(as, AUTHV_NAME)) == NULL)
auth_errx(as, 1, "internal error");
if (auth_setpwd(as, NULL) || (pwd = auth_getpwd(as)) == NULL) {
@@ -225,6 +225,8 @@ main(int argc, char **argv)
}
fprintf(stderr, "Login incorrect\n");
}
+ if (pwd == NULL)
+ auth_errx(as, 1, "internal error");
if (pledge("stdio unveil rpath getpw exec id", NULL) == -1)
err(1, "pledge");
@@ -236,7 +238,7 @@ main(int argc, char **argv)
auth_errx(as, 1, "permission denied (shell).");
} else if (pwd->pw_shell && *pwd->pw_shell) {
if ((shell = strdup(pwd->pw_shell)) == NULL)
- auth_errx(as, 1, "can't allocate memory");
+ auth_err(as, 1, NULL);
iscsh = UNSET;
} else {
shell = _PATH_BSHELL;
Index: usr.bin/login/login.c
===================================================================
RCS file: /cvs/src/usr.bin/login/login.c,v
diff -u -p -u -r1.71 login.c
--- usr.bin/login/login.c 28 Jun 2019 13:35:01 -0000 1.71
+++ usr.bin/login/login.c 3 Dec 2019 03:45:18 -0000
@@ -340,8 +340,13 @@ main(int argc, char *argv[])
}
shell = strrchr(script, '/') + 1;
auth_setstate(as, AUTH_OKAY);
- auth_call(as, script, shell,
- fflag ? "-f" : username, fflag ? username : 0, (char *)0);
+ if (fflag) {
+ auth_call(as, script, shell, "-f", "--", username,
+ (char *)NULL);
+ } else {
+ auth_call(as, script, shell, "--", username,
+ (char *)NULL);
+ }
if (!(auth_getstate(as) & AUTH_ALLOW))
quickexit(1);
auth_setenv(as);
@@ -367,7 +372,7 @@ main(int argc, char *argv[])
}
/*
- * Request the things like the approval script print things
+ * Request that things like the approval script print things
* to stdout (in particular, the nologins files)
*/
auth_setitem(as, AUTHV_INTERACTIVE, "True");