Skip to content

Commit

Permalink
Merge pull request #53 from sailfishos/jb54497_defaultsandboxing
Browse files Browse the repository at this point in the history
Allow sandboxing of legacy apps.
  • Loading branch information
rainemak authored Jun 18, 2021
2 parents d658e88 + ede2eb6 commit a630f83
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 11 deletions.
1 change: 1 addition & 0 deletions daemon/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ CPPFLAGS += -DVERSION='"${VERSION}"'
CPPFLAGS += -DSYSCONFDIR='"${_SYSCONFDIR}"'
CPPFLAGS += -DSHAREDSTATEDIR='"${_SHAREDSTATEDIR}"'
CPPFLAGS += -DDATADIR='"${_DATADIR}"'
CPPFLAGS += -DBINDIR='"${_BINDIR}"'

CPPFLAGS += -D_GNU_SOURCE
CPPFLAGS += -D_FILE_OFFSET_BITS=64
Expand Down
62 changes: 57 additions & 5 deletions daemon/appinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ typedef struct
* ========================================================================= */

#define APPINFO_DEFAULT_PROFILE_SECTION "Default Profile"
#define APPINFO_KEY_ENABLED "Enabled"

/* ========================================================================= *
* Prototypes
Expand Down Expand Up @@ -145,6 +146,8 @@ const gchar *appinfo_get_method (const appinfo_t *self);
const gchar *appinfo_get_organization_name(const appinfo_t *self);
const gchar *appinfo_get_application_name (const appinfo_t *self);
const gchar *appinfo_get_data_directory (const appinfo_t *self);
app_mode_t appinfo_get_mode (const appinfo_t *self);
static const gchar *appinfo_get_mode_string (const appinfo_t *self);
void appinfo_set_name (appinfo_t *self, const gchar *name);
void appinfo_set_type (appinfo_t *self, const gchar *type);
void appinfo_set_icon (appinfo_t *self, const gchar *icon);
Expand All @@ -156,6 +159,7 @@ void appinfo_set_method (appinfo_t *self, const gch
void appinfo_set_organization_name(appinfo_t *self, const gchar *organization_name);
void appinfo_set_application_name (appinfo_t *self, const gchar *application_name);
void appinfo_set_data_directory (appinfo_t *self, const gchar *data_directory);
void appinfo_set_mode (appinfo_t *self, app_mode_t mode);

/* ------------------------------------------------------------------------- *
* APPINFO_PERMISSIONS
Expand Down Expand Up @@ -213,6 +217,7 @@ struct appinfo_t
appinfo_state_t anf_state;
time_t anf_dt_ctime[APPINFO_DIR_COUNT];
bool anf_dirty;
app_mode_t anf_mode;

// desktop properties
gchar *anf_dt_name; // DESKTOP_KEY_NAME
Expand Down Expand Up @@ -250,6 +255,8 @@ appinfo_ctor(appinfo_t *self, applications_t *applications, const gchar *id)
self->anf_dt_ctime[APPINFO_DIR_ALT] = -1;
self->anf_dirty = false;

self->anf_mode = APP_MODE_NORMAL;

self->anf_dt_name = NULL;
self->anf_dt_type = NULL;
self->anf_dt_icon = NULL;
Expand Down Expand Up @@ -366,6 +373,7 @@ appinfo_to_variant(const appinfo_t *self)

if( self ) {
add_string("Id", appinfo_id(self));
add_string("Mode", appinfo_get_mode_string(self));

/* Desktop properties
*/
Expand Down Expand Up @@ -548,6 +556,23 @@ appinfo_get_data_directory(const appinfo_t *self)
return self->anf_sj_data_directory ?: appinfo_unknown;
}

app_mode_t
appinfo_get_mode(const appinfo_t *self)
{
return self->anf_mode;
}

static const gchar *
appinfo_get_mode_string(const appinfo_t *self)
{
static const gchar * const lut[] = {
[APP_MODE_NORMAL] = "Normal",
[APP_MODE_COMPATIBILITY] = "Compatibility",
[APP_MODE_NONE] = "None",
};
return lut[self->anf_mode];
}

