⬆️ ⬇️

Add support for Windows mount balloon in Android

I recently bought a Samsung Galaxy Tab Pro 10.1 LTE SM-T525 tablet and wanted to watch movies and other files from my network drive shared via samba at home. To do this, the kernel must have support for CIFS and not only ... in android since version 4.2 this turned out to be a non-trivial task.



1. The essence of the problem with custom mounts



The fact is that since version 4.2, Adnroid introduced multi-user mode and with it all file systems are mounted as Slave, this leads to the fact that the file system mounted by one user is not visible to other users.

In the Dalvik virtual machine, the android from version 4.2 has the following code in the vm / Init.cpp file:

if (mount("rootfs", "/", NULL, (MS_SLAVE | MS_REC), NULL) == -1) { SLOGE("Failed to mount() rootfs as MS_SLAVE: %s", strerror(errno)); return -1; } 




This code mounts the root file system with the MS_SLAVE and MS_REC flags, this means that the file systems mounted inside / will also be mounted by default with the MS_SLAVE flag and are available only to users of their mounted and their child processes. To solve this problem, the following patch for the kernel in the do_mount function was proposed by the user mkasick with xda-developers:

 --- kernel_orig/fs/namespace.c 2014-01-23 15:34:18.000000000 +1100 +++ kernel/fs/namespace.c 2014-04-11 15:18:22.258114000 +1100 @@ -2141,6 +2141,21 @@ if (data_page) ((char *)data_page)[PAGE_SIZE - 1] = 0; +#ifdef CONFIG_RESTRICT_ROOTFS_SLAVE + /* Check if this is an attempt to mark "/" as recursive-slave. */ + if (strcmp(dir_name, "/") == 0 && flags == (MS_SLAVE | MS_REC)) { + static const char storage[] = "/storage"; + long res; + /* Mark /storage as recursive-slave instead. */ + if ((res = do_mount(NULL, (char *)storage, NULL, (MS_SLAVE | MS_REC), NULL)) == 0) { + return 0; + } else { + pr_warn("Failed to mount %s as MS_SLAVE: %ld\n", storage, res); + } + /* Fallback: Mark rootfs as recursive-slave as requested. */ + } +#endif + /* ... and get the mountpoint */ retval = kern_path(dir_name, LOOKUP_FOLLOW, &path); if (retval) 


The essence of the patch is that we intercept the do_mount call for / with the MS_SVALE and MS_REC flags and do not allow them to be set. But for the work of the android, these flags are necessary for user file systems in / storage, otherwise my system simply does not boot. Therefore, we call do_mount (NULL, (char *) storage, NULL, (MS_SLAVE | MS_REC), NULL)) == 0). For the last call to work, / storage should be a mount point, not just a directory, so in the init.rc file in the ramdisk where the / storage directory is being created, you need to mount tmpfs there

 mkdir /storage 0050 root sdcard_r mount tmpfs tmpfs /storage mode=0050,uid=0,gid=1028 


After these manipulations, the mount points outside / storage will be visible to all users.

')

2. Building the kernel



First you need to add support for CIFS in the Linux kernel. This can be done in two ways: compile the module for the cifs core, or add cifs support to the core itself. The first way is better, because It will not be necessary to flash the new core and lose the warranty on some devices.

The core of my tablet turned out to be assembled without the support of modules, so I had to reassemble and flash the new kernel:

To build the kernel you need:

a) Linux machine

b) kernel sources for your device, for Samsung we take here opensource.samsung.com

c) Toolchain for build, take developer.android.com/tools/sdk/ndk/index.html here

To build the kernel, create the ~ / android directory, and unpack the kernel sources inside it into the kernel, android-ndk directory in android-ndk-r9

 mkdir ~/android cd ~/android tar xjf android-ndk-r9d-linux-x86_64.tar.bz2 unzip SM-T525_SEA_KK_Opensource.zip mkdir kernel cd kernel tar xzf ../Kernel.tar.gz 


Now apply the patch to fix the problem with empty mount points.

