Это видео недоступно.
Сожалеем об этом.

How to make memory read-only in your C programs.

Поделиться
HTML-код
  • Опубликовано: 2 окт 2023
  • Patreon ➤ / jacobsorber
    Courses ➤ jacobsorber.thinkific.com
    Website ➤ www.jacobsorber.com
    ---
    How to make memory read-only in your C programs // most of the memory we use in our C programs is readable and writable, but sometimes you want to protect some memory and prevent yourself (or some buggy or malicious code) from changing it. This video shows you how.
    Related Videos:
    Shared Memory: • Simple Shared Memory i...
    Memory-mapped File I/O: • How to Map Files into ...
    ***
    Welcome! I post videos that help you learn to program and become a more confident software developer. I cover beginner-to-advanced systems topics ranging from network programming, threads, processes, operating systems, embedded systems and others. My goal is to help you get under-the-hood and better understand how computers work and how you can use them to become stronger students and more capable professional developers.
    About me: I'm a computer scientist, electrical engineer, researcher, and teacher. I specialize in embedded systems, mobile computing, sensor networks, and the Internet of Things. I teach systems and networking courses at Clemson University, where I also lead the PERSIST research lab.
    More about me and what I do:
    www.jacobsorber.com
    people.cs.clemson.edu/~jsorber/
    persist.cs.clemson.edu/
    To Support the Channel:
    + like, subscribe, spread the word
    + contribute via Patreon --- [ / jacobsorber ]
    Source code is also available to Patreon supporters. --- [jsorber-youtube-source.heroku...]

