Version in base suite: 1.3.8+dfsg-4+deb12u3 Base version: proftpd-dfsg_1.3.8+dfsg-4+deb12u3 Target version: proftpd-dfsg_1.3.8+dfsg-4+deb12u4 Base file: /srv/ftp-master.debian.org/ftp/pool/main/p/proftpd-dfsg/proftpd-dfsg_1.3.8+dfsg-4+deb12u3.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/p/proftpd-dfsg/proftpd-dfsg_1.3.8+dfsg-4+deb12u4.dsc changelog | 9 control | 2 control.in | 2 patches/5031d498a71c493b9659e2b5ccafde58b0897e30.diff | 337 ++++++++++++++++++ patches/series | 1 5 files changed, 349 insertions(+), 2 deletions(-) diff -Nru proftpd-dfsg-1.3.8+dfsg/debian/changelog proftpd-dfsg-1.3.8+dfsg/debian/changelog --- proftpd-dfsg-1.3.8+dfsg/debian/changelog 2024-01-09 21:52:35.000000000 +0000 +++ proftpd-dfsg-1.3.8+dfsg/debian/changelog 2024-11-30 22:32:48.000000000 +0000 @@ -1,3 +1,12 @@ +proftpd-dfsg (1.3.8+dfsg-4+deb12u4) bookworm-security; urgency=high + + * Add my Debian E-Mail address to Field Uploaders. + * Patch for issue Issue #1830 (Closes: #1082326). + Supplemental Group Inheritance Grants Unintended Access to GID 0 + (CVE-2024-48651). + + -- Hilmar Preuße Sat, 30 Nov 2024 23:32:48 +0100 + proftpd-dfsg (1.3.8+dfsg-4+deb12u3) bookworm; urgency=medium * Add patch for Terrapin attack (CVE-2023-48795). diff -Nru proftpd-dfsg-1.3.8+dfsg/debian/control proftpd-dfsg-1.3.8+dfsg/debian/control --- proftpd-dfsg-1.3.8+dfsg/debian/control 2024-01-01 21:21:15.000000000 +0000 +++ proftpd-dfsg-1.3.8+dfsg/debian/control 2024-11-30 22:32:48.000000000 +0000 @@ -3,7 +3,7 @@ Priority: optional Maintainer: ProFTPD Maintainance Team Uploaders: Francesco Paolo Lovergine , - Hilmar Preusse + Hilmar Preuße Standards-Version: 4.6.0 Build-Depends: debhelper-compat (= 13), dh-exec, diff -Nru proftpd-dfsg-1.3.8+dfsg/debian/control.in proftpd-dfsg-1.3.8+dfsg/debian/control.in --- proftpd-dfsg-1.3.8+dfsg/debian/control.in 2024-01-01 21:21:15.000000000 +0000 +++ proftpd-dfsg-1.3.8+dfsg/debian/control.in 2024-11-30 22:32:48.000000000 +0000 @@ -3,7 +3,7 @@ Priority: optional Maintainer: ProFTPD Maintainance Team Uploaders: Francesco Paolo Lovergine , - Hilmar Preusse + Hilmar Preuße Standards-Version: 4.6.0 Build-Depends: debhelper-compat (= 13), dh-exec, diff -Nru proftpd-dfsg-1.3.8+dfsg/debian/patches/5031d498a71c493b9659e2b5ccafde58b0897e30.diff proftpd-dfsg-1.3.8+dfsg/debian/patches/5031d498a71c493b9659e2b5ccafde58b0897e30.diff --- proftpd-dfsg-1.3.8+dfsg/debian/patches/5031d498a71c493b9659e2b5ccafde58b0897e30.diff 1970-01-01 00:00:00.000000000 +0000 +++ proftpd-dfsg-1.3.8+dfsg/debian/patches/5031d498a71c493b9659e2b5ccafde58b0897e30.diff 2024-11-30 22:32:48.000000000 +0000 @@ -0,0 +1,337 @@ +From 5031d498a71c493b9659e2b5ccafde58b0897e30 Mon Sep 17 00:00:00 2001 +From: TJ Saunders +Date: Wed, 13 Nov 2024 06:33:35 -0800 +Subject: [PATCH] Issue #1830: When no supplemental groups are provided by the + underlying authentication providers, fall back to using the primary + group/GID. (#1835) + +This prevents surprise due to inheritance of the parent processes' supplemental group membership, which might inadvertently provided undesired access. +--- + NEWS | 2 + + contrib/mod_sftp/auth.c | 14 +- + modules/mod_auth.c | 21 ++- + src/auth.c | 16 +- + .../ProFTPD/Tests/Modules/mod_sql_sqlite.pm | 174 ++++++++++++++++++ + 5 files changed, 213 insertions(+), 14 deletions(-) + +diff --git a/NEWS b/NEWS +index 2cd427e8d..495d74853 100644 +diff --git a/contrib/mod_sftp/auth.c b/contrib/mod_sftp/auth.c +index c7a694e04..6196fec4a 100644 +--- a/contrib/mod_sftp/auth.c ++++ b/contrib/mod_sftp/auth.c +@@ -388,8 +388,20 @@ static int setup_env(pool *p, const char *user) { + session.groups == NULL) { + res = pr_auth_getgroups(p, pw->pw_name, &session.gids, &session.groups); + if (res < 1) { ++ /* If no supplemental groups are provided, default to using the process ++ * primary GID as the supplemental group. This prevents access ++ * regressions as seen in Issue #1830. ++ */ + (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, +- "no supplemental groups found for user '%s'", pw->pw_name); ++ "no supplemental groups found for user '%s', " ++ "using primary group %s (GID %lu)", pw->pw_name, session.group, ++ (unsigned long) session.login_gid); ++ ++ session.gids = make_array(p, 2, sizeof(gid_t)); ++ session.groups = make_array(p, 2, sizeof(char *)); ++ ++ *((gid_t *) push_array(session.gids)) = session.login_gid; ++ *((char **) push_array(session.groups)) = pstrdup(p, session.group); + } + } + +diff --git a/modules/mod_auth.c b/modules/mod_auth.c +index a85be0675..4daa927d7 100644 +--- a/modules/mod_auth.c ++++ b/modules/mod_auth.c +@@ -2,7 +2,7 @@ + * ProFTPD - FTP server daemon + * Copyright (c) 1997, 1998 Public Flood Software + * Copyright (c) 1999, 2000 MacGyver aka Habeeb J. Dihu +- * Copyright (c) 2001-2022 The ProFTPD Project team ++ * Copyright (c) 2001-2024 The ProFTPD Project team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -1113,8 +1113,8 @@ static int setup_env(pool *p, cmd_rec *cmd, const char *user, char *pass) { + session.groups = NULL; + } + +- if (!session.gids && +- !session.groups) { ++ if (session.gids == NULL && ++ session.groups == NULL) { + /* Get the supplemental groups. Note that we only look up the + * supplemental group credentials if we have not cached the group + * credentials before, in session.gids and session.groups. +@@ -1124,8 +1124,19 @@ static int setup_env(pool *p, cmd_rec *cmd, const char *user, char *pass) { + */ + res = pr_auth_getgroups(p, pw->pw_name, &session.gids, &session.groups); + if (res < 1) { +- pr_log_debug(DEBUG5, "no supplemental groups found for user '%s'", +- pw->pw_name); ++ /* If no supplemental groups are provided, default to using the process ++ * primary GID as the supplemental group. This prevents access ++ * regressions as seen in Issue #1830. ++ */ ++ pr_log_debug(DEBUG5, "no supplemental groups found for user '%s', " ++ "using primary group %s (GID %lu)", pw->pw_name, session.group, ++ (unsigned long) session.login_gid); ++ ++ session.gids = make_array(p, 2, sizeof(gid_t)); ++ session.groups = make_array(p, 2, sizeof(char *)); ++ ++ *((gid_t *) push_array(session.gids)) = session.login_gid; ++ *((char **) push_array(session.groups)) = pstrdup(p, session.group); + } + } + +diff --git a/src/auth.c b/src/auth.c +index b90fe4162..378f99744 100644 +--- a/src/auth.c ++++ b/src/auth.c +@@ -2,7 +2,7 @@ + * ProFTPD - FTP server daemon + * Copyright (c) 1997, 1998 Public Flood Software + * Copyright (c) 1999, 2000 MacGyver aka Habeeb J. Dihu +- * Copyright (c) 2001-2022 The ProFTPD Project team ++ * Copyright (c) 2001-2024 The ProFTPD Project team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -1471,12 +1471,12 @@ int pr_auth_getgroups(pool *p, const char *name, array_header **group_ids, + } + + /* Allocate memory for the array_headers of GIDs and group names. */ +- if (group_ids) { +- *group_ids = make_array(permanent_pool, 2, sizeof(gid_t)); ++ if (group_ids != NULL) { ++ *group_ids = make_array(p, 2, sizeof(gid_t)); + } + +- if (group_names) { +- *group_names = make_array(permanent_pool, 2, sizeof(char *)); ++ if (group_names != NULL) { ++ *group_names = make_array(p, 2, sizeof(char *)); + } + + cmd = make_cmd(p, 3, name, group_ids ? *group_ids : NULL, +@@ -1495,7 +1495,7 @@ int pr_auth_getgroups(pool *p, const char *name, array_header **group_ids, + * for the benefit of auth_getgroup() implementors. + */ + +- if (group_ids) { ++ if (group_ids != NULL) { + register unsigned int i; + char *strgids = ""; + gid_t *gids = (*group_ids)->elts; +@@ -1511,7 +1511,7 @@ int pr_auth_getgroups(pool *p, const char *name, array_header **group_ids, + *strgids ? strgids : "(None; corrupted group file?)"); + } + +- if (group_names) { ++ if (group_names != NULL) { + register unsigned int i; + char *strgroups = ""; + char **groups = (*group_names)->elts; +@@ -1527,7 +1527,7 @@ int pr_auth_getgroups(pool *p, const char *name, array_header **group_ids, + } + } + +- if (cmd->tmp_pool) { ++ if (cmd->tmp_pool != NULL) { + destroy_pool(cmd->tmp_pool); + cmd->tmp_pool = NULL; + } +diff --git a/tests/t/lib/ProFTPD/Tests/Modules/mod_sql_sqlite.pm b/tests/t/lib/ProFTPD/Tests/Modules/mod_sql_sqlite.pm +index 08c1542aa..42ba9678b 100644 +--- a/tests/t/lib/ProFTPD/Tests/Modules/mod_sql_sqlite.pm ++++ b/tests/t/lib/ProFTPD/Tests/Modules/mod_sql_sqlite.pm +@@ -467,6 +467,11 @@ my $TESTS = { + order => ++$order, + test_class => [qw(forking bug mod_tls)], + }, ++ ++ sql_user_info_no_suppl_groups_issue1830 => { ++ order => ++$order, ++ test_class => [qw(forking bug rootprivs)], ++ }, + }; + + sub new { +@@ -15764,4 +15769,173 @@ EOC + test_cleanup($setup->{log_file}, $ex); + } + ++sub sql_user_info_no_suppl_groups_issue1830 { ++ my $self = shift; ++ my $tmpdir = $self->{tmpdir}; ++ my $setup = test_setup($tmpdir, 'sqlite'); ++ ++ my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); ++ ++ # Build up sqlite3 command to create users, groups tables and populate them ++ my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); ++ ++ if (open(my $fh, "> $db_script")) { ++ print $fh <{user}', '$setup->{passwd}', $setup->{uid}, $setup->{gid}, '$setup->{home_dir}', '/bin/bash'); ++ ++CREATE TABLE groups ( ++ groupname TEXT, ++ gid INTEGER, ++ members TEXT ++); ++INSERT INTO groups (groupname, gid, members) VALUES ('$setup->{group}', $setup->{gid}, '$setup->{user}'); ++EOS ++ ++ unless (close($fh)) { ++ die("Can't write $db_script: $!"); ++ } ++ ++ } else { ++ die("Can't open $db_script: $!"); ++ } ++ ++ my $cmd = "sqlite3 $db_file < $db_script"; ++ build_db($cmd, $db_script); ++ ++ # Make sure that, if we're running as root, the database file has ++ # the permissions/privs set for use by proftpd ++ if ($< == 0) { ++ unless (chmod(0666, $db_file)) { ++ die("Can't set perms on $db_file to 0666: $!"); ++ } ++ } ++ ++ my $config = { ++ PidFile => $setup->{pid_file}, ++ ScoreboardFile => $setup->{scoreboard_file}, ++ SystemLog => $setup->{log_file}, ++ TraceLog => $setup->{log_file}, ++ Trace => 'auth:20 sql:20', ++ ++ # Required for logging the expected message ++ DebugLevel => 5, ++ ++ IfModules => { ++ 'mod_delay.c' => { ++ DelayEngine => 'off', ++ }, ++ ++ 'mod_sql.c' => { ++ AuthOrder => 'mod_sql.c', ++ ++ SQLAuthenticate => 'users', ++ SQLAuthTypes => 'plaintext', ++ SQLBackend => 'sqlite3', ++ SQLConnectInfo => $db_file, ++ SQLLogFile => $setup->{log_file}, ++ ++ # Set these, so that our lower UID/GID will be used ++ SQLMinUserUID => 100, ++ SQLMinUserGID => 100, ++ }, ++ }, ++ }; ++ ++ my ($port, $config_user, $config_group) = config_write($setup->{config_file}, ++ $config); ++ ++ # Open pipes, for use between the parent and child processes. Specifically, ++ # the child will indicate when it's done with its test by writing a message ++ # to the parent. ++ my ($rfh, $wfh); ++ unless (pipe($rfh, $wfh)) { ++ die("Can't open pipe: $!"); ++ } ++ ++ my $ex; ++ ++ # Fork child ++ $self->handle_sigchld(); ++ defined(my $pid = fork()) or die("Can't fork: $!"); ++ if ($pid) { ++ eval { ++ sleep(2); ++ ++ my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); ++ $client->login($setup->{user}, $setup->{passwd}); ++ ++ my $resp_msgs = $client->response_msgs(); ++ my $nmsgs = scalar(@$resp_msgs); ++ ++ my $expected = 1; ++ $self->assert($expected == $nmsgs, ++ test_msg("Expected $expected, got $nmsgs")); ++ ++ $expected = "User $setup->{user} logged in"; ++ $self->assert($expected eq $resp_msgs->[0], ++ test_msg("Expected response '$expected', got '$resp_msgs->[0]'")); ++ ++ $client->quit(); ++ }; ++ if ($@) { ++ $ex = $@; ++ } ++ ++ $wfh->print("done\n"); ++ $wfh->flush(); ++ ++ } else { ++ eval { server_wait($setup->{config_file}, $rfh) }; ++ if ($@) { ++ warn($@); ++ exit 1; ++ } ++ ++ exit 0; ++ } ++ ++ # Stop server ++ server_stop($setup->{pid_file}); ++ $self->assert_child_ok($pid); ++ ++ eval { ++ if (open(my $fh, "< $setup->{log_file}")) { ++ my $ok = 0; ++ ++ while (my $line = <$fh>) { ++ chomp($line); ++ ++ if ($ENV{TEST_VERBOSE}) { ++ print STDERR "# $line\n"; ++ } ++ ++ if ($line =~ /no supplemental groups found for user '$setup->{user}', using primary group/) { ++ $ok = 1; ++ last; ++ } ++ } ++ ++ close($fh); ++ ++ $self->assert($ok, test_msg("Did not see expected log message")); ++ ++ } else { ++ die("Can't read $setup->{log_file}: $!"); ++ } ++ }; ++ if ($@) { ++ $ex = $@ unless $ex; ++ } ++ ++ test_cleanup($setup->{log_file}, $ex); ++} ++ + 1; diff -Nru proftpd-dfsg-1.3.8+dfsg/debian/patches/series proftpd-dfsg-1.3.8+dfsg/debian/patches/series --- proftpd-dfsg-1.3.8+dfsg/debian/patches/series 2024-01-01 21:21:15.000000000 +0000 +++ proftpd-dfsg-1.3.8+dfsg/debian/patches/series 2024-11-30 22:32:48.000000000 +0000 @@ -20,3 +20,4 @@ upstream_1707.diff bcec15efe6c53dac40420731013f1cd2fd54123b.diff 97bbe68363ccf2de0c07f67170ec64a8b4d62592.diff +5031d498a71c493b9659e2b5ccafde58b0897e30.diff