Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
[SOLVED] Chown-ed / - How to recover?
View unanswered posts
View posts from last 24 hours

 
Reply to topic    Gentoo Forums Forum Index Other Things Gentoo
View previous topic :: View next topic  
Author Message
piii_man
n00b
n00b


Joined: 18 Jul 2004
Posts: 39

PostPosted: Thu Apr 06, 2023 7:58 am    Post subject: [SOLVED] Chown-ed / - How to recover? Reply with quote

Hi all,

I really goofed and chowned my fs root.

Code:
sudo chown -R piii_man /


I have backups, but of documents and etc files, not a system snapshot. A silver lining to the mistake was that I only chown-ed owner, not group. I was able to reverse most of the damage with a script that chowned files based on file stat info.

Code:
stat.st_ctime > self.ctime_cutoff and stat.st_gid != stat.st_uid and stat.st_uid == self.bad_uid


Where bad_uid is the uid of user piii_man and ctime_cutoff is when I did the chown. The logic was, if the above is true chown the file to gid:gid.

This of course wasn't perfect (i.e. many files don't follow owner:group == group:group), but fixed a lot of the issues. After some other fixes, I have a pretty much working system where I can emerge things, run KDE etc. Looking through my journalctl, some things are definitely broken (FUSE for one). What's a more robust solution here? Can I just emerge -e @world, or will I have to tackle the remaining problems one by one? I would appreciate any insight you have.


Last edited by piii_man on Thu Apr 06, 2023 8:39 pm; edited 1 time in total
Back to top
View user's profile Send private message
alamahant
Advocate
Advocate


Joined: 23 Mar 2019
Posts: 3879

PostPosted: Thu Apr 06, 2023 8:37 am    Post subject: Reply with quote

Hi
Maybe
Code:

emerge -pve @world

ie rebuild ALL packages.
If the above shows it possible then please remove the "p" flag.
But please take a second opinion also.
After doing that you might want to
Code:

sudo chown -R $USER:$USER ~

And if you have other users also chown their home dirs to their names.
I am not sure what to do about

