Skip to content

Commit 4a2bcf8

Browse files
committed
added selinux support
Commit adds SELinux support to dropbear by: - adding a new '--enable-selinux' option to configure; by default, it is disabled. This option defines an ENABLE_SELINUX preprocessor macro. - mapping the unix username to the SELinux user which is stored in a new 'user_sid' attribute in the AuthState object - relabeling the controlling pty - setting the context for the next execve() call to the user_sid Operations above will not be done when SELinux is disabled. Failures will generate LOG_ERR messages and in enforcing SELinux mode, dropbear_exit() will be called. Signed-off-by: Enrico Scholz <[email protected]>
1 parent df0f129 commit 4a2bcf8

File tree

7 files changed

+156
-2
lines changed

7 files changed

+156
-2
lines changed

Makefile.in

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
2424
LIBTOM_LIBS=$(STATIC_LTC) $(STATIC_LTM)
2525
endif
2626

27+
LIBSELINUX_LIBS=@LIBSELINUX_LIBS@
28+
2729
OPTION_HEADERS = default_options_guard.h sysoptions.h
2830
ifneq ($(wildcard localoptions.h),)
2931
CFLAGS+=-DLOCALOPTIONS_H_EXISTS
@@ -189,7 +191,7 @@ dropbearkey: $(dropbearkeyobjs)
189191
dropbearconvert: $(dropbearconvertobjs)
190192

191193
dropbear: $(HEADERS) $(LIBTOM_DEPS) Makefile
192-
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@
194+
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBSELINUX_LIBS) $(LIBS) @CRYPTLIB@
193195

194196
dbclient: $(HEADERS) $(LIBTOM_DEPS) Makefile
195197
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS)
@@ -210,7 +212,7 @@ ifeq ($(MULTI),1)
210212
endif
211213

212214
dropbearmulti$(EXEEXT): $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile
213-
$(CC) $(LDFLAGS) -o $@ $(MULTIOBJS) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@
215+
$(CC) $(LDFLAGS) -o $@ $(MULTIOBJS) $(LIBTOM_LIBS) $(LIBSELINUX_LIBS) $(LIBS) @CRYPTLIB@
214216

215217
multibinary: dropbearmulti$(EXEEXT)
216218

auth.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@ struct AuthState {
127127
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
128128
struct PubKeyOptions* pubkey_options;
129129
#endif
130+
131+
#ifdef DROPBEAR_ENABLE_SELINUX
132+
char *user_sid;
133+
#endif
130134
};
131135

132136
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT

common-session.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ void common_session_init(int sock_in, int sock_out) {
126126
ses.keys->trans.zstream = NULL;
127127
#endif
128128

129+
#ifdef DROPBEAR_ENABLE_SELINUX
130+
ses.authstate.user_sid = NULL;
131+
#endif
132+
129133
/* key exchange buffers */
130134
ses.session_id = NULL;
131135
ses.kexhashbuf = NULL;

configure.ac

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,18 @@ AC_ARG_WITH(lastlog,
611611
]
612612
)
613613

614+
AC_MSG_CHECKING([whether to enable SELinux])
615+
AC_ARG_ENABLE([selinux],
616+
[ --enable-selinux Enable SELinux support]
617+
)
618+
AC_MSG_RESULT([$enable_selinux])
619+
620+
AC_ARG_VAR([LIBSELINUX_LIBS],[SELinux libraries])
621+
if test x"$enable_selinux" = xyes; then
622+
AC_DEFINE([DROPBEAR_ENABLE_SELINUX],[1],[Enable SELinux support])
623+
AC_SUBST([LIBSELINUX_LIBS],[${LIBSELINUX_LIBS:--lselinux}])
624+
fi
625+
614626
if test -z "$no_loginfunc_check"; then
615627
dnl Checks for libutil functions (login(), logout() etc, not openpty() )
616628
AC_SEARCH_LIBS(login, util bsd, [AC_DEFINE(HAVE_LOGIN,1,[Have login() function])])

svr-auth.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,13 @@
3737
#include "runopts.h"
3838
#include "dbrandom.h"
3939

40+
#ifdef DROPBEAR_ENABLE_SELINUX
41+
# include <selinux/selinux.h>
42+
# include <selinux/get_context_list.h>
43+
#endif
44+
4045
static int checkusername(const char *username, unsigned int userlen);
46+
static void initselinux(const char *username);
4147