/* - - - - - - - - - - - - - - - - - - - *
* Setters
* - - - - - - - - - - - - - - - - - - - */
Expand Down Expand Up @@ -629,6 +654,15 @@ appinfo_set_data_directory(appinfo_t *self, const gchar *data_directory)
appinfo_set_dirty(self);
}

void
appinfo_set_mode(appinfo_t *self, app_mode_t mode)
{
if( self->anf_mode != mode ) {
self->anf_mode = mode;
appinfo_set_dirty(self);
}
}

/* ------------------------------------------------------------------------- *
* APPINFO_PERMISSIONS
* ------------------------------------------------------------------------- */
Expand Down Expand Up @@ -772,9 +806,9 @@ appinfo_parse_desktop(appinfo_t *self)
gchar *path2 = NULL;
GError *err = NULL;
gchar **permissions = NULL;
appinfo_file_t file1_state = APPINFO_STATE_UNSET;
appinfo_file_t file2_state = APPINFO_STATE_UNSET;
appinfo_file_t combined = APPINFO_STATE_UNSET;
appinfo_file_t file1_state = 0;
appinfo_file_t file2_state = 0;
appinfo_file_t combined = 0;

path1 = path_from_desktop_name(appinfo_id(self));
path2 = alt_path_from_desktop_name(appinfo_id(self));
Expand Down Expand Up @@ -851,8 +885,15 @@ appinfo_parse_desktop(appinfo_t *self)
group = SAILJAIL_SECTION_SECONDARY;
/* else: legacy app => use default profile */

/* Sandboxing=Disabled means that the app opts out of sandboxing and
* launching via sailjail will result in use of compatibility mode.
*/
gchar *sandboxing = NULL;
if( group )
sandboxing = keyfile_get_string(ini, group, SAILJAIL_KEY_SANDBOXING, 0);