/var/lib/*

ie if you have docker or lxd containers or dbs or data in there.

Also consider your

/boot/*
/lib/modules/*
/usr/src/*

directories but I think you will be fine even with different owner.
If everything restores to its original state then please BACKUP everyday possibly before updating.
I always rsync my whole system to a partition before updating.
_________________
:)
Back to top
View user's profile Send private message
Hu
Administrator
Administrator


Joined: 06 Mar 2007
Posts: 21793

PostPosted: Thu Apr 06, 2023 3:16 pm    Post subject: Reply with quote

It appears that the Portage vdb does not remember ownership. However, Portage binpkgs do remember ownership, so if you have been building tbz2 packages as you install things, you can reinstall from those to save yourself the time of a rebuild. With a bit of cleverness, you could even extract the permissions from the tbz2 and apply them without restoring the file contents.
Back to top
View user's profile Send private message
piii_man
n00b
n00b


Joined: 18 Jul 2004
Posts: 39

PostPosted: Thu Apr 06, 2023 7:30 pm    Post subject: Reply with quote

Alright thanks guys. I just finished an emerge -e. After rebooting, journalctl -b0 looks good. I'll monitor it for any unusual logs. I don't want to bring bad luck, but this was actually less bad than I expected

@alamahant: I'm rethinking my backup strategy. I used to think configs and documents were what was most important, but I've started to value my time a lot more. I believe the script I wrote should cover most of the things you mentioned, but time will tell.

@Hu: That idea gets 10/10 for style points! Ultimately, this is a pretty new desktop so re-emerging the whole system isn't too bad.

Hopefully no one needs this, but for anyone who finds themselves in a similar position, here's the script I wrote. It is a hacky fix to file ownership just to give a mostly working system. It converts recently changed files with bad_uid:not_bad_gid to not_bad_gid:not_bad_gid. To use, modify the script to set set the ctime_cutoff to just before the errant chown and set the bad_uid to the uid you accidently chowned / with. You can run the script with sudo ./unChown.py / --dry-run. It will make a log file with all changes, in the same dir it's run in. If you like the changes, remove the --dry-run flag and re-run. On systems that are making use of lots of users in different groups, this script will make a lot of mistakes.

Code:

#!/usr/bin/python3

import logging
import os
import sys
import time
from os.path import join
from typing import *


class unChown:
    """
    This is a script to undo an errant chown of ONLY owner.  The *imperfect* logic is that files and folders
    where owner uid != group gid should be modified to owner = gid, group = gid.  The script also looks at
    file stat info and only changes files where the ctime is after a certain threshold (i.e. when the chown mistake
    was made)
    """

    def __init__(self, bad_uid: int, ctime_cutoff: int, log_path: str):
        """
        *Note:* Only logs to file when used with a ```with``` statement.
        :param bad_uid: owners to be undone if they don't owner != group
        :param ctime_cutoff: no files with most recently change BEFORE this cutoff can be modified
        :param log_path:  path to start a recursive search
        """
        self.bad_uid = bad_uid
        self.ctime_cutoff = ctime_cutoff
        self.log_path = log_path
        # log file only created when called using a with statement.  Is list of changes made (or to make if --dry-run)
        self.log_file = None
        self.logger = logging.getLogger(type(self).__name__)

    def __enter__(self) -> 'unChown':
        self.log_file = open(self.log_path, "a")
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        if self.log_file:
            self.log_file.close()
            self.log_file = None

    def _shouldChown(self, stat: os.stat_result) -> bool:
        """
        Decide if file or folder should be chowned.
        :param stat: stat_result of the file/dir
        :return: True if should be unChown-ed else False
        """
        return stat.st_ctime >= self.ctime_cutoff and stat.st_gid != stat.st_uid and stat.st_uid == self.bad_uid

    def _doChown(self, path: str, stat: os.stat_result, dry_run: bool) -> bool:
        """
        Chown the file at ```path``` to owner = gid, group = gid
        :param path: path
        :param stat: stat_result for the path
        :param dry_run: True don't actually modify file. False, do modify file.
        :return: ```True``` if a chown was performed, else ```False```
        """
        if not dry_run:
            try:
                os.chown(path=path, uid=stat.st_gid, gid=stat.st_gid, follow_symlinks=False)
            except Exception as e:
                self.logger.warning("Couldn't chown: " + str(e))
                return False
        return True

    def _doLog(self, path: str, uid: int, gid: int) -> None:
        """
        Log to std.out and if run using a with statement to a file
        :param path: path to log
        :param uid: uid of fs object at path
        :param gid: gid of fs object at path
        :return:
        """
        log_line = f"{uid}:{gid} {path}"
        self.logger.info(log_line)
        if self.log_file:
            self.log_file.write(f'{log_line}\n')

    def _handlePath(self, path: str, dry_run=False) -> bool:
        """
        :param path: path to filesystem object
        :param dry_run:
        :return:
        """
        try:
            stat = os.lstat(path)
        except Exception as e:
            self.logger.warning(f"Unable to stat: {path}: {str(e)}")
            return False
        if self._shouldChown(stat) and self._doChown(path=path, stat=stat, dry_run=dry_run):
            self._doLog(path=path, uid=stat.st_uid, gid=stat.st_gid)
            return True
        return False

    def run(self, root_path: str, dry_run: bool = False) -> None:
        """
        :param root_path: path to start filesystem walk from
        :param dry_run: if ```True``` no changes will be made to file permissions, a log may be created *see:*
        constructor for more info
        :return:
        """
        for dir_path, dir_names, file_names in os.walk(top=root_path, topdown=True, followlinks=False):
            self._handlePath(path=dir_path, dry_run=dry_run)
            for file_name in file_names:
                file_path = join(dir_path, file_name)
                self._handlePath(path=file_path, dry_run=dry_run)


# [ROOT_DIR] {optional: --dry-run}
def parseArgs() -> List[str | bool]:
    args = sys.argv[1:]
    if len(args) == 1:
        args.append(False)
    elif len(args) == 2 and args[1].lower() == "--dry-run":  # dry-run == no changes to disk
        args[1] = True
    else:
        raise ValueError("expected at least 1 arg: {root path} and the optional --dry-run flag")
    return args


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)

    root_path, dry_run = parseArgs()  # location to start walk form
    log_path = f"log-{int(round(time.time(), 0))}"  # path to write log file
    ctime_cutoff = 1680734730 - 30  # only files/dirs with ctimes AT or AFTER this will be modified
    bad_uid = 1_000  # owner uid which should be changed

    with unChown(bad_uid=bad_uid, ctime_cutoff=ctime_cutoff, log_path=log_path) as chown:
        chown.run(root_path=root_path, dry_run=dry_run)


And here are some 1 off changes I made. Everything should be done from a Live USB.

Code:

chmod +s su
chmod +s sudo

sudo chown polkitd:root /usr/lib/polkit-1/polkitd
sudo chmod 5755 /usr/lib/polkit-1/polkitd
sudo chown -R polkitd:root /etc/polkit-1
Back to top
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Other Things Gentoo All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum