Skip to content

Commit adea841

Browse files
sabamdarifblurb-it[bot]mhsmith
authored
gh-152936: Make privileged functions available on Android (#152977)
Expose the chroot, initgroups, setegid, seteuid, setgid, sethostname, setregid, setresgid, setresuid, setreuid, and setuid functions on Android. Previously, these methods were excluded by an autoconf guard; they're now included with a permission check to prevent issues invoking them as a non-root user. Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Malcolm Smith <smith@chaquo.com>
1 parent 2638785 commit adea841

9 files changed

Lines changed: 166 additions & 23 deletions

File tree

Doc/library/os.rst

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -574,10 +574,13 @@ process and user.
574574
the groups of which the specified username is a member, plus the specified
575575
group id.
576576

577-
.. availability:: Unix, not WASI, not Android.
577+
.. availability:: Unix, not WASI.
578578

579579
.. versionadded:: 3.2
580580

581+
.. versionchanged:: 3.16
582+
Support for Android now exists.
583+
581584

582585
.. function:: putenv(key, value, /)
583586

@@ -610,21 +613,30 @@ process and user.
610613

611614
Set the current process's effective group id.
612615

613-
.. availability:: Unix, not WASI, not Android.
616+
.. availability:: Unix, not WASI.
617+
618+
.. versionchanged:: 3.16
619+
Support for Android now exists.
614620

615621

616622
.. function:: seteuid(euid, /)
617623

618624
Set the current process's effective user id.
619625

620-
.. availability:: Unix, not WASI, not Android.
626+
.. availability:: Unix, not WASI.
627+
628+
.. versionchanged:: 3.16
629+
Support for Android now exists.
621630

622631

623632
.. function:: setgid(gid, /)
624633

625634
Set the current process' group id.
626635

627-
.. availability:: Unix, not WASI, not Android.
636+
.. availability:: Unix, not WASI.
637+
638+
.. versionchanged:: 3.16
639+
Support for Android now exists.
628640

629641

630642
.. function:: setgroups(groups, /)
@@ -718,32 +730,44 @@ process and user.
718730

719731
Set the current process's real and effective group ids.
720732

721-
.. availability:: Unix, not WASI, not Android.
733+
.. availability:: Unix, not WASI.
734+
735+
.. versionchanged:: 3.16
736+
Support for Android now exists.
722737

723738

724739
.. function:: setresgid(rgid, egid, sgid, /)
725740

726741
Set the current process's real, effective, and saved group ids.
727742

728-
.. availability:: Unix, not WASI, not Android, not macOS, not iOS.
743+
.. availability:: Unix, not WASI, not macOS, not iOS.
729744

730745
.. versionadded:: 3.2
731746

747+
.. versionchanged:: 3.16
748+
Support for Android now exists.
749+
732750

733751
.. function:: setresuid(ruid, euid, suid, /)
734752

735753
Set the current process's real, effective, and saved user ids.
736754

737-
.. availability:: Unix, not WASI, not Android, not macOS, not iOS.
755+
.. availability:: Unix, not WASI, not macOS, not iOS.
738756

739757
.. versionadded:: 3.2
740758

759+
.. versionchanged:: 3.16
760+
Support for Android now exists.
761+
741762

742763
.. function:: setreuid(ruid, euid, /)
743764

744765
Set the current process's real and effective user ids.
745766

746-
.. availability:: Unix, not WASI, not Android.
767+
.. availability:: Unix, not WASI.
768+
769+
.. versionchanged:: 3.16
770+
Support for Android now exists.
747771

748772

749773
.. function:: getsid(pid, /)
@@ -766,7 +790,10 @@ process and user.
766790

767791
Set the current process's user id.
768792

769-
.. availability:: Unix, not WASI, not Android.
793+
.. availability:: Unix, not WASI.
794+
795+
.. versionchanged:: 3.16
796+
Support for Android now exists.
770797

771798

772799
.. placed in this section since it relates to errno.... a little weak
@@ -2324,11 +2351,14 @@ features:
23242351

23252352
Change the root directory of the current process to *path*.
23262353

2327-
.. availability:: Unix, not WASI, not Android.
2354+
.. availability:: Unix, not WASI.
23282355

23292356
.. versionchanged:: 3.6
23302357
Accepts a :term:`path-like object`.
23312358

2359+
.. versionchanged:: 3.16
2360+
Support for Android now exists.
2361+
23322362

23332363
.. function:: fchdir(fd)
23342364

Doc/library/socket.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1372,10 +1372,13 @@ The :mod:`!socket` module also offers various network-related services:
13721372

13731373
.. audit-event:: socket.sethostname name socket.sethostname
13741374

1375-
.. availability:: Unix, not Android.
1375+
.. availability:: Unix.
13761376

13771377
.. versionadded:: 3.3
13781378

1379+
.. versionchanged:: 3.16
1380+
Support for Android now exists.
1381+
13791382

13801383
.. function:: if_nameindex()
13811384

Doc/whatsnew/3.16.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,14 @@ os
474474
process via a pidfd. Available on Linux 5.6+.
475475
(Contributed by Maurycy Pawłowski-Wieroński in :gh:`149464`.)
476476

477+
* The following functions are now available on Android:
478+
:func:`os.chroot`, :func:`os.initgroups`, :func:`os.setegid`,
479+
:func:`os.seteuid`, :func:`os.setgid`, :func:`os.setregid`,
480+
:func:`os.setresgid`, :func:`os.setresuid`, :func:`os.setreuid`,
481+
and :func:`os.setuid`. Calling them without sufficient privileges
482+
now raises :exc:`PermissionError` instead of the functions being unavailable.
483+
(Contributed by Md Arif in :gh:`152936`.)
484+
477485

478486
pydoc
479487
-----
@@ -513,6 +521,15 @@ shlex
513521
(Contributed by Jay Berry in :gh:`148846`.)
514522

515523

524+
socket
525+
------
526+
527+
* The :func:`socket.sethostname` function is now available on Android.
528+
Calling it without sufficient privileges now raises :exc:`PermissionError`
529+
instead of the function being unavailable.
530+
(Contributed by Md Arif in :gh:`152936`.)
531+
532+
516533
sqlite3
517534
-------
518535

Lib/test/test_os/test_posix.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ def test_getresgid(self):
107107
@unittest.skipUnless(hasattr(posix, 'setresuid'),
108108
'test needs posix.setresuid()')
109109
def test_setresuid(self):
110+
# Android blocks this function for non-root users regardless of the arguments.
111+
if support.is_android and os.getuid() != 0:
112+
self.assertRaises(PermissionError, posix.setresuid, -1, -1, -1)
113+
return
110114
current_user_ids = posix.getresuid()
111115
self.assertIsNone(posix.setresuid(*current_user_ids))
112116
# -1 means don't change that value.
@@ -124,6 +128,10 @@ def test_setresuid_exception(self):
124128
@unittest.skipUnless(hasattr(posix, 'setresgid'),
125129
'test needs posix.setresgid()')
126130
def test_setresgid(self):
131+
# Android blocks this function for non-root users regardless of the arguments.
132+
if support.is_android and os.getuid() != 0:
133+
self.assertRaises(PermissionError, posix.setresgid, -1, -1, -1)
134+
return
127135
current_group_ids = posix.getresgid()
128136
self.assertIsNone(posix.setresgid(*current_group_ids))
129137
# -1 means don't change that value.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
:func:`os.chroot`, :func:`os.initgroups`, :func:`os.setegid`,
2+
:func:`os.seteuid`, :func:`os.setgid`, :func:`os.setregid`,
3+
:func:`os.setresgid`, :func:`os.setresuid`, :func:`os.setreuid`,
4+
:func:`os.setuid`, and :func:`socket.sethostname` are now available on
5+
Android. Calling them without sufficient privileges now raises
6+
:exc:`PermissionError` instead of the functions being unavailable.

Modules/posixmodule.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4399,6 +4399,14 @@ static PyObject *
43994399
os_chroot_impl(PyObject *module, path_t *path)
44004400
/*[clinic end generated code: output=de80befc763a4475 input=14822965652c3dc3]*/
44014401
{
4402+
#ifdef __ANDROID__
4403+
// On Android, calling this function as a non-root user leads to a process crash
4404+
// rather than returning a permission error.
4405+
if (getuid() != 0) {
4406+
errno = EPERM;
4407+
return path_error(path);
4408+
}
4409+
#endif
44024410
int res;
44034411
Py_BEGIN_ALLOW_THREADS
44044412
res = chroot(path->narrow);
@@ -9875,6 +9883,14 @@ os_initgroups_impl(PyObject *module, PyObject *oname, gid_t gid)
98759883
/*[clinic end generated code: output=59341244521a9e3f input=7e4514dff4526a95]*/
98769884
#endif
98779885
{
9886+
#ifdef __ANDROID__
9887+
// On Android, calling this function as a non-root user leads to a process crash
9888+
// rather than returning a permission error.
9889+
if (getuid() != 0) {
9890+
errno = EPERM;
9891+
return posix_error();
9892+
}
9893+
#endif
98789894
const char *username = PyBytes_AS_STRING(oname);
98799895

98809896
if (initgroups(username, gid) == -1)
@@ -10301,6 +10317,14 @@ static PyObject *
1030110317
os_setuid_impl(PyObject *module, uid_t uid)
1030210318
/*[clinic end generated code: output=a0a41fd0d1ec555f input=c921a3285aa22256]*/
1030310319
{
10320+
#ifdef __ANDROID__
10321+
// On Android, calling this function as a non-root user leads to a process crash
10322+
// rather than returning a permission error.
10323+
if (getuid() != 0) {
10324+
errno = EPERM;
10325+
return posix_error();
10326+
}
10327+
#endif
1030410328
if (setuid(uid) < 0)
1030510329
return posix_error();
1030610330
Py_RETURN_NONE;
@@ -10322,6 +10346,14 @@ static PyObject *
1032210346
os_seteuid_impl(PyObject *module, uid_t euid)
1032310347
/*[clinic end generated code: output=102e3ad98361519a input=ba93d927e4781aa9]*/
1032410348
{
10349+
#ifdef __ANDROID__
10350+
// On Android, calling this function as a non-root user leads to a process crash
10351+
// rather than returning a permission error.
10352+
if (getuid() != 0) {
10353+
errno = EPERM;
10354+
return posix_error();
10355+
}
10356+
#endif
1032510357
if (seteuid(euid) < 0)
1032610358
return posix_error();
1032710359
Py_RETURN_NONE;
@@ -10343,6 +10375,14 @@ static PyObject *
1034310375
os_setegid_impl(PyObject *module, gid_t egid)
1034410376
/*[clinic end generated code: output=4e4b825a6a10258d input=4080526d0ccd6ce3]*/
1034510377
{
10378+
#ifdef __ANDROID__
10379+
// On Android, calling this function as a non-root user leads to a process crash
10380+
// rather than returning a permission error.
10381+
if (getuid() != 0) {
10382+
errno = EPERM;
10383+
return posix_error();
10384+
}
10385+
#endif
1034610386
if (setegid(egid) < 0)
1034710387
return posix_error();
1034810388
Py_RETURN_NONE;
@@ -10365,6 +10405,14 @@ static PyObject *
1036510405
os_setreuid_impl(PyObject *module, uid_t ruid, uid_t euid)
1036610406
/*[clinic end generated code: output=62d991210006530a input=0ca8978de663880c]*/
1036710407
{
10408+
#ifdef __ANDROID__
10409+
// On Android, calling this function as a non-root user leads to a process crash
10410+
// rather than returning a permission error.
10411+
if (getuid() != 0) {
10412+
errno = EPERM;
10413+
return posix_error();
10414+
}
10415+
#endif
1036810416
if (setreuid(ruid, euid) < 0) {
1036910417
return posix_error();
1037010418
} else {
@@ -10389,6 +10437,14 @@ static PyObject *
1038910437
os_setregid_impl(PyObject *module, gid_t rgid, gid_t egid)
1039010438
/*[clinic end generated code: output=aa803835cf5342f3 input=c59499f72846db78]*/
1039110439
{
10440+
#ifdef __ANDROID__
10441+
// On Android, calling this function as a non-root user leads to a process crash
10442+
// rather than returning a permission error.
10443+
if (getuid() != 0) {
10444+
errno = EPERM;
10445+
return posix_error();
10446+
}
10447+
#endif
1039210448
if (setregid(rgid, egid) < 0)
1039310449
return posix_error();
1039410450
Py_RETURN_NONE;
@@ -10409,6 +10465,14 @@ static PyObject *
1040910465
os_setgid_impl(PyObject *module, gid_t gid)
1041010466
/*[clinic end generated code: output=bdccd7403f6ad8c3 input=27d30c4059045dc6]*/
1041110467
{
10468+
#ifdef __ANDROID__
10469+
// On Android, calling this function as a non-root user leads to a process crash
10470+
// rather than returning a permission error.
10471+
if (getuid() != 0) {
10472+
errno = EPERM;
10473+
return posix_error();
10474+
}
10475+
#endif
1041210476
if (setgid(gid) < 0)
1041310477
return posix_error();
1041410478
Py_RETURN_NONE;
@@ -15506,6 +15570,14 @@ static PyObject *
1550615570
os_setresuid_impl(PyObject *module, uid_t ruid, uid_t euid, uid_t suid)
1550715571
/*[clinic end generated code: output=834a641e15373e97 input=9e33cb79a82792f3]*/
1550815572
{
15573+
#ifdef __ANDROID__
15574+
// On Android, calling this function as a non-root user leads to a process crash
15575+
// rather than returning a permission error.
15576+
if (getuid() != 0) {
15577+
errno = EPERM;
15578+
return posix_error();
15579+
}
15580+
#endif
1550915581
if (setresuid(ruid, euid, suid) < 0)
1551015582
return posix_error();
1551115583
Py_RETURN_NONE;
@@ -15529,6 +15601,14 @@ static PyObject *
1552915601
os_setresgid_impl(PyObject *module, gid_t rgid, gid_t egid, gid_t sgid)
1553015602
/*[clinic end generated code: output=6aa402f3d2e514a9 input=33e9e0785ef426b1]*/
1553115603
{
15604+
#ifdef __ANDROID__
15605+
// On Android, calling this function as a non-root user leads to a process crash
15606+
// rather than returning a permission error.
15607+
if (getuid() != 0) {
15608+
errno = EPERM;
15609+
return posix_error();
15610+
}
15611+
#endif
1553215612
if (setresgid(rgid, egid, sgid) < 0)
1553315613
return posix_error();
1553415614
Py_RETURN_NONE;

Modules/socketmodule.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5988,6 +5988,15 @@ _socket_sethostname(PyObject *module, PyObject *hnobj)
59885988
Py_buffer buf;
59895989
int res, flag = 0;
59905990

5991+
#ifdef __ANDROID__
5992+
// On Android, calling this function as a non-root user leads to a process crash
5993+
// rather than returning a permission error.
5994+
if (getuid() != 0) {
5995+
errno = EPERM;
5996+
return set_error();
5997+
}
5998+
#endif
5999+
59916000
#if defined(_AIX) || (defined(__sun) && defined(__SVR4) && Py_SUNOS_VERSION <= 510)
59926001
/* issue #18259, sethostname is not declared in any useful header file on AIX
59936002
* the same is true for Solaris 10 */

configure

Lines changed: 1 addition & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

configure.ac

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5494,14 +5494,9 @@ else
54945494
fi
54955495

54965496
if test "$ac_sys_system" = "Linux-android"; then
5497-
# When these functions are used in an unprivileged process, they crash rather
5498-
# than returning an error.
5499-
blocked_funcs="chroot initgroups setegid seteuid setgid sethostname
5500-
setregid setresgid setresuid setreuid setuid"
5501-
55025497
# These functions are unimplemented and always return an error
55035498
# (https://android.googlesource.com/platform/system/sepolicy/+/refs/heads/android13-release/public/domain.te#1044)
5504-
blocked_funcs="$blocked_funcs sem_open sem_unlink"
5499+
blocked_funcs="sem_open sem_unlink"
55055500

55065501
# Before API level 23, when fchmodat is called with the unimplemented flag
55075502
# AT_SYMLINK_NOFOLLOW, instead of returning ENOTSUP as it should, it actually

0 commit comments

Comments
 (0)