4248
/* initialise the first time for a session, resetting all parameters */
4349
void svr_authinitialise() {
@@ -119,6 +125,8 @@ void recv_msg_userauth_request() {
119125
valid_user = 1;
120126
}
121127

128+
initselinux(ses.authstate.pw_name);
129+
122130
/* user wants to know what methods are supported */
123131
if (methodlen == AUTH_METHOD_NONE_LEN &&
124132
strncmp(methodname, AUTH_METHOD_NONE,
@@ -227,6 +235,44 @@ static int check_group_membership(gid_t check_gid, const char* username, gid_t u
227235
}
228236
#endif
229237

238+
static void initselinux(const char *username)
239+
{
240+
#ifdef DROPBEAR_ENABLE_SELINUX
241+
char *seuser;
242+
char *level;
243+
int rc;
244+
245+
if (!is_selinux_enabled())
246+
return;
247+
248+
freecon(ses.authstate.user_sid);
249+
ses.authstate.user_sid = NULL;
250+
251+
rc = getseuserbyname(username, &seuser, &level);
252+
if (rc < 0) {
253+
dropbear_log(LOG_ERR, "getseuserbyname(%s) failed", username);
254+
goto out;
255+
}
256+
257+
rc = get_default_context_with_level(seuser, level, NULL,
258+
&ses.authstate.user_sid);
259+
free(seuser);
260+
free(level);
261+
262+
if (rc < 0) {
263+
dropbear_log(LOG_ERR, "get_default_context(%s) failed", username);
264+
ses.authstate.user_sid = NULL;
265+
goto out;
266+
}
267+
268+
rc = 0;
269+
270+
out:
271+
if (rc < 0 && security_getenforce() > 0)
272+
dropbear_exit("SELinux: failed to initialie");
273+
#endif
274+
}
275+
230276
/* Check that the username exists and isn't disallowed (root), and has a valid shell.
231277
* returns DROPBEAR_SUCCESS on valid username, DROPBEAR_FAILURE on failure */
232278
static int checkusername(const char *username, unsigned int userlen) {

svr-chansession.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@
3838
#include "runopts.h"
3939
#include "auth.h"
4040

41+
#ifdef DROPBEAR_ENABLE_SELINUX
42+
# include <selinux/selinux.h>
43+
#endif
44+
4145
/* Handles sessions (either shells or programs) requested by the client */
4246

4347
static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
@@ -573,6 +577,53 @@ static void get_termmodes(const struct ChanSess *chansess) {
573577
TRACE(("leave get_termmodes"))
574578
}
575579

580+
static void relabelpty(const char *tty)
581+
{
582+
#ifdef DROPBEAR_ENABLE_SELINUX
583+
char *old_sid = NULL;
584+
char *new_sid = NULL;
585+
security_class_t class;
586+
int rc;
587+
588+
if (!is_selinux_enabled())
589+
return;
590+
591+
rc = getfilecon(tty, &old_sid);
592+
if (rc < 0) {
593+
dropbear_log(LOG_ERR, "failed to get context of tty '%s'", tty);
594+
goto out;
595+
}
596+
597+
class = string_to_security_class("chr_file");
598+
if (!class) {
599+
rc = -1;
600+
dropbear_log(LOG_ERR, "SELinux: failed to map 'chr_file'");
601+
goto out;
602+
}
603+
604+
rc = security_compute_relabel(ses.authstate.user_sid, old_sid, class, &new_sid);
605+
if (rc < 0) {
606+
dropbear_log(LOG_ERR, "failed to compute tty relabel");
607+
goto out;
608+
}
609+
610+
rc = setfilecon(tty, new_sid);
611+
if (rc < 0) {
612+
dropbear_log(LOG_ERR, "failed to set file context for '%s'", tty);
613+
goto out;
614+
}
615+
616+
rc = 0;
617+
618+
out:
619+
freecon(new_sid);
620+
freecon(old_sid);
621+
622+
if (rc < 0 && security_getenforce() > 0)
623+
dropbear_exit("SELinux: failed to relabel PTY");
624+
#endif
625+
}
626+
576627
/* Set up a session pty which will be used to execute the shell or program.
577628
* The pty is allocated now, and kept for when the shell/program executes.
578629
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
@@ -621,6 +672,8 @@ static int sessionpty(struct ChanSess * chansess) {
621672
/* Read the terminal modes */
622673
get_termmodes(chansess);
623674

675+
relabelpty(chansess->tty);
676+
624677
TRACE(("leave sessionpty"))
625678
return DROPBEAR_SUCCESS;
626679
}
@@ -743,6 +796,29 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
743796
return ret;
744797
}
745798

799+
static void init_selinux_session(void)
800+
{
801+
#ifdef DROPBEAR_ENABLE_SELINUX
802+
char *ctx = ses.authstate.user_sid;
803+
int rc;
804+
805+
if (!is_selinux_enabled())
806+
return;
807+
808+
rc = setexeccon(ctx);
809+
if (rc < 0) {
810+
dropbear_log(LOG_ERR, "setexeccon() failed");
811+
goto out;
812+
}
813+
814+
rc = 0;
815+
816+
out:
817+
if (rc < 0 && security_getenforce() > 0)
818+
dropbear_exit("SELinux: failed to initialize session");
819+
#endif
820+
}
821+
746822
/* Execute a command and set up redirection of stdin/stdout/stderr without a
747823
* pty.
748824
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
@@ -949,6 +1025,8 @@ static void execchild(const void *user_data) {
9491025
#endif /* HAVE_CLEARENV */
9501026
#endif /* DEBUG_VALGRIND */
9511027

1028+
init_selinux_session();
1029+
9521030
/* We can only change uid/gid as root ... */
9531031
if (getuid() == 0) {
9541032

svr-session.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@
4242
#include "crypto_desc.h"
4343
#include "fuzz.h"
4444

45+
#ifdef DROPBEAR_ENABLE_SELINUX
46+
# include <selinux/selinux.h>
47+
#endif
48+
4549
static void svr_remoteclosed(void);
4650
static void svr_algos_initialise(void);
4751

@@ -84,6 +88,10 @@ svr_session_cleanup(void) {
8488
/* free potential public key options */
8589
svr_pubkey_options_cleanup();
8690

91+
#ifdef DROPBEAR_ENABLE_SELINUX
92+
freecon(ses.authstate.user_sid);
93+
#endif
94+
8795
m_free(svr_ses.addrstring);
8896
m_free(svr_ses.remotehost);
8997
m_free(svr_ses.childpids);

0 commit comments

Comments
 (0)