Skip to content

Commit

Permalink
[usb-moded] Keep mtp device accessible by the current user. Fixes JB#…
Browse files Browse the repository at this point in the history
…50332

Additional users can't activate mtp mode. This happens because mtp
device is mounted on usb-moded startup using hard-coded default user
specific permissions.

Keep mtp device unmounted when it is not needed.

Mount mtp device when activating mtp mode - using uid/gid for the
currently active user.

Signed-off-by: Simo Piiroinen <simo.piiroinen@jollamobile.com>
  • Loading branch information
spiiroin committed Jul 4, 2020
1 parent a8ffe2f commit cd0c7e4
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 3 deletions.
3 changes: 0 additions & 3 deletions src/usb_moded-configfs.c
Expand Up @@ -797,9 +797,6 @@ configfs_init(void)

/* Prep: mtp_mode */
configfs_register_function(FUNCTION_MTP);
if( access("/dev/mtp/ep0", F_OK) == -1 ) {
common_system("/bin/mount -o uid=100000,gid=100000 -t functionfs mtp /dev/mtp");
}

/* Prep: developer_mode */
configfs_register_function(FUNCTION_RNDIS);
Expand Down
143 changes: 143 additions & 0 deletions src/usb_moded-worker.c
Expand Up @@ -33,13 +33,38 @@
#include "usb_moded-modesetting.h"
#include "usb_moded-modules.h"

// FIXME: worker thread should not depend on control functionality
#include "usb_moded-control.h"

#include <sys/types.h>
#include <sys/eventfd.h>

#include <pthread.h> // NOTRIM
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pwd.h>

/* ========================================================================= *
* Types
* ========================================================================= */

/** Device mounting state */
typedef enum {
/** Mountpoint state can't be determined */
DEVSTATE_UNKNOWN,
/** Mountpoint does not exist */
DEVSTATE_UNMOUNTED,
/** Mountpoint does exist */
DEVSTATE_MOUNTED,
} devstate_t;

static const char * const devstate_name[] = {
[DEVSTATE_UNKNOWN] = "unknown",
[DEVSTATE_UNMOUNTED] = "unmounted",
[DEVSTATE_MOUNTED] = "mounted",
};

/* ========================================================================= *
* Prototypes
Expand All @@ -51,6 +76,9 @@

static bool worker_thread_p (void);
bool worker_bailing_out (void);
static devstate_t worker_get_mtp_device_state (void);
static void worker_unmount_mtp_device (void);
static bool worker_mount_mtp_device (void);
static bool worker_mode_is_mtp_mode (const char *mode);
static bool worker_is_mtpd_running (void);
static bool worker_mtpd_running_p (void *aptr);
Expand Down Expand Up @@ -143,6 +171,113 @@ worker_bailing_out(void)
!worker_bailout_handled);
}

/* ------------------------------------------------------------------------- *
* MTP_DEVICE
* ------------------------------------------------------------------------- */

/** Check if mtp device is mounted
*
* Returns DEVSTATE_MOUNTED / DEVSTATE_UNMOUNTED depending
* on whether control endpoint file exists in the mtp device
* directory.
*
* Note: If mtp device directory is for some reason not accessible by
* uid=root processes and usb-moded does not have suitable DAC
* override permissions existance of the control endpoint file
* might not be determinable. In these cases DEVSTATE_UNKNOWN
* is returned and it is left up to the caller how to handle
* such uncertainty.
*
* @return DEVSTATE_UNMOUNTED,
* DEVSTATE_MOUNTED, or
* DEVSTATE_UNKNOWN
*/
static devstate_t
worker_get_mtp_device_state(void)
{
LOG_REGISTER_CONTEXT;

devstate_t state = DEVSTATE_UNKNOWN;

if( access("/dev/mtp/ep0", F_OK) == 0 )
state = DEVSTATE_MOUNTED;
else if( errno == ENOENT )
state = DEVSTATE_UNMOUNTED;
else
log_warning("/dev/mtp/ep0: %m");

log_debug("mtp device state = %s", devstate_name[state]);
return state;
}

/** Unmount mtp device
*/
static void
worker_unmount_mtp_device(void)
{
LOG_REGISTER_CONTEXT;

if( worker_get_mtp_device_state() != DEVSTATE_UNMOUNTED ) {
log_debug("unmounting mtp device");
common_system("/bin/umount /dev/mtp");
}
}

/** Mount mtp device
*
* Mount mtp device so that it is accessible by root and the
* currently active user.
*
* @return true if mtp device was mounted as result of call, false otherwise
*/
static bool
worker_mount_mtp_device(void)
{
LOG_REGISTER_CONTEXT;

bool mounted = false;

/* Fail if control endpoint is already present */
if( worker_get_mtp_device_state() != DEVSTATE_UNMOUNTED ) {
log_err("mtp device already mounted");
goto EXIT;
}

/* Probe currently active user for uid/gid info. In case these
* can't be obtained, use values for default user as fallback. */
gid_t gid = 100000;
uid_t uid = control_get_current_user();
if( uid == UID_UNKNOWN )
uid = 100000;

struct passwd *pw = getpwuid(uid);
if( pw )
gid = pw->pw_gid;

/* Attempt to mount mtp device using root uid and primary
* gid of the current user.
*/
char cmd[256];
snprintf(cmd, sizeof cmd,
"/bin/mount -o mode=0770,uid=0,gid=%u -t functionfs mtp /dev/mtp",
(unsigned)gid);

log_debug("mounting mtp device");
if( common_system(cmd) != 0 )
goto EXIT;

/* Check that control endpoint is present */
if( worker_get_mtp_device_state() != DEVSTATE_MOUNTED ) {
log_err("mtp control not mounted");
goto EXIT;
}

mounted = true;

EXIT:
return mounted;
}

/* ------------------------------------------------------------------------- *
* MTP_DAEMON
* ------------------------------------------------------------------------- */
Expand Down Expand Up @@ -588,8 +723,12 @@ worker_switch_to_mode(const char *mode)

/* Either mtp daemon is not needed, or it must be *started* in
* correct phase of gadget configuration when entering mtp mode.
*
* Similarly, unmount mtp device to make sure sure it gets mounted
* with appropriate uid/gid values when it is actually needed.
*/
worker_stop_mtpd();
worker_unmount_mtp_device();

if( worker_get_usb_mode_data() ) {
modesetting_leave_dynamic_mode();
Expand Down Expand Up @@ -624,6 +763,8 @@ worker_switch_to_mode(const char *mode)
/* When dealing with configfs, we can't enable UDC without
* already having mtpd running */
if( worker_mode_is_mtp_mode(mode) && configfs_in_use() ) {
if( !worker_mount_mtp_device() )
goto FAILED;
if( !worker_start_mtpd() )
goto FAILED;
}
Expand All @@ -638,6 +779,8 @@ worker_switch_to_mode(const char *mode)
* we can start mtpd. Assumption is that the same applies
* when using kernel modules. */
if( worker_mode_is_mtp_mode(mode) && !configfs_in_use() ) {
if( !worker_mount_mtp_device() )
goto FAILED;
if( !worker_start_mtpd() )
goto FAILED;
}
Expand Down

0 comments on commit cd0c7e4

Please sign in to comment.