Skip to content

Commit

Permalink
suid and apparmor support in linux
Browse files Browse the repository at this point in the history
 The newer Ryzen controller does not like to be run as root
 (sandbox complain). Better run the application as a normal user
 and let the user space binary run as root if launched via the ryzen
 controller app and user bellongs to the ryzenadj group.
  • Loading branch information
joka90 committed Aug 28, 2022
1 parent 4893bb5 commit d55ed19
Show file tree
Hide file tree
Showing 8 changed files with 206 additions and 0 deletions.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,31 @@ The simplest way to build it:
cmake -DCMAKE_BUILD_TYPE=Release ..
make

modify permissions for executing as root when started from Ryzen controller
and user belongs to the ryzenadj group.

sudo chow root:root ./ryzenadj
sudo chmod u+s ./ryzenadj

add system group for RyzenAdj authentication

getent group ryzenadj || sudo addgroup --quiet --system ryzenadj

add allowed users to ryzenadj group

sudo usermod -aG ryzenadj $USER

### Package build

On Debian/Ubuntu:

dpkg-buildpackage -us -uc
sudo dpkg -i ../ryzenadj_*.deb ../libryzenadj0_*.deb

add allowed users to ryzenadj group

sudo usermod -aG ryzenadj $USER

### Windows

It can be built by Visual Studio + MSVC automaticaly, or Clang + Nmake in command line.
Expand Down
49 changes: 49 additions & 0 deletions debian/apparmor/usr.bin.ryzenadj
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
abi <abi/3.0>,

include <tunables/global>

/usr/bin/ryzenadj flags=(enforce) {
include <abstractions/base>
include <abstractions/consoles>
include <abstractions/nameservice>
include if exists <local/usr.bin.ryzenadj>

capability sys_admin,
capability sys_rawio,

# Needed for some files in /proc see
# https://gitlab.com/apparmor/apparmor/-/wikis/TechnicalDoc_Proc_and_ptrace#apparmor-3-with-ptrace-rules
# https://bugs.launchpad.net/ubuntu/+source/gpsd/+bug/1872175
capability sys_ptrace,
ptrace read peer=unconfined,

/etc/ld.so.cache r,
/lib/@{multiarch}/ld-*.so* mr,
/lib/@{multiarch}/libc-*.so* mr,
/lib/@{multiarch}/libgcc_s.so* mr,
/lib/@{multiarch}/libld-*.so* mr,
/lib/libgcc_s.so* mr,
/lib{,32,64}/ld-*.so* mr,
/lib{,32,64}/libc-*.so* mr,
/lib{,32,64}/libld-*.so* mr,
/usr/bin/ryzenadj mr,
/usr/lib/@{multiarch}/libpci.so* mr,
/usr/lib/@{multiarch}/libudev.so* mr,
/usr/lib/@{multiarch}/libz.so* mr,
/usr/lib/libpci.so* mr,
/usr/lib/libudev.so* mr,
/usr/lib/libz.so* mr,
@{PROC}/ r,
@{PROC}/[0-9]*/ r,
@{PROC}/[0-9]*/exe r,

@{sys}/kernel/ryzen_smu_drv/pm_table r,
/dev/mem r,

@{sys}/devices/pci0000:00/0000:00:00.0/class r,
@{sys}/devices/pci0000:00/0000:00:00.0/config rw,
@{sys}/devices/pci0000:00/0000:00:00.0/device r,
@{sys}/devices/pci0000:00/0000:00:00.0/resource r,
@{sys}/devices/pci0000:00/0000:00:00.0/vendor r,

}
2 changes: 2 additions & 0 deletions debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Maintainer: Johan Källström <[email protected]>
Uploaders: Johan Källström <[email protected]>,
Build-Depends: cmake (>= 3.0~),
debhelper-compat (= 13),
dh-apparmor,
libpci-dev
Standards-Version: 4.6.0
Homepage: https://github.com/FlyGoat/RyzenAdj/
Expand All @@ -18,6 +19,7 @@ Architecture: any
Depends: ${misc:Depends},
${shlibs:Depends},
libryzenadj0 (= ${binary:Version}),
Pre-Depends: adduser (>= 3.11),
Description: Adjust power management settings for Ryzen Mobile Processors.
This is a commandline tool that allows you to adjust power management
settings for Ryzen Mobile Processors.
Expand Down
5 changes: 5 additions & 0 deletions debian/rules
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ override_dh_auto_configure:
dh_auto_configure -- \
-DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) \
-DCMAKE_BUILD_TYPE=RelWithDebInfo


