From 5d6e17e57a41071316dfa9a53cd23c85e85ce53e Mon Sep 17 00:00:00 2001 From: kitsunyan Date: Sat, 28 Apr 2018 23:51:52 +0300 Subject: Print error if chdir, setgroups, setuid, or setgid failed --- src/common.nim | 72 ++++++++++++++++++++++++++++----------------- src/feature/syncinstall.nim | 72 ++++++++++++++++++++++++--------------------- src/pacman.nim | 6 ++-- src/utils.nim | 16 +++++++--- 4 files changed, 100 insertions(+), 66 deletions(-) diff --git a/src/common.nim b/src/common.nim index c42cb82..2b9651a 100644 --- a/src/common.nim +++ b/src/common.nim @@ -236,22 +236,29 @@ proc bisectVersion(repoPath: string, debug: bool, firstCommit: Option[string], discard close(1) discard close(2) - dropPrivileges() - execResult(args))) + if dropPrivileges(): + execResult(args) + else: + quit(1))) let (workFirstCommit, checkFirst) = if firstCommit.isSome: (firstCommit, false) else: (forkWaitRedirect(() => (block: - dropPrivileges() - execResult(gitCmd, "-C", repoPath, - "rev-list", "--max-parents=0", "@"))) + if dropPrivileges(): + execResult(gitCmd, "-C", repoPath, + "rev-list", "--max-parents=0", "@") + else: + quit(1))) .output.optLast, true) let (realLastThreeCommits, _) = forkWaitRedirect(() => (block: - dropPrivileges() - execResult(gitCmd, "-C", repoPath, - "rev-list", "--max-count=3", "@"))) + if dropPrivileges(): + execResult(gitCmd, "-C", repoPath, + "rev-list", "--max-count=3", "@") + else: + quit(1))) + let index = workFirstCommit.map(c => realLastThreeCommits.find(c)).get(-1) let lastThreeCommits = if index >= 0: realLastThreeCommits[0 .. index] @@ -266,9 +273,11 @@ proc bisectVersion(repoPath: string, debug: bool, firstCommit: Option[string], none(string) else: let foundVersion = forkWaitRedirect(() => (block: - dropPrivileges() - execResult(pkgLibDir & "/bisect", - compareMethod, repoPath & "/" & gitSubdir, version))) + if dropPrivileges(): + execResult(pkgLibDir & "/bisect", + compareMethod, repoPath & "/" & gitSubdir, version) + else: + quit(1))) .output.optFirst let checkout2Code = forkExecWithoutOutput(gitCmd, "-C", repoPath, @@ -308,9 +317,11 @@ proc bisectVersion(repoPath: string, debug: bool, firstCommit: Option[string], "bisect", "run", pkgLibDir & "/bisect", compareMethod, gitSubdir, version) let commit = forkWaitRedirect(() => (block: - dropPrivileges() - execResult(gitCmd, "-C", repoPath, - "rev-list", "--max-count=1", "refs/bisect/bad"))) + if dropPrivileges(): + execResult(gitCmd, "-C", repoPath, + "rev-list", "--max-count=1", "refs/bisect/bad") + else: + quit(1))) .output.optFirst discard forkExecWithoutOutput(gitCmd, "-C", repoPath, @@ -330,9 +341,10 @@ proc bisectVersion(repoPath: string, debug: bool, firstCommit: Option[string], proc obtainSrcInfo*(path: string): string = let (output, code) = forkWaitRedirect(() => (block: - discard chdir(path) - dropPrivileges() - execResult(makePkgCmd, "--printsrcinfo"))) + if dropPrivileges() and chdir(path) == 0: + execResult(makePkgCmd, "--printsrcinfo") + else: + quit(1))) if code == 0: output.foldl(a & b & "\n", "") @@ -368,10 +380,12 @@ proc obtainBuildPkgInfosInternal(config: Config, bases: seq[LookupBaseGroup], removeDirQuiet(repoPath) if forkWait(() => (block: - dropPrivileges() - execResult(gitCmd, "-C", config.tmpRoot, - "clone", "-q", git.url, "-b", git.branch, - "--single-branch", base))) == 0: + if dropPrivileges(): + execResult(gitCmd, "-C", config.tmpRoot, + "clone", "-q", git.url, "-b", git.branch, + "--single-branch", base) + else: + quit(1))) == 0: let commit = bisectVersion(repoPath, config.debug, none(string), "source", git.path, version) @@ -380,9 +394,11 @@ proc obtainBuildPkgInfosInternal(config: Config, bases: seq[LookupBaseGroup], (newSeq[PackageInfo](), none(string)) else: discard forkWait(() => (block: - dropPrivileges() - execResult(gitCmd, "-C", repoPath, - "checkout", "-q", commit.unsafeGet))) + if dropPrivileges(): + execResult(gitCmd, "-C", repoPath, + "checkout", "-q", commit.unsafeGet) + else: + quit(1))) let srcInfo = obtainSrcInfo(repoPath & "/" & git.path) let pkgInfos = parseSrcInfo(repo, srcInfo, config.arch, @@ -439,8 +455,10 @@ proc cloneAurRepo*(config: Config, basePackages: seq[PackageInfo]): (int, Option raise newException(SystemError, "invalid clone call") else: let cloneCode = forkWait(() => (block: - dropPrivileges() - execResult(gitCmd, "-C", config.tmpRoot, - "clone", "-q", basePackages[0].gitUrl, "--single-branch", base))) + if dropPrivileges(): + execResult(gitCmd, "-C", config.tmpRoot, + "clone", "-q", basePackages[0].gitUrl, "--single-branch", base) + else: + quit(1))) (cloneCode, none(string)) diff --git a/src/feature/syncinstall.nim b/src/feature/syncinstall.nim index 94bb886..4fa5eaa 100644 --- a/src/feature/syncinstall.nim +++ b/src/feature/syncinstall.nim @@ -240,6 +240,17 @@ proc printUnsatisfied(config: Config, trp("unable to satisfy dependency '%s' required by %s\n") % [$reference, pkgInfo.name]) +template dropPrivilegesAndChdir(path: Option[string], body: untyped): int = + if dropPrivileges(): + if path.isNone or chdir(path.unsafeGet) == 0: + body + else: + printError(config.color, tr"chdir failed: $#" % [path.unsafeGet]) + quit(1) + else: + printError(config.color, tr"failed to drop privileges") + quit(1) + proc editLoop(config: Config, base: string, repoPath: string, gitSubdir: Option[string], defaultYes: bool, noconfirm: bool): char = proc editFileLoop(file: string): char = @@ -266,25 +277,25 @@ proc editLoop(config: Config, base: string, repoPath: string, gitSubdir: Option[ if editor.strip.len == 0: 'n' else: - discard forkWait(proc: int = - discard chdir(buildPath(repoPath, gitSubdir)) - dropPrivileges() - execResult(bashCmd, "-c", """$1 "$2"""", "bash", editor, file)) + discard forkWait(() => (block: + let buildPath = buildPath(repoPath, gitSubdir) + dropPrivilegesAndChdir(some(buildPath)): + execResult(bashCmd, "-c", """$1 "$2"""", "bash", editor, file))) editFileLoop(file) else: res let rawFiles = if gitSubdir.isSome: forkWaitRedirect(() => (block: - dropPrivileges() - execResult(gitCmd, "-C", repoPath, "ls-tree", "-r", "--name-only", "@", - gitSubdir.unsafeGet & "/"))) + dropPrivilegesAndChdir(none(string)): + execResult(gitCmd, "-C", repoPath, "ls-tree", "-r", "--name-only", "@", + gitSubdir.unsafeGet & "/"))) .output .map(s => s[gitSubdir.unsafeGet.len + 1 .. ^1]) else: forkWaitRedirect(() => (block: - dropPrivileges() - execResult(gitCmd, "-C", repoPath, "ls-tree", "-r", "--name-only", "@"))) + dropPrivilegesAndChdir(none(string)): + execResult(gitCmd, "-C", repoPath, "ls-tree", "-r", "--name-only", "@"))) .output let files = ("PKGBUILD" & rawFiles.filter(x => x != ".SRCINFO")).deduplicate @@ -338,20 +349,18 @@ proc buildLoop(config: Config, pkgInfos: seq[PackageInfo], noconfirm: bool, let envExt = getEnv("PKGEXT") let confExt = if envExt.len == 0: forkWaitRedirect(() => (block: - dropPrivileges() - execResult(bashCmd, "-c", - "source \"$@\" && echo \"$PKGEXT\"", - "bash", workConfFile))) + dropPrivilegesAndChdir(none(string)): + execResult(bashCmd, "-c", + "source \"$@\" && echo \"$PKGEXT\"", + "bash", workConfFile))) .output.optFirst.get("") else: envExt let (buildCode, interrupted) = catchInterrupt(): forkWait(proc: int = - if chdir(buildPath) == 0: - discard cunsetenv("MAKEPKG_CONF") - dropPrivileges() - + discard cunsetenv("MAKEPKG_CONF") + dropPrivilegesAndChdir(some(buildPath)): if not noextract: removeDirQuiet(buildPath & "src") @@ -361,9 +370,7 @@ proc buildLoop(config: Config, pkgInfos: seq[PackageInfo], noconfirm: bool, ] execResult(@[makepkgCmd, "--config", workConfFile, "-f"] & - optional.filter(o => o.cond).map(o => o.arg)) - else: - quit(1)) + optional.filter(o => o.cond).map(o => o.arg))) discard unlink(workConfFile) @@ -450,9 +457,8 @@ proc buildFromSources(config: Config, commonArgs: seq[Argument], printColon(config.color, tr"Running pre-build command...") let code = forkWait(() => (block: - discard chdir(buildPath(repoPath, gitSubdir)) - dropPrivileges() - execResult(bashCmd, "-c", config.preBuildCommand.unsafeGet))) + dropPrivilegesAndChdir(some(buildPath(repoPath, gitSubdir))): + execResult(bashCmd, "-c", config.preBuildCommand.unsafeGet))) if code != 0 and printColonUserChoice(config.color, tr"Command failed, continue?", ['y', 'n'], 'n', 'n', @@ -665,8 +671,8 @@ proc handleInstall(args: seq[Argument], config: Config, upgradeCount: int, discard open("/dev/null") discard close(2) discard open("/dev/null") - dropPrivileges() - execResult(gpgCmd, "--list-keys", pgpKeys[index]))) == 0: + dropPrivilegesAndChdir(none(string)): + execResult(gpgCmd, "--list-keys", pgpKeys[index]))) == 0: keysLoop(index + 1, skipKeys) else: let res = if skipKeys: @@ -684,14 +690,14 @@ proc handleInstall(args: seq[Argument], config: Config, upgradeCount: int, keysLoop(index, newSkipKeys) elif res == 'y' or newSkipKeys: let importCode = forkWait(() => (block: - dropPrivileges() - if config.pgpKeyserver.isSome: - forkWait(() => execResult(gpgCmd, - "--keyserver", config.pgpKeyserver.unsafeGet, - "--recv-keys", pgpKeys[index])) - else: - forkWait(() => execResult(gpgCmd, - "--recv-keys", pgpKeys[index])))) + dropPrivilegesAndChdir(none(string)): + if config.pgpKeyserver.isSome: + forkWait(() => execResult(gpgCmd, + "--keyserver", config.pgpKeyserver.unsafeGet, + "--recv-keys", pgpKeys[index])) + else: + forkWait(() => execResult(gpgCmd, + "--recv-keys", pgpKeys[index])))) if importCode == 0 or newSkipKeys or noconfirm: keysLoop(index + 1, newSkipKeys) diff --git a/src/pacman.nim b/src/pacman.nim index 05abf51..58bf42b 100644 --- a/src/pacman.nim +++ b/src/pacman.nim @@ -356,8 +356,10 @@ proc obtainPacmanConfig*(args: seq[Argument]): PacmanConfig = x <- y.split(',')), string].toSet let hasKeyserver = forkWaitRedirect(() => (block: - dropPrivileges() - execResult(gpgConfCmd, "--list-options", "gpg"))) + if dropPrivileges(): + execResult(gpgConfCmd, "--list-options", "gpg") + else: + quit(1))) .output .filter(s => s.len > 10 and s[0 .. 9] == "keyserver:" and not (s[^2] == ':')) .len > 0 diff --git a/src/utils.nim b/src/utils.nim index 7cbf184..b480ce9 100644 --- a/src/utils.nim +++ b/src/utils.nim @@ -253,13 +253,17 @@ except: proc canDropPrivileges*(): bool = initialUser.isSome -proc dropPrivileges*() = +proc dropPrivileges*(): bool = if initialUser.isSome: let user = initialUser.unsafeGet var groups = user.groups.map(x => x.cint) - discard setgroups(user.groups.len, addr(groups[0])); - discard setgid((Gid) user.gid) - discard setuid((Uid) user.uid) + + if setgroups(user.groups.len, addr(groups[0])) < 0: + return false + if setgid((Gid) user.gid) != 0: + return false + if setuid((Uid) user.uid) != 0: + return false template replaceExisting(name: string, value: string) = if cgetenv(name) != nil: @@ -277,6 +281,10 @@ proc dropPrivileges*() = discard cunsetenv("SUDO_GID") discard cunsetenv("PKEXEC_UID") + return true + else: + return true + var intSigact: SigAction intSigact.sa_handler = SIG_DFL discard sigaction(SIGINT, intSigact) -- cgit v1.2.3-70-g09d2