diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 47e57db0..907fdaee 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -97,8 +97,10 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - + - uses: actions/checkout@v3 + with: # fetch tags for git describe + fetch-depth: 0 + - run: git fetch --tags - name: Install Dependencies run: | sudo apt-get update @@ -113,6 +115,22 @@ jobs: cmake DCMAKE_BUILD_TYPE=Release .. make + - name: Install Debian build Dependencies + run: | + sudo apt-get update + sudo apt-get -y install devscripts equivs dpkg-dev + sudo mk-build-deps -i + + - name: Test debian build + shell: bash + run: | + gcc --version + rm -f debian/changelog.dch + debchange -Mv $(git describe --tags HEAD | cut -f2- -dv) 'CI/CD build' + dpkg-buildpackage -us -uc + mkdir -p out + mv ../*.*deb out/ + - name: Test Scripts shell: bash run: | @@ -131,3 +149,9 @@ jobs: fi exit 0 + - name: Upload ryzenadj Debian + uses: actions/upload-artifact@v3 + with: + name: ryzenadj-ubuntu-focal-amd64 + path: | + ./out/*.*deb diff --git a/.gitignore b/.gitignore index edbd6728..901f5f81 100644 --- a/.gitignore +++ b/.gitignore @@ -348,3 +348,9 @@ ASALocalRun/ healthchecksdb # End of https://www.gitignore.io/api/visualstudio + +# Debian package build +obj-*/ + +# Cmake generated version file +lib/ryzenadj_version.h diff --git a/CMakeLists.txt b/CMakeLists.txt index eadd4ec8..f8bd3d34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,12 +2,17 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.0) #define project name -PROJECT(ryzenadj) +PROJECT(ryzenadj VERSION 0.11.1) set(CMAKE_CXX_STANDARD 11) message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") +configure_file ( + "${PROJECT_SOURCE_DIR}/lib/ryzenadj_version.h.in" + "${PROJECT_SOURCE_DIR}/lib/ryzenadj_version.h" +) + INCLUDE_DIRECTORIES(${INC_DIR}) AUX_SOURCE_DIRECTORY(./ SRC_DIR) @@ -37,4 +42,17 @@ target_link_libraries(${PROJECT_NAME} ${OS_LINK_LIBRARY}) ADD_LIBRARY (libryzenadj SHARED ${OS_SOURCE} ${COMMON_SOURCES}) set_target_properties(libryzenadj PROPERTIES PREFIX "") target_link_libraries(libryzenadj ${OS_LINK_LIBRARY}) -#SET_TARGET_PROPERTIES(libryzenadj PROPERTIES LINKER_LANGUAGE C) +set_target_properties(libryzenadj PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR}) +set_target_properties(libryzenadj PROPERTIES PUBLIC_HEADER "lib/ryzenadj.h;lib/ryzenadj_version.h;lib/nb_smu_ops.h;lib/ryzenadj_priv.h") + +if (UNIX) + include(GNUInstallDirs) + install(TARGETS ${PROJECT_NAME} libryzenadj + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) +endif (UNIX) diff --git a/README.md b/README.md index 95e04713..02534713 100644 --- a/README.md +++ b/README.md @@ -128,6 +128,38 @@ 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 + + setcap 'cap_sys_rawio=ep cap_dac_override=ep cap_sys_admin=ep' ./ryzenadj + +or via the suid bit + + 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: + + sudo apt-get update + sudo apt-get -y install devscripts equivs dpkg-dev + sudo mk-build-deps -i + 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. diff --git a/debian/.gitignore b/debian/.gitignore new file mode 100644 index 00000000..34bbc99a --- /dev/null +++ b/debian/.gitignore @@ -0,0 +1,8 @@ +.debhelper/ +debhelper-build-stamp +files +*.substvars +ryzenadj/ +libryzenadj-dev/ +libryzenadj0/ +tmp/ diff --git a/debian/apparmor/usr.bin.ryzenadj b/debian/apparmor/usr.bin.ryzenadj new file mode 100644 index 00000000..2bae5e99 --- /dev/null +++ b/debian/apparmor/usr.bin.ryzenadj @@ -0,0 +1,53 @@ +abi , + +include + +/usr/bin/ryzenadj flags=(enforce) { + include + include + include + include if exists + + capability sys_admin, + capability sys_rawio, + capability dac_override, + + # Needed for some files in /proc see + # https://gitlab.com/apparmor/apparmor/-/wikis/TechnicalDoc_Proc_and_ptrace#apparmor-3-with-ptrace-rules + # from man proc 5 : + # /proc/[pid]/exe : + # Permission to dereference or read (readlink(2)) this symbolic link is governed by a ptrace access mode + # PTRACE_MODE_READ_FSCREDS check; see ptrace(2). + 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, + +} diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 00000000..d1d7ccf6 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,11 @@ +ryzenadj (0.11.1-1) unstable; urgency=medium + + New revision + + -- Johan Källström Sat, 27 Aug 2022 14:02:53 +0200 + +ryzenadj (0.11.0-1) unstable; urgency=medium + + initial debian package release + + -- Johan Källström Sat, 27 Mar 2022 08:18:45 +0100 diff --git a/debian/compat b/debian/compat new file mode 100644 index 00000000..b4de3947 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +11 diff --git a/debian/control b/debian/control new file mode 100644 index 00000000..105a6e09 --- /dev/null +++ b/debian/control @@ -0,0 +1,47 @@ +Source: ryzenadj +Section: admin +Priority: optional +Maintainer: Johan Källström +Uploaders: Johan Källström , +Build-Depends: cmake (>= 3.0~), + dh-apparmor, + libpci-dev, + debhelper +Standards-Version: 4.6.0 +Homepage: https://github.com/FlyGoat/RyzenAdj/ +Vcs-Browser: https://github.com/FlyGoat/RyzenAdj/ +Vcs-Git: https://github.com/FlyGoat/RyzenAdj.git +Rules-Requires-Root: no + + +Package: ryzenadj +Architecture: any +Depends: ${misc:Depends}, + ${shlibs:Depends}, + libryzenadj0 (= ${binary:Version}), +Pre-Depends: adduser (>= 3.11), + libcap2-bin, +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. + +Package: libryzenadj0 +Architecture: any +Depends: ${misc:Depends}, + ${shlibs:Depends}, +Suggests: ryzen-smu-dkms +Description: power management library for Ryzen Mobile Processors. + This library provides APIs to Adjust power management settings for + Ryzen Mobile Processors. + +Package: libryzenadj-dev +Architecture: any +Depends: ${misc:Depends}, + libryzenadj0 (= ${binary:Version}) +Description: power management library - development files + for Ryzen Mobile Processors. + This library provides APIs to Adjust power management settings for + Ryzen Mobile Processors. + . + This package contains the files needed for developing applications that + use libryzenadj. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 00000000..90a0e61d --- /dev/null +++ b/debian/copyright @@ -0,0 +1,8 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Contact: jiaxun.yang@flygoat.com +Upstream-Name: ryzenadj +Source: https://github.com/FlyGoat/RyzenAdj/ + +Files: * +Copyright: 2019-2022, Jiaxun Yang +License: LGPL-3 diff --git a/debian/libryzenadj-dev.install b/debian/libryzenadj-dev.install new file mode 100644 index 00000000..4f9ded54 --- /dev/null +++ b/debian/libryzenadj-dev.install @@ -0,0 +1,3 @@ +usr/include/* +usr/lib/*/libryzenadj.so + diff --git a/debian/libryzenadj0.install b/debian/libryzenadj0.install new file mode 100644 index 00000000..5ea5d005 --- /dev/null +++ b/debian/libryzenadj0.install @@ -0,0 +1,2 @@ +usr/lib/*/libryzenadj.so.* + diff --git a/debian/rules b/debian/rules new file mode 100755 index 00000000..868d96f2 --- /dev/null +++ b/debian/rules @@ -0,0 +1,19 @@ +#!/usr/bin/make -f + +DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) + +export DEB_BUILD_MAINT_OPTIONS=hardening=+all +export DH_VERBOSE = 1 + +%: + dh $@ + +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 diff --git a/debian/ryzenadj.install b/debian/ryzenadj.install new file mode 100644 index 00000000..f1dbfe3e --- /dev/null +++ b/debian/ryzenadj.install @@ -0,0 +1,2 @@ +usr/bin/ryzenadj +debian/apparmor/usr.bin.ryzenadj etc/apparmor.d diff --git a/debian/ryzenadj.postinst b/debian/ryzenadj.postinst new file mode 100644 index 00000000..c8f89fdb --- /dev/null +++ b/debian/ryzenadj.postinst @@ -0,0 +1,19 @@ +#!/bin/sh +# postinst script for #PACKAGE# + +BINARY=/usr/bin/ryzenadj +case "$1" in + configure) + if which setcap > /dev/null && setcap 'cap_sys_rawio=ep cap_dac_override=ep cap_sys_admin=ep' "$BINARY" ; then + echo "Set setcap on $BINARY successfull" + else + echo "Set setuid root on $BINARY" + chmod u+s "$BINARY" || ( echo "Error: failed to setuid root on $BINARY" >&2 ) + fi + ;; + + *) + ;; +esac + +#DEBHELPER# diff --git a/debian/ryzenadj.preinst b/debian/ryzenadj.preinst new file mode 100644 index 00000000..e0f6197d --- /dev/null +++ b/debian/ryzenadj.preinst @@ -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# diff --git a/lib/ryzenadj.h b/lib/ryzenadj.h index 2dff5d45..8d433432 100644 --- a/lib/ryzenadj.h +++ b/lib/ryzenadj.h @@ -4,14 +4,13 @@ #ifndef RYZENADJ_H #define RYZENADJ_H + +#include "ryzenadj_version.h" + #ifdef __cplusplus extern "C" { #endif -#define RYZENADJ_REVISION_VER 0 -#define RYZENADJ_MAJOR_VER 11 -#define RYZENADJ_MINIOR_VER 1 - enum ryzen_family { FAM_UNKNOWN = -1, FAM_RAVEN = 0, diff --git a/lib/ryzenadj_version.h.in b/lib/ryzenadj_version.h.in new file mode 100644 index 00000000..b8210ef3 --- /dev/null +++ b/lib/ryzenadj_version.h.in @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: LGPL */ +/* Copyright (C) 2019 Jiaxun Yang */ +/* RyzenAdj API Version */ + +#ifndef RYZENADJ_VERSION_H +#define RYZENADJ_VERSION_H +#ifdef __cplusplus +extern "C" { +#endif + +#define RYZENADJ_REVISION_VER @PROJECT_VERSION_MAJOR@ +#define RYZENADJ_MAJOR_VER @PROJECT_VERSION_MINOR@ +#define RYZENADJ_MINIOR_VER @PROJECT_VERSION_PATCH@ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/main.c b/main.c index 25f48348..4de6fcb0 100644 --- a/main.c +++ b/main.c @@ -3,6 +3,13 @@ /* Ryzen NB SMU Service Request Tool */ #include + +#ifndef _WIN32 +#include +#include +#include +#endif + #include "lib/ryzenadj.h" #include "argparse.h" @@ -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) { @@ -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(),