shared_rootfs.patch
 --- kernel_orig/fs/namespace.c 2014-01-23 15:34:18.000000000 +1100 +++ kernel/fs/namespace.c 2014-04-11 15:18:22.258114000 +1100 @@ -2141,6 +2141,21 @@ if (data_page) ((char *)data_page)[PAGE_SIZE - 1] = 0; +#ifdef CONFIG_RESTRICT_ROOTFS_SLAVE + /* Check if this is an attempt to mark "/" as recursive-slave. */ + if (strcmp(dir_name, "/") == 0 && flags == (MS_SLAVE | MS_REC)) { + static const char storage[] = "/storage"; + long res; + /* Mark /storage as recursive-slave instead. */ + if ((res = do_mount(NULL, (char *)storage, NULL, (MS_SLAVE | MS_REC), NULL)) == 0) { + return 0; + } else { + pr_warn("Failed to mount %s as MS_SLAVE: %ld\n", storage, res); + } + /* Fallback: Mark rootfs as recursive-slave as requested. */ + } +#endif + /* ... and get the mountpoint */ retval = kern_path(dir_name, LOOKUP_FOLLOW, &path); if (retval) --- kernel_orig/fs/Kconfig 2014-01-23 15:34:17.000000000 +1100 +++ kernel/fs/Kconfig 2014-04-10 19:29:30.990114000 +1100 @@ -292,4 +292,29 @@ source "fs/nls/Kconfig" source "fs/dlm/Kconfig" +config RESTRICT_ROOTFS_SLAVE + bool "Android: Restrict rootfs slave mountspace to /storage" + help + Restrict slave mountspace so Dalvik apps can mount system-wide volumes + + Android 4.2 implements multi-user storage using per-process mount + namespaces. Everything under "/" (the entire filesystem hierarchy) is + marked as a recursive-slave mountspace for all zygote instances. This is + done so that user-storage sandbox mounts under /storage/emulated are hidden + from other apps and users. Unfortunately this means that any Dalvik app + (actually, any program whose clone/fork ancestry includes a Dalvik zygote, + which is everything except services spawned directly from init) cannot + mount system-wide volumes. + + This option restricts rootfs-slave calls to /storage (and + /mnt/shell/emulated) so that Dalvik apps can mount system-wide volumes + elsewhere (with appropriate permission, as in earlier versions of Android), + while retaining full multi-user storage compatibility. It is made + available as a kernel-based workaround for instances where libdvm can not + be modified. + + This option requires that a tmpfs volume is mounted as /storage in + Android init.rc. If this volume is unavailable, then we fall back to the + previous behavior of marking the entire filesystem hierarchy as slave. + endmenu 




 patch -p1 < shared_rootfs.patch 


Next, you need to register the environment variables and prepare the kernel configuration file, for my Samsung it is done like this:

 export CROSS_COMPILE="~/android/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/arm-linux-androideabi-" export ARCH="arm" make mrproper make VARIANT_DEFCONFIG=msm8974_sec_picassoeur_defconfig msm8974_sec_defconfig SELINUX_DEFCONFIG=selinux_defconfig 


This command will create a .config file, then you need to run the command make menuconfig and go to File Systems -> Network File Systems section and check the CIFS support item (in case of module assembly, you must mark M) and check RESTRICT_ROOTFS_SLAVE in File Systems



Next, exit the Esc key and save the configuration. Now we assemble the kernel with the command make -j3 (instead of the number 3 we indicate the number of processor cores + 1)

This completes the kernel build.



3. Build boot.img for firmware



Now you need to flash the new kernel into the tablet. To do this, you need to collect the boot.img image that includes the kernel, ramdisk and device tree for Qualcomm chips.

First we need to get the native ramdisk, for this we unpack the original firmware (this is the usual tar) and get the boot.img file from there

 tar xf T525XXUANB2_T525SERANA6_T525XXUANA7_HOME.tar.md5 boot.img 


For unpacking boot.img you will need a package bootimg_tools