Комментарии • 77

  • @greg4367
    @greg4367 10 месяцев назад +10

    Thanks. You always make me think, today you taught me something too. Fifty years coding in C and there is always another trick.

    • @JacobSorber
      @JacobSorber  10 месяцев назад +3

      You're very welcome. I love new-trick days.

  • @FreeDomSy-nk9ue
    @FreeDomSy-nk9ue 10 месяцев назад +42

    I don't think memory protection is part of the C specifications, it's more of an OS thing.
    This is also doable in any language that can call OS APIs.
    On Windows it's VirtualProtect (or the lower level NtProtectVirtualMemory)

    • @mihaicotin3261
      @mihaicotin3261 10 месяцев назад

      I guess it put that memory pages as read only and that’s the protection so it generates page faults?

    • @questionmarc8
      @questionmarc8 10 месяцев назад +9

      Pretty much everything in this video is not defined by the C standard, most of it is defined by POSIX only, mprotect is one of those and MAP_ANONYMOUS is defined by neither, pretty much the only thing in this video defined by the C standard is malloc

    • @redcrafterlppa303
      @redcrafterlppa303 10 месяцев назад

      ​@@mihaicotin3261it generates segmentation faults. Segfaults are real observable errors (crash) and page faults are os internal problems.

    • @directx872
      @directx872 10 месяцев назад +2

      Lol. Literally nothing is part of the C specifications😂

  • @mshingote
    @mshingote 10 месяцев назад +3

    These videos are super high quality content ❤

  • @starc0w
    @starc0w 9 месяцев назад

    Great video! Thank you very much Jacob! 🍀

  • @amber1862
    @amber1862 10 месяцев назад +5

    I absolutely adore this channel.

  • @pablo506
    @pablo506 9 месяцев назад +1

    Hi! Im new to C programming and I need to make a program which constantly shows in screen the word that the user types and can be stopped by the key word "END" like this:
    Type a word: "hello"
    Word is hello
    Type a word: "bye"
    Word is bye
    Type a word: "END"
    -
    It is for a class exercise so it would be amazing if we could use simple functions to make it. Thanks for reading 🙏

  • @alkaratus9189
    @alkaratus9189 10 месяцев назад +2

    I remember your lesson about making C code more abstract, we can use this for structures to make their data unchangeable after iniciation. Unless we make special function which will make it possible

    • @samhadi7972
      @samhadi7972 10 месяцев назад

      It’s requiring a system call though so it ain’t cheap

    • @alkaratus9189
      @alkaratus9189 10 месяцев назад

      @@samhadi7972 unless it will be marked as inline

    • @samhadi7972
      @samhadi7972 10 месяцев назад

      You mean mprotect? Inlining that won’t do anything it’s still a system call

    • @alkaratus9189
      @alkaratus9189 10 месяцев назад

      @@samhadi7972 no, i mean you can create function like struct_get_something(struct *object) and make this function inline

  • @abdulshabazz8597
    @abdulshabazz8597 9 месяцев назад +1

    4:44 Be careful! sysconf returns a 'long' data type which can overflow that declared 'integer' pagesize data type, under certain conditions.
    Recommended security patch:
    static constexpr long kPageSize = sysconf (_SC_PAGE_SIZE);
    Then, if kPageSize fits within the INT_MIN and INT_MAX int data type range, then assign it to the local variable.

  • @khomo12
    @khomo12 10 месяцев назад

    Thank you!👍👍👍

  • @bombrix5195
    @bombrix5195 10 месяцев назад +4

    I thought you just make your pointer point to const and it's done 😂

  • @lithiumferrate6960
    @lithiumferrate6960 10 месяцев назад +18

    Out of curiosity. Have you ever done windows API programming in C? I've never done so i am curious about how it looks and feels.

    • @REALsnstruthers
      @REALsnstruthers 10 месяцев назад +8

      ive delved into it a little bit; it can be intimidating, but there are enough analogues between the win32 & posix apis to get your feet wet without getting too uncomfortable.
      there’s even some aspects of win32 that i think are superior to posix, namely how it has asynchronous i/o built in and immediately available as an option.
      the biggest downsides for me are wrangling w/ COM or WinRT - its possible, but difficult in c; its more manageable in a language like c++ - and the at-times excessive amount of extra parameters. msdn & online code samples are your friend here.
      the other two pain points i have are more subjective &/or nitpicky; using wide strings (aka utf16) for unicode isn’t too bad, since stdc does come with wide string analogues to the normal narrow string utils out of the box; and writing code which is backward compatible with yet still mostly functional in older versions of windows is annoying, though that mostly holds true for every other operating system so 🤷

    • @ahmadalastal5303
      @ahmadalastal5303 10 месяцев назад +8

      nearly the whole video can be done with VirtualProtect and VirtualAlloc Win32 API, this is most used in hooking

    • @JacobSorber
      @JacobSorber  10 месяцев назад +12

      Yeah, my first programming job involved windows API programming in C, but it's been a while.

    • @nordgaren2358
      @nordgaren2358 10 месяцев назад +3

      No. You don't wanna know how it looks and feels. It looks ugly and it feels like pulling teeth. 😂

    • @ronensuperexplainer
      @ronensuperexplainer 9 месяцев назад

      Microsoft hasn't worked on a C compiler in 25 years. Their latest C++ compiler happens to support compiling C files. MSVC is a C++ compiler with a C++ linker. Also, GCC is written in C++ since 2010.

  • @user-mr3mf8lo7y
    @user-mr3mf8lo7y 10 месяцев назад

    Great! finally I can make own ram drive. What happens when program exists? Would it be still marked read-only? Say one program initialized ram drive and stayed resident in memory. How could another program access/modify the content of proposed ram drive?

    • @maxaafbackname5562
      @maxaafbackname5562 10 месяцев назад +1

      Al that memory is "owned" by the process running this code.
      After exiting, the process will be cleaned up/destroyed by the OS.
      The memory will become unclaimed memory and the rights/protection is removed and set to the "protection" of unclaimed menory.
      It will result in a segmentation fault when accessed.

  • @user-mr3mf8lo7y
    @user-mr3mf8lo7y 9 месяцев назад

    Just a quick question is there any limitation on branching out else if's (or, similarly, case's on switch) ?
    i.e., if (main cond).. else if (cond 1); else if (cond 2); .. else if (cond n). max number of lines/statements, n? Any thoughts? Thanks,.

  • @Jim-vr2lx
    @Jim-vr2lx 10 месяцев назад

    Would you recommend this for ephemeral encryption keys? Can the memory page still be swapped out? Is it protected against malicious software in kernel-space; for example, root-kits? POSIX is just an API front-end, right? Is an OS's POSIX sub-system verified by independent groups? Can we ever be sure whats happening to these 'protected' spaces?

    • @JacobSorber
      @JacobSorber  10 месяцев назад

      I'm pretty sure this won't necessarily protect you from a malicious or compromised kernel.

    • @Jim-vr2lx
      @Jim-vr2lx 9 месяцев назад

      @@JacobSorber Ever since i read Ken Thompson's 'Reflections on Trusting Trust' I've been fascinated with the idea of protecting a user-space program from a malicious kernel. Whitfield Diffie, Martin Hellman, and Ralph Merkle devised brilliant ways to exchange cypher keys over insecure channels. I still think there's hope for a protected user-space.

  • @Enomem
    @Enomem 10 месяцев назад +3

    If only the compiler had some keyword to help with this...

    • @boggless2771
      @boggless2771 9 месяцев назад

      Is it final?
      no wait! It's hardcode!
      No wait, its variable!

    • @ajtan2607
      @ajtan2607 9 месяцев назад +1

      If you're referring to C23's `constexpr`, then it might help. However, it can only guarantee that the data is usable at compile-time. There is no guarantee that the data is stored in read-only memory (in the OS's perspective).

  • @kennethbrown445
    @kennethbrown445 10 месяцев назад +1

    Regarding MAP_ANONYMOUS, I thought process memory was already isolated in Linux? I thought I remembered reading somewhere that malloc was just basically actually handled by mmap and MAP_ANONYMOUS in the kernel space

    • @JacobSorber
      @JacobSorber  10 месяцев назад +1

      I may not have had to specify MAP_ANONYMOUS (would have to check the docs again). Heap management (malloc) runs in user space, uses either brk or mmap to get pages from the kernel (depends on the allocator and requested block size), and then it breaks those pages up into smaller blocks to service program requests.

    • @kennethbrown445
      @kennethbrown445 10 месяцев назад +1

      @@JacobSorber ok I was thinking that was the case. It has been on my mind lately because I have been writing a number of apps where I want to try to act like it's running in a hostile environment. Key derivation functions, password managers, etc. I have been hearing lots of different things about how isolated one processes' memory is from others. I never even considered needing to make my memory read only for those purposes, but now I'm thinking it couldn't hurt to take such a precaution.

  • @MatthisDayer
    @MatthisDayer 10 месяцев назад +3

    couldn't you have used aligned_alloc from stdlib? what are the differences?

    • @anon_y_mousse
      @anon_y_mousse 9 месяцев назад

      Sure for alignment purposes, but the whole point of the video is to make it read only.

    • @MatthisDayer
      @MatthisDayer 9 месяцев назад +1

      @@anon_y_mousse I'm talking about at one point in the video where he uses a Linux or posix only function to allocate aligned memory. I'm wondering if the std library one could be used instead

    • @anon_y_mousse
      @anon_y_mousse 9 месяцев назад

      @@MatthisDayer I'm pretty sure it can, but you'll have to test that.

  • @ThatGuyexe
    @ThatGuyexe 10 месяцев назад +3

    Can you make brk vs mmap?

    • @JacobSorber
      @JacobSorber  10 месяцев назад +1

      Haven't I already done that? I'll go back and check. It's hard to keep track sometimes. 🤔

  • @kennethbrown445
    @kennethbrown445 10 месяцев назад

    What IDE is this?

  • @duneharv
    @duneharv 10 месяцев назад +1

    So is a segmentation fault always related to a read-only portion of a page in (virtual) memory being written to or are there other causes too?

    • @drdca8263
      @drdca8263 10 месяцев назад +2

      Reading from memory your process doesn’t have permissions for should also cause it, I think.

    • @JacobSorber
      @JacobSorber  10 месяцев назад +3

      accessing an unmapped page will cause a seg fault, as well.

  • @zxuiji
    @zxuiji 10 месяцев назад

    Just had an idea for protecting against "buffer" overrun/underrun, for starters instead of handing the allocation directly to the requester, instead hand over a object that reference the memory by index. The functions for read/write would be similar to the file functions and when handing over the pointer a reference count should be updated in a different page. The allocation itself would always be set to read only when this reference count is greater than 0, serving as a lock against writing. When it's 0 then the protection is removed from the page and the write calls can go ahead without issue. Here's a VERY rough example in code (with some assumed symbols):
    int main(void)
    {
    #define HELLO "Hello World"
    #define BYE "Goodbye World"
    /* Ensure we cannot accidentally write more than we need, the 0 indicates we do NOT want this memory to auto grow,
    the remaining 1s mean pad both the front and back of the memory with null bytes of the size mentioned where sizeof(char) is, this ensures we can always pass the string into any function that expects a null byte */
    int strmem = mem_calloc( sizeof(HELLO), 0, sizeof(char), 1, 1 );
    /* The 0 indicates that no, the pointer will not be handed to iconv() or some other 3rd party function that does not expect the custom interface */
    char *str = NULL;
    /* This could segfault under different circumstances but on this occasion the count is at 1 so an exclusive lock is possible */
    str = memputraw( strmem, STR, sizeof(STR) );
    /* This will run without issue as it only reads the memory */
    puts( str );
    /* This will segfault because the mem_getptr( strmem, true ) was not called */
    str[0] = 0;
    /* Assuming we didn't do the line above then this would start writing "Goodbye World" from position 0 (as indicated by the 0) however only "Goodbye Wor" will actually get written
    because we specified during allocation we do not want the memory to grow */
    str = memputabs( strmem, BYE, sizeof(BYE), 0 );
    puts( str );
    /* 0 the memory 1st then release it, this will protect against hackers using the pointer after it was released to glean sensitive info */
    mem_zero_and_free(strmem);
    return EXIT_SUCCESS;
    }

    • @anon_y_mousse
      @anon_y_mousse 9 месяцев назад

      Kind of sounds like you just want a managed string type. Have you considered using one of the thousand libraries that provide that in C?

    • @zxuiji
      @zxuiji 9 месяцев назад

      @@anon_y_mousse That was just an easier to get across example, I'm sure there's plenty more cases where null terminated/prefixed buffers are handy, for example a list of IDs where id 0 is invalid, or linked lists that use offsets from the buffer root instead of addresses.
      Just give it a think for yourself, I'm sure you can come up with other cases where it's useful to not have to worry about buffer lengths matching their capacity when you null out the final element (since the reported capacity would be less then actual capacity).
      Strings are just the easiest example to give so I used 'em

    • @anon_y_mousse
      @anon_y_mousse 9 месяцев назад

      @@zxuiji Yeah, that's why I wrote and use my own data structures library. I have an abstract object that I don't manipulate directly and I call functions on it to work with it. Objects don't even have to be on the heap either because of how I've structured things. I'm sure a thousand other libraries exist to do the same things. If you don't want to write it yourself, then use one of those. Also, I'm just going to throw this out there, but get yourself a copy of RayLib and make a game.

    • @zxuiji
      @zxuiji 9 месяцев назад

      @@anon_y_mousse tried it, didn't like it, don't remember the reason as it was years ago I think

    • @anon_y_mousse
      @anon_y_mousse 9 месяцев назад

      @@zxuiji Might have just been how it was then, but that's okay. Have you ever written a game? Because I'm trying to push as many people that way as I can. The more I can get people into it without using a game engine I feel it's for the better.

  • @cernejr
    @cernejr 10 месяцев назад +4

    Hmm, in real world code I would want something else than a segfault. I guess one could capture the signal somehow and do some error handling.

    • @IvanKekov
      @IvanKekov 9 месяцев назад

      segfault here is for the sake of simplicity as it's not related to main subject

  • @rian0xFFF
    @rian0xFFF 10 месяцев назад

    make videos about binary programming, or more low level programming

    • @JacobSorber
      @JacobSorber  10 месяцев назад

      I do like low-level stuff. Can you clarify what you mean by "binary programming"?

    • @rian0xFFF
      @rian0xFFF 10 месяцев назад

      @@JacobSorber like manipulating data using bitwise, shifts, etc. As if we were developing a driver

  • @kermitdafrog8
    @kermitdafrog8 10 месяцев назад +2

    Hmm used malloc but didn't use free.

    • @bob_kazamakis
      @bob_kazamakis 10 месяцев назад +7

      There’s no opportunity for a leak here since it’s not a real program

    • @kermitdafrog8
      @kermitdafrog8 10 месяцев назад

      @@bob_kazamakis I know but it should be taught as a habit so new programmers don't forget. And especially if we are trying to deal with security issues.

    • @maxaafbackname5562
      @maxaafbackname5562 10 месяцев назад

      There is a group of programmers that do not cleanup at the end of the program because the OS will do it anyway.
      No constructs like destructors, so technically no need to free/cleanup.
      The cleanup takes up time and codespace and can even break things due to bugs in the cleanup code
      I think it is always better to proper cleanup when the code is subject for update or reuse.
      In this case neither will, so for the simplicity of the demonstration code, better leave out the cleanup.

  • @andrewporter1868
    @andrewporter1868 10 месяцев назад +1

    One thing that no one ever covers though: how do I make memory write-only without having to implement a software solution myself, even if it's cheap? Every cycle counts.

  • @drdca8263
    @drdca8263 10 месяцев назад +1

    9:04 why is p3 6 bytes long while p1 and p2 are 4?
    Or are all 3 of them like, 8 bytes long and the leading zeros are just omitted?

    • @JacobSorber
      @JacobSorber  10 месяцев назад +2

      Yep. All 8 with leading zeros omitted.

    • @drdca8263
      @drdca8263 10 месяцев назад +1

      @@JacobSorber Thanks! For some reason I imagined that memory addresses that a program gets wouldn’t typically start with zero. I don’t have a justification for thinking that way though.

  • @bramfran4326
    @bramfran4326 10 месяцев назад +1

    Making memory read-only feels harder than it should be.