stringset_t *set;
if( group ) {
if( group && g_strcmp0(sandboxing, "Disabled") ) {
tmp = keyfile_get_string(ini, group, SAILJAIL_KEY_ORGANIZATION_NAME, 0),
appinfo_set_organization_name(self, tmp),
g_free(tmp);
Expand All @@ -866,15 +907,26 @@ appinfo_parse_desktop(appinfo_t *self)
g_free(tmp);

set = keyfile_get_stringset(ini, group, SAILJAIL_KEY_PERMISSIONS);

appinfo_set_mode(self, APP_MODE_NORMAL);
}
else {
/* Read default profile from configuration */
set = config_stringset(appinfo_config(self),
const config_t *config = appinfo_config(self);
set = config_stringset(config,
APPINFO_DEFAULT_PROFILE_SECTION,
SAILJAIL_KEY_PERMISSIONS);
if( !g_strcmp0(sandboxing, "Disabled") ||
!config_boolean(config,
APPINFO_DEFAULT_PROFILE_SECTION,
APPINFO_KEY_ENABLED, false) )
appinfo_set_mode(self, APP_MODE_NONE);
else
appinfo_set_mode(self, APP_MODE_COMPATIBILITY);
}
appinfo_set_permissions(self, set);
stringset_delete(set);
g_free(sandboxing);

/* Validate */
if( appinfo_get_name(self) != appinfo_unknown &&
Expand Down
8 changes: 8 additions & 0 deletions daemon/appinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ typedef struct appinfo_t appinfo_t;
typedef struct config_t config_t;
typedef struct control_t control_t;

typedef enum {
APP_MODE_NORMAL,
APP_MODE_COMPATIBILITY,
APP_MODE_NONE,
} app_mode_t;

/* ========================================================================= *
* Prototypes
* ========================================================================= */
Expand Down Expand Up @@ -95,6 +101,7 @@ const gchar *appinfo_get_method (const appinfo_t *self);
const gchar *appinfo_get_organization_name(const appinfo_t *self);
const gchar *appinfo_get_application_name (const appinfo_t *self);
const gchar *appinfo_get_data_directory (const appinfo_t *self);
app_mode_t appinfo_get_mode (const appinfo_t *self);
void appinfo_set_name (appinfo_t *self, const gchar *name);
void appinfo_set_type (appinfo_t *self, const gchar *type);
void appinfo_set_icon (appinfo_t *self, const gchar *icon);
Expand All @@ -106,6 +113,7 @@ void appinfo_set_method (appinfo_t *self, const gchar *method)
void appinfo_set_organization_name(appinfo_t *self, const gchar *organization_name);
void appinfo_set_application_name (appinfo_t *self, const gchar *application_name);
void appinfo_set_data_directory (appinfo_t *self, const gchar *data_directory);
void appinfo_set_mode (appinfo_t *self, app_mode_t mode);

/* ------------------------------------------------------------------------- *
* APPINFO_PERMISSIONS
Expand Down
41 changes: 35 additions & 6 deletions daemon/sailjailclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ const char *client_sailjail_data_directory (client_t *self)
const char **client_sailjail_application_permissions(client_t *self);
const char *client_maemo_service (client_t *self);
const char *client_maemo_method (client_t *self);
const char *client_mode (client_t *self);

/* ------------------------------------------------------------------------- *
* CLIENT_PROPERTIES
Expand Down Expand Up @@ -162,7 +163,7 @@ static int sailjailclient_get_field_code(const char *arg);
static bool sailjailclient_is_option (const char *arg);
static bool sailjailclient_ignore_arg (const char *arg);
static bool sailjailclient_match_argv (const char **tpl_argv, const char **app_argv);
static bool sailjailclient_validate_argv (const char *exec, const gchar **app_argv);
static bool sailjailclient_validate_argv (const char *exec, const gchar **app_argv, bool use_compatibility);
static bool sailjailclient_test_elf (const char *filename);
static void sailjailclient_print_usage (const char *progname);
static bool sailjailclient_binary_check (const char *binary_path);
Expand Down Expand Up @@ -355,6 +356,12 @@ client_maemo_method(client_t *self)
return client_get_appinfo_string(self, MAEMO_KEY_METHOD);
}

const char *
client_mode(client_t *self)
{
return client_get_appinfo_string(self, "Mode");
}

/* ------------------------------------------------------------------------- *
* CLIENT_PROPERTIES
* ------------------------------------------------------------------------- */
Expand Down Expand Up @@ -732,12 +739,15 @@ client_launch_application(client_t *self)
goto EXIT;
}

/* Interpret both "Compatibility" and "None" as compatibility mode */
bool use_compatibility = g_strcmp0(client_mode(self), "Normal");

if( booster_name ) {
/* Application booster validates Exec line when it gets
* launch requrest from invoker.
*/
}
else if( !sailjailclient_validate_argv(exec, argv) ) {
else if( !sailjailclient_validate_argv(exec, argv, use_compatibility) ) {
log_err("Command line does not match template");
goto EXIT;
}
Expand All @@ -760,8 +770,10 @@ client_launch_application(client_t *self)
client_add_firejail_option(self, "--whitelist=%s", desktop1_path);

/* Legacy app binary based data directories are made available.
* But only if they already exist. */
client_add_firejail_directory(self, false, "${HOME}/.local/share/%s", binary_name);
* But they are not created unless legacy app sandboxing is used. */
client_add_firejail_directory(self, use_compatibility, "${HOME}/.local/share/%s", binary_name);
client_add_firejail_directory(self, use_compatibility, "${HOME}/.config/%s", binary_name);
client_add_firejail_directory(self, use_compatibility, "${HOME}/.cache/%s", binary_name);

if( !empty_p(org_name) && !empty_p(app_name) ) {
client_add_firejail_directory(self, true, "${HOME}/.cache/%s/%s", org_name, app_name);
Expand Down Expand Up @@ -1039,7 +1051,7 @@ sailjailclient_match_argv(const char **tpl_argv, const char **app_argv)
}

static bool
sailjailclient_validate_argv(const char *exec, const gchar **app_argv)
sailjailclient_validate_argv(const char *exec, const gchar **app_argv, bool use_compatibility)
{
bool validated = false;
GError *err = NULL;
Expand All @@ -1050,6 +1062,11 @@ sailjailclient_validate_argv(const char *exec, const gchar **app_argv)
goto EXIT;
}

if( use_compatibility && strncmp(app_argv[0], BINDIR "/", sizeof BINDIR) ) {
log_err("Legacy apps must be in: " BINDIR "/");
goto EXIT;
}

/* Split desktop Exec line into argv */
if( !g_shell_parse_argv(exec, NULL, &exec_argv, &err) ) {
log_err("Exec line parse failure: %s", err->message);
Expand All @@ -1064,18 +1081,30 @@ sailjailclient_validate_argv(const char *exec, const gchar **app_argv)
/* Expectation: Exec line might have leading 'wrapper' executables
* such as sailjail, invoker, etc -> make an attempt to skip those
* by looking for argv[0] for command we are about to launch.
*
* While sandboxing aware apps must use absolute path, legacy apps
* usually don't and they must reside in BINDIR.
*/
const char **tpl_argv = (const char **)exec_argv;
const char *alternative = app_argv[0] + sizeof (BINDIR "/") - 1;
for( ; *tpl_argv; ++tpl_argv ) {
if( !g_strcmp0(*tpl_argv, app_argv[0]) )
break;
if( use_compatibility && !g_strcmp0(*tpl_argv, alternative) )
break;
}

if( !*tpl_argv ) {
log_err("Exec line does not contain '%s'", *app_argv);
goto EXIT;
}

if( use_compatibility && strncmp(*tpl_argv, BINDIR "/", sizeof BINDIR) ) {
char *temp = (char *)*tpl_argv;
*tpl_argv = g_strconcat(BINDIR "/", temp, NULL);
g_free(temp);
}

if( !sailjailclient_match_argv(tpl_argv, app_argv) ) {
gchar *args = g_strjoinv(" ", (gchar **)app_argv);
log_err("Application args do not match Exec line template");
Expand Down Expand Up @@ -1329,7 +1358,7 @@ sailjailclient_main(int argc, char **argv)

if( match_exec ) {
if( sailjailclient_validate_argv(match_exec,
client_get_argv(client, NULL)) )
client_get_argv(client, NULL), false) )
exit_code = EXIT_SUCCESS;
goto EXIT;
}
Expand Down
5 changes: 5 additions & 0 deletions daemon/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ G_BEGIN_DECLS
# define VERSION "0.0.0"
# endif

# ifndef BINDIR
# define BINDIR "/usr/bin"
# endif

# ifndef SYSCONFDIR
# define SYSCONFDIR "/etc"
# endif
Expand Down Expand Up @@ -118,6 +122,7 @@ G_BEGIN_DECLS
# define SAILJAIL_KEY_APPLICATION_NAME "ApplicationName"
# define SAILJAIL_KEY_DATA_DIRECTORY "DataDirectory"
# define SAILJAIL_KEY_PERMISSIONS "Permissions"
# define SAILJAIL_KEY_SANDBOXING "Sandboxing"

# define NEMO_KEY_APPLICATION_TYPE "X-Nemo-Application-Type"
# define NEMO_KEY_SINGLE_INSTANCE "X-Nemo-Single-Instance"
Expand Down
1 change: 1 addition & 0 deletions rpm/sailjail.spec
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ install -D -m755 tools/measure_launch_time.py \
make \
_SYSCONFDIR=%{_sysconfdir}\
_DATADIR=%{_datadir}\
_BINDIR=%{_bindir}\
_LIBDIR=%{_libdir}\
_USERUNITDIR=%{_userunitdir}\
_UNITDIR=%{_unitdir}\
Expand Down

0 comments on commit a630f83

Please sign in to comment.