Download it to ~ / android, and unpack the boot.img file with the split_boot command

 mkdir ~/adndroid/bootimg_tools cd ~/adnroid/bootimg_tools unzip ../bootimg_tools_7.8.13.zip ./split_boot ../boot.img 


and we get the unpacked ramdisk in the boot / ramdisk directory

Now you need to fix a couple of files in the ramdisk to transfer Selinux to permissive mode and to mount / storage as tmpfs

In the file init.rc, we search for the line setsebool debugfs 1 and replace it with

 setsebool debugfs 0 setenforce 0 


Next, look for the line setprop selinux.reload_policy 1 and change it to setprop selinux.reload_policy 0

To mount / storage as tmpfs, look for the mkdir / storage 0751 root sdcard_r line and add it after it

 mount tmpfs tmpfs /storage mode=0050,uid=0,gid=1028 


Also in the defaul.prop file we change ro.secure = 1 to ro.secure = 0 and ro.adb.secure = 1 to ro.adb.secure = 0



Now we collect ramdisk back

 ./repack_ramdisk boot/ramdisk ramdisk.cpio.gz cp boot/ramdisk.cpio.gz ~/android/kernel 


Next, we still need the dt.img file for the build, it is generated by the dtbTool utility that comes with the kernel

 cd ~/android/kernel ./tools/dtbTool -o dt.img -s 2048 -p ./scripts/dtc/ ./arch/arm/boot/ 


Now that we have everything we need to build boot.img, we start the build itself using the mkbootimg utility (it also ships with the kernel)

 ./tools/mkbootimg --kernel ./arch/arm/boot/zImage --ramdisk ramdisk.cpio.gz --cmdline 'console=null androidboot.hardware=qcom user_debug=31 msm_rtb.filter=0x37 ehci-hcd.park=3' --base 0x00000000 --pagesize 2048 --ramdisk_offset 0x02000000 --tags_offset 0x01E00000 --dt dt.img -o boot.img 


Everything, the boot.img file is ready. To flash it through Odin, we make boot.tar.md5 out of it.

 tar -H ustar -c boot.img > boot.tar md5sum -t boot.tar >> boot.tar mv boot.tar boot.tar.md5 


Now flashing it through Odin





On Samsung, there is a problem that wifi stops working with the atomic core, this is treated by editing the build.prop file on the working system. You must replace ro.securestorage.support = true with ro.securestorage.support = false



4. Configuring Mount Software



To mount the ball we will use the program CifsManager







There are a few nuances in the setup:

a) In the cifs on the 3.4 kernel something broke, and now it does not handle the device parameter of the mount command, i.e. view construction

mount -t cifs //pc/share /mnt no longer works, the mounted ball must be specified in the unc parameter, i.e. The previous command will look like this:

 mount -t cifs -o unc=\\\\pc\\share none /mnt 


b) Now about the mount point. As stated above, if we mount inside / storage, then such a ball will be empty for other applications, if mounted somewhere outside / storage, then most applications will not be able to open it, because allow you to open files only inside the memory card. There is an exit. Internal memory / storage / emulated / 0 actually lies in / data / media / 0, and / storage / emulated / 0 is emulation of fat32 for this directory. So we can safely mount for example in / data / media / 0 / cifs and see our ball in the file manager in internal storage.

c) There is still no clue described anywhere; for some reason, the mount -t cifs command ignores parameters following the password, for example, in the command

 mount -t cifs -o unc=\\\\pc\\share,username=user,password=123,sec=ntlmssp none /data/media/0/cifs 


sec = ntlmssp will not be processed. Therefore, if a password is required to connect to the balloon, then in the CifsManager, the Password field is left blank, and the password is written in the Options field at the very end, as in the screenshot above.

d) To work correctly with Russian letters in file names, you need to add the option iocharset = utf8



Now we mount the ball in CifsManager and enjoy!



Used materials from the following sources:

www.ibm.com/developerworks/ru/library/l-mount-namespaces

forum.xda-developers.com/showthread.php?p=36889027

www.netzgewitter.com/2013/10/troubleshoot-cifs-on-android

Source: https://habr.com/ru/post/220309/



All Articles