override_dh_install:
dh_install
dh_apparmor -p ryzenadj --profile-name=usr.bin.ryzenadj
1 change: 1 addition & 0 deletions debian/ryzenadj.install
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
usr/bin/ryzenadj
debian/apparmor/usr.bin.ryzenadj etc/apparmor.d
14 changes: 14 additions & 0 deletions debian/ryzenadj.postinst
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/sh
# postinst script for #PACKAGE#

case "$1" in
configure)
# Set setuid root on usr/bin/ryzenadj
chmod u+s /usr/bin/ryzenadj || ( echo 'Error: failed to setuid root on usr/bin/ryzenadj' >&2 )
;;

*)
;;
esac

#DEBHELPER#
18 changes: 18 additions & 0 deletions debian/ryzenadj.preinst
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/sh
# preinst script for #PACKAGE#
set -e
RYZENADJ_GROUP=ryzenadj

case "$1" in
install|upgrade)
# create group for authenticating users.
if ! getent group $RYZENADJ_GROUP 2>&1 >/dev/null ; then
echo "Adding group $RYZENADJ_GROUP.."
addgroup --quiet --system $RYZENADJ_GROUP
fi
;;
*)
;;
esac

#DEBHELPER#
99 changes: 99 additions & 0 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
/* Ryzen NB SMU Service Request Tool */

#include <string.h>

#ifndef _WIN32
#include <unistd.h>
#include <grp.h>
#include <pwd.h>
#endif

#include "lib/ryzenadj.h"
#include "argparse.h"

Expand Down Expand Up @@ -181,6 +188,90 @@ static void show_table_dump(ryzen_access ry, int any_adjust_applied)
//don't free current_table_values because this would deinitialize our table
}

// Check if launched from ryzen-controller
static int check_parent() {
#ifndef _WIN32
pid_t ppid = getppid();
char pathname[512];
char buf[512];
char gt[38] = "/opt/Ryzen Controller/ryzen-controller";
int cx;
cx = snprintf(pathname, 512, "/proc/%d/exe", ppid);

if (cx >= 0 && cx < 512) {
ssize_t l = readlink(pathname, buf, 512);
if (l > 0) {
if (strncmp(buf, gt, 38) == 0) {
return 1;
}
}
}
#endif
return 0;
}

// Are we launched via a root user?
static int is_user_root() {
#ifndef _WIN32
uid_t uid = getuid();
return uid == 0;
#else
return 1;
#endif
}

// Are we in ryzenadj group?
static int is_in_ryzenadj_group() {
#ifndef _WIN32
int ngroups = 0;
uid_t uid;
struct passwd *pw;
struct group *gr_allow;
gr_allow = getgrnam("ryzenadj");

if (gr_allow == NULL) {
fprintf(stderr, "getgrnam(ryzenadj): group does not exsist\n");
return 0;
}

uid = getuid();
pw = getpwuid(uid);
if (pw == NULL) {
fprintf(stderr, "getpwuid(uid): failed\n");
exit(EXIT_FAILURE);
}

/* Retrieve ngroups. */
getgrouplist(pw->pw_name, pw->pw_gid, NULL, &ngroups);

gid_t *groups = malloc(sizeof(*groups) * ngroups);
if (groups == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}

/* Retrieve group list. */
if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups) == -1) {
fprintf(stderr, "getgrouplist() failed; ngroups = %d\n", ngroups);
exit(EXIT_FAILURE);
}

/* Check if we are in allowed group */
int found = 0;
for (int i = 0; i < ngroups; ++i) {
if (gr_allow->gr_gid == groups[i]) {
found = 1;
break;
}
}
free(groups);
return found;
#else
return 1;
#endif
}



int main(int argc, const char **argv)
{
Expand All @@ -198,6 +289,14 @@ int main(int argc, const char **argv)
uint32_t skin_temp_power_limit = -1;
uint32_t gfx_clk = -1, oc_clk = -1, oc_volt = -1, coall = -1, coper = -1, cogfx = -1;

// Check if we run are lauched root or launched from ryzen-controller
// and the user is in the ryzenadj group. Exit if user is not not.
// As we want to limit the setuid bit capabilities.
if (!(is_user_root() || (check_parent() && is_in_ryzenadj_group()))) {
printf("Need root for ryzenadj\n");
return -1;
}

//create structure for parseing
struct argparse_option options[] = {
OPT_HELP(),
Expand Down

0 comments on commit d55ed19

Please sign